Annotation of libwww/Library/src/HTWriter.c, revision 2.40.2.4
2.11 frystyk 1: /* HTWrite.c
2.24 frystyk 2: ** FILE WRITER BASED ON A SOCKET
2.1 timbl 3: **
2.15 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.11 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.40.2.4! eric 6: ** @(#) $Id: HTWriter.c,v 2.40.2.3 1996/11/22 16:46:48 eric Exp $
2.14 frystyk 7: **
8: ** This is a try with a non-buffered output stream which remembers
9: ** state using the write_pointer. As normally we have a big buffer
10: ** somewhere else in the stream chain an extra output buffer will often
2.34 frystyk 11: ** not be needed.
2.1 timbl 12: */
2.11 frystyk 13:
2.13 frystyk 14: /* Library include files */
2.31 frystyk 15: #include "sysdep.h"
2.33 frystyk 16: #include "WWWUtil.h"
2.34 frystyk 17: #include "WWWCore.h"
2.40.2.1 eric 18: #include "HTNet.h"
2.18 frystyk 19: #include "HTNetMan.h"
2.40.2.4! eric 20: #include "HTWatch.h"
2.14 frystyk 21: #include "HTWriter.h" /* Implemented here */
2.1 timbl 22:
23: struct _HTStream {
2.33 frystyk 24: const HTStreamClass * isa;
25: /* ... */
26: };
27:
28: struct _HTOutputStream {
29: const HTOutputStreamClass * isa;
30: HTChannel * ch;
2.40.2.2 frystyk 31: HTHost * host;
2.33 frystyk 32: char * write;
2.1 timbl 33: #ifdef NOT_ASCII
2.33 frystyk 34: char * ascbuf; /* Buffer for TOASCII conversion */
2.1 timbl 35: #endif
36: };
37:
2.14 frystyk 38: /* ------------------------------------------------------------------------- */
2.1 timbl 39:
2.33 frystyk 40: PRIVATE int HTWriter_flush (HTOutputStream * me)
41: {
42: return HT_OK; /* As we don't have any output buffer */
43: }
44:
45: PRIVATE int HTWriter_free (HTOutputStream * me)
46: {
47: return HT_OK;
48: }
49:
50: PRIVATE int HTWriter_abort (HTOutputStream * me, HTList * e)
51: {
52: return HT_ERROR;
53: }
54:
2.14 frystyk 55: /* Write to the socket
56: **
57: ** According to Solaris 2.3 man on write:
58: **
59: ** o If O_NONBLOCK and O_NDELAY are clear, write() blocks
60: ** until the data can be accepted.
61: **
62: ** o If O_NONBLOCK or O_NDELAY is set, write() does not
63: ** block the process. If some data can be written
64: ** without blocking the process, write() writes what it
65: ** can and returns the number of bytes written. Other-
66: ** wise, if O_NONBLOCK is set, it returns - 1 and sets
67: ** errno to EAGAIN or if O_NDELAY is set, it returns 0.
68: **
69: ** According to SunOS 4.1.1 man on write:
70: **
71: ** + If the descriptor is marked for non-blocking I/O
72: ** using fcntl() to set the FNONBLOCK or O_NONBLOCK
73: ** flag (defined in <sys/fcntl.h>), write() requests
74: ** for {PIPE_BUF} (see pathconf(2V)) or fewer bytes
75: ** either succeed completely and return nbyte, or
76: ** return -1 and set errno to EAGAIN. A write() request
77: ** for greater than {PIPE_BUF} bytes either transfers
78: ** what it can and returns the number of bytes written,
79: ** or transfers no data and returns -1 and sets errno
80: ** to EAGAIN. If a write() request is greater than
81: ** {PIPE_BUF} bytes and all data previously written to
82: ** the pipe has been read, write() transfers at least
83: ** {PIPE_BUF} bytes.
84: */
2.33 frystyk 85: PRIVATE int HTWriter_write (HTOutputStream * me, const char * buf, int len)
2.14 frystyk 86: {
2.40.2.2 frystyk 87: HTHost * host = me->host;
88: SOCKET soc = HTChannel_socket(HTHost_channel(host));
89: HTNet * net = HTHost_getWriteNet(host);
2.14 frystyk 90: int b_write;
2.31 frystyk 91: const char *limit = buf+len;
2.1 timbl 92:
2.9 frystyk 93: #ifdef NOT_ASCII
2.34 frystyk 94: if (len && !me->ascbuf) { /* Generate new buffer */
95: const char *orig = buf;
2.14 frystyk 96: char *dest;
97: int cnt;
2.29 frystyk 98: if ((me->ascbuf = (char *) HT_MALLOC(len)) == NULL)
2.34 frystyk 99: HT_OUTOFMEM("HTWriter_write");
2.14 frystyk 100: dest = me->ascbuf;
2.20 frystyk 101: for (cnt=0; cnt<len; cnt++) {
102: *dest = TOASCII(*orig);
103: dest++, orig++;
104: }
2.33 frystyk 105: me->write = me->ascbuf;
2.14 frystyk 106: limit = me->ascbuf+len;
2.1 timbl 107: }
2.14 frystyk 108: #else
2.33 frystyk 109: if (!me->write)
110: me->write = (char *) buf;
2.14 frystyk 111: else
2.33 frystyk 112: len -= (me->write - buf);
2.14 frystyk 113: #endif
114:
115: /* Write data to the network */
2.33 frystyk 116: while (me->write < limit) {
117: if ((b_write = NETWRITE(soc, me->write, len)) < 0) {
2.14 frystyk 118: #ifdef EAGAIN
2.19 frystyk 119: if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
2.14 frystyk 120: #else
2.19 frystyk 121: if (socerrno == EWOULDBLOCK) /* BSD */
2.1 timbl 122: #endif
2.14 frystyk 123: {
124: if (PROT_TRACE)
2.33 frystyk 125: HTTrace("Write Socket WOULD BLOCK %d\n",soc);
2.40.2.2 frystyk 126: HTHost_register(host, net, HTEvent_WRITE);
2.14 frystyk 127: return HT_WOULD_BLOCK;
2.39 frystyk 128: #ifdef EINTR
2.37 frystyk 129: } else if (socerrno == EINTR) {
130: /*
131: ** EINTR A signal was caught during the write opera-
132: ** tion and no data was transferred.
133: */
134: if (PROT_TRACE)
135: HTTrace("Write Socket call interruted - try again\n");
136: continue;
2.39 frystyk 137: #endif
2.14 frystyk 138: } else {
2.33 frystyk 139: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
2.28 frystyk 140: "NETWRITE");
2.14 frystyk 141: return HT_ERROR;
142: }
2.1 timbl 143: }
2.40.2.1 eric 144: /* We do this unconditionally, should we check to see if we ever blocked? */
2.40.2.2 frystyk 145: HTHost_unregister(host, net, HTEvent_WRITE);
2.40.2.3 eric 146: HTWatch_logData(me->write, b_write, "HTWriter_write");
2.33 frystyk 147: me->write += b_write;
2.14 frystyk 148: len -= b_write;
149: if (PROT_TRACE)
2.30 eric 150: HTTrace("Write Socket %d bytes written to socket %d\n",
2.33 frystyk 151: b_write, soc);
2.39 frystyk 152: #if 0
2.28 frystyk 153: net->bytes_written += b_write;
2.39 frystyk 154: #endif
2.28 frystyk 155: {
156: HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
2.33 frystyk 157: if (cbf) (*cbf)(net->request, HT_PROG_WRITE,
158: HT_MSG_NULL, NULL, NULL, NULL);
2.28 frystyk 159: }
2.1 timbl 160: }
2.14 frystyk 161: #ifdef NOT_ASCII
2.29 frystyk 162: HT_FREE(me->ascbuf);
2.14 frystyk 163: #else
2.33 frystyk 164: me->write = NULL;
2.14 frystyk 165: #endif
166: return HT_OK;
2.1 timbl 167: }
168:
169: /* Character handling
170: ** ------------------
171: */
2.33 frystyk 172: PRIVATE int HTWriter_put_character (HTOutputStream * me, char c)
2.1 timbl 173: {
2.14 frystyk 174: return HTWriter_write(me, &c, 1);
2.1 timbl 175: }
176:
177: /* String handling
178: ** ---------------
179: **
180: ** Strings must be smaller than this buffer size.
181: */
2.33 frystyk 182: PRIVATE int HTWriter_put_string (HTOutputStream * me, const char * s)
2.1 timbl 183: {
2.14 frystyk 184: return HTWriter_write(me, s, (int) strlen(s));
2.1 timbl 185: }
2.33 frystyk 186: /*
187: ** The difference between the close and the free method is that we don't
188: ** close the connection in the free method - we only call the free method
189: ** of the target stream. That way, we can keep the output stream as long
190: ** as the channel itself.
191: */
192: PRIVATE int HTWriter_close (HTOutputStream * me)
2.1 timbl 193: {
2.33 frystyk 194: if (PROT_TRACE) HTTrace("Socket write FREEING....\n");
2.29 frystyk 195: HT_FREE(me);
2.33 frystyk 196: return HT_OK;
2.1 timbl 197: }
198:
2.33 frystyk 199: PRIVATE const HTOutputStreamClass HTWriter =
2.1 timbl 200: {
2.14 frystyk 201: "SocketWriter",
202: HTWriter_flush,
203: HTWriter_free,
204: HTWriter_abort,
205: HTWriter_put_character,
206: HTWriter_put_string,
2.33 frystyk 207: HTWriter_write,
208: HTWriter_close
2.1 timbl 209: };
210:
2.40.2.2 frystyk 211: PUBLIC HTOutputStream * HTWriter_new (HTHost * host, HTChannel * ch,
2.33 frystyk 212: void * param, int mode)
2.1 timbl 213: {
2.40.2.2 frystyk 214: if (host && ch) {
2.33 frystyk 215: HTOutputStream * me = HTChannel_output(ch);
2.40.2.2 frystyk 216: if (!me) {
2.33 frystyk 217: if ((me=(HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL)
218: HT_OUTOFMEM("HTWriter_new");
219: me->isa = &HTWriter;
220: me->ch = ch;
2.40.2.2 frystyk 221: me->host = host;
2.33 frystyk 222: }
223: return me;
224: }
225: return NULL;
2.21 frystyk 226: }
Webmaster