Annotation of libwww/Library/src/HTWriter.c, revision 2.29
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.14 frystyk 6: **
7: ** This is a try with a non-buffered output stream which remembers
8: ** state using the write_pointer. As normally we have a big buffer
9: ** somewhere else in the stream chain an extra output buffer will often
2.21 frystyk 10: ** not be needed. There is also a small buffer stream that can be used
11: ** if athis is not the case.
2.1 timbl 12: */
2.11 frystyk 13:
2.13 frystyk 14: /* Library include files */
15: #include "tcp.h"
16: #include "HTUtils.h"
17: #include "HTString.h"
2.17 frystyk 18: #include "HTReq.h"
2.18 frystyk 19: #include "HTNetMan.h"
2.21 frystyk 20: #include "HTConLen.h"
2.28 frystyk 21: #include "HTAlert.h"
2.14 frystyk 22: #include "HTWriter.h" /* Implemented here */
2.1 timbl 23:
24: struct _HTStream {
25: CONST HTStreamClass * isa;
2.24 frystyk 26: SOCKET sockfd;
2.17 frystyk 27: HTNet * net;
2.21 frystyk 28: char *wptr;
2.17 frystyk 29: BOOL leave_open;
2.1 timbl 30: #ifdef NOT_ASCII
2.14 frystyk 31: BOOL make_ascii; /* Are we writing to the net? */
32: char * ascbuf; /* Buffer for TOASCII conversion */
2.1 timbl 33: #endif
34: };
35:
2.14 frystyk 36: /* ------------------------------------------------------------------------- */
2.1 timbl 37:
2.14 frystyk 38: /* Write to the socket
39: **
40: ** According to Solaris 2.3 man on write:
41: **
42: ** o If O_NONBLOCK and O_NDELAY are clear, write() blocks
43: ** until the data can be accepted.
44: **
45: ** o If O_NONBLOCK or O_NDELAY is set, write() does not
46: ** block the process. If some data can be written
47: ** without blocking the process, write() writes what it
48: ** can and returns the number of bytes written. Other-
49: ** wise, if O_NONBLOCK is set, it returns - 1 and sets
50: ** errno to EAGAIN or if O_NDELAY is set, it returns 0.
51: **
52: ** According to SunOS 4.1.1 man on write:
53: **
54: ** + If the descriptor is marked for non-blocking I/O
55: ** using fcntl() to set the FNONBLOCK or O_NONBLOCK
56: ** flag (defined in <sys/fcntl.h>), write() requests
57: ** for {PIPE_BUF} (see pathconf(2V)) or fewer bytes
58: ** either succeed completely and return nbyte, or
59: ** return -1 and set errno to EAGAIN. A write() request
60: ** for greater than {PIPE_BUF} bytes either transfers
61: ** what it can and returns the number of bytes written,
62: ** or transfers no data and returns -1 and sets errno
63: ** to EAGAIN. If a write() request is greater than
64: ** {PIPE_BUF} bytes and all data previously written to
65: ** the pipe has been read, write() transfers at least
66: ** {PIPE_BUF} bytes.
67: */
2.21 frystyk 68: PRIVATE int HTWriter_write (HTStream * me, CONST char * buf, int len)
2.14 frystyk 69: {
70: int b_write;
71: CONST char *limit = buf+len;
2.28 frystyk 72: HTRequest * request = me->net->request;
73: HTNet * net = me->net;
2.1 timbl 74:
2.9 frystyk 75: #ifdef NOT_ASCII
2.14 frystyk 76: if (me->make_ascii && len && !me->ascbuf) { /* Generate new buffer */
77: char *orig=buf;
78: char *dest;
79: int cnt;
2.29 ! frystyk 80: if ((me->ascbuf = (char *) HT_MALLOC(len)) == NULL)
! 81: HT_OUTOFMEM("me->ascbuf ");
2.14 frystyk 82: dest = me->ascbuf;
2.20 frystyk 83: for (cnt=0; cnt<len; cnt++) {
84: *dest = TOASCII(*orig);
85: dest++, orig++;
86: }
2.21 frystyk 87: me->wptr = me->ascbuf;
2.14 frystyk 88: limit = me->ascbuf+len;
2.1 timbl 89: }
2.14 frystyk 90: #else
2.21 frystyk 91: if (!me->wptr)
92: me->wptr = (char *) buf;
2.14 frystyk 93: else
2.21 frystyk 94: len -= (me->wptr - buf);
2.14 frystyk 95: #endif
96:
97: /* Write data to the network */
2.21 frystyk 98: while (me->wptr < limit) {
99: if ((b_write = NETWRITE(me->sockfd, me->wptr, len)) < 0) {
2.14 frystyk 100:
101: #ifdef EAGAIN
2.19 frystyk 102: if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
2.14 frystyk 103: #else
2.19 frystyk 104: if (socerrno == EWOULDBLOCK) /* BSD */
2.1 timbl 105: #endif
2.14 frystyk 106: {
107: if (PROT_TRACE)
2.28 frystyk 108: TTYPrint(TDEST,"Write Socket WOULD BLOCK %d\n",me->sockfd);
109: HTEvent_Register(me->sockfd, request, (SockOps) FD_WRITE,
110: net->cbf, net->priority);
2.14 frystyk 111: return HT_WOULD_BLOCK;
112: } else {
2.28 frystyk 113: HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO,
114: "NETWRITE");
2.14 frystyk 115: return HT_ERROR;
116: }
2.1 timbl 117: }
2.17 frystyk 118: HTEvent_UnRegister(me->sockfd, (SockOps) FD_WRITE);
2.21 frystyk 119: me->wptr += b_write;
2.14 frystyk 120: len -= b_write;
121: if (PROT_TRACE)
2.22 frystyk 122: TTYPrint(TDEST, "Write Socket %d bytes written to socket %d\n",
2.17 frystyk 123: b_write, me->sockfd);
2.28 frystyk 124: net->bytes_written += b_write;
125: {
126: HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
127: if (cbf) (*cbf)(request, HT_PROG_WRITE,HT_MSG_NULL,NULL,NULL,NULL);
128: }
2.1 timbl 129: }
2.14 frystyk 130: #ifdef NOT_ASCII
2.29 ! frystyk 131: HT_FREE(me->ascbuf);
2.14 frystyk 132: #else
2.21 frystyk 133: me->wptr = NULL;
2.14 frystyk 134: #endif
135: return HT_OK;
2.1 timbl 136: }
137:
138: /* Character handling
139: ** ------------------
140: */
2.21 frystyk 141: PRIVATE int HTWriter_put_character (HTStream * me, char c)
2.1 timbl 142: {
2.14 frystyk 143: return HTWriter_write(me, &c, 1);
2.1 timbl 144: }
145:
146: /* String handling
147: ** ---------------
148: **
149: ** Strings must be smaller than this buffer size.
150: */
2.21 frystyk 151: PRIVATE int HTWriter_put_string (HTStream * me, CONST char * s)
2.1 timbl 152: {
2.14 frystyk 153: return HTWriter_write(me, s, (int) strlen(s));
2.1 timbl 154: }
155:
2.21 frystyk 156: PRIVATE int HTWriter_flush (HTStream * me)
2.1 timbl 157: {
2.16 frystyk 158: return HT_OK; /* As we don't keep any buffer in this stream */
2.1 timbl 159: }
160:
2.21 frystyk 161: PRIVATE int HTWriter_free (HTStream * me)
2.1 timbl 162: {
2.14 frystyk 163: int status = HT_OK;
164: if (!me->leave_open) {
2.17 frystyk 165: if (NETCLOSE(me->sockfd) < 0)
2.14 frystyk 166: status = HT_ERROR;
167: }
2.29 ! frystyk 168: HT_FREE(me);
2.14 frystyk 169: return status;
2.1 timbl 170: }
171:
2.23 frystyk 172: PRIVATE int HTWriter_abort (HTStream * me, HTList * e)
2.1 timbl 173: {
2.14 frystyk 174: if (!me->leave_open)
2.17 frystyk 175: NETCLOSE(me->sockfd);
2.29 ! frystyk 176: HT_FREE(me);
2.14 frystyk 177: return HT_ERROR;
2.1 timbl 178: }
179:
180:
181: /* Structured Object Class
182: ** -----------------------
183: */
2.14 frystyk 184: PRIVATE CONST HTStreamClass HTWriter =
2.1 timbl 185: {
2.14 frystyk 186: "SocketWriter",
187: HTWriter_flush,
188: HTWriter_free,
189: HTWriter_abort,
190: HTWriter_put_character,
191: HTWriter_put_string,
192: HTWriter_write
2.1 timbl 193: };
194:
195:
196: /* Subclass-specific Methods
197: ** -------------------------
198: */
2.17 frystyk 199: PUBLIC HTStream* HTWriter_new (HTNet *net, BOOL leave_open)
2.1 timbl 200: {
2.29 ! frystyk 201: HTStream* me;
! 202: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
! 203: HT_OUTOFMEM("HTWriter_new");
2.2 timbl 204: me->isa = &HTWriter;
2.14 frystyk 205: me->leave_open = leave_open;
2.17 frystyk 206: me->sockfd = net->sockfd;
207: me->net = net;
2.2 timbl 208: return me;
2.21 frystyk 209: }
210:
211: /*
212: ** Set up stream to write to a socket. If buf_size > 0 then we set up
213: ** buffered output used for at most buf_size bytes. From that point we
214: ** switch to unbuffered mode. Otherwise we'll use nonbuffered output.
215: */
216: PUBLIC HTStream* HTBufWriter_new (HTNet *net, BOOL leave_open, int buf_size)
217: {
218: return HTBuffer_new(HTWriter_new(net, leave_open), net->request, buf_size);
2.1 timbl 219: }
2.8 luotonen 220:
2.1 timbl 221: /* Subclass-specific Methods
222: ** -------------------------
223: */
2.26 frystyk 224: #ifdef NOT_ASCII
2.25 frystyk 225: PUBLIC HTStream * HTASCIIWriter (HTNet *net, BOOL leave_open)
2.1 timbl 226: {
2.29 ! frystyk 227: HTStream * me;
! 228: if ((me = (HTStream *) HT_CALLOC(1, sizeof(*me))) == NULL)
! 229: HT_OUTOFMEM("HTASCIIWriter_new");
2.2 timbl 230: me->isa = &HTWriter;
2.14 frystyk 231: me->leave_open = leave_open;
2.2 timbl 232: me->make_ascii = YES;
2.17 frystyk 233: me->sockfd = net->sockfd;
234: me->net = net;
2.2 timbl 235: return me;
2.1 timbl 236: }
2.26 frystyk 237: #else
238: #ifdef WWW_WIN_DLL
2.27 frystyk 239: PUBLIC HTStream * HTASCIIWriter (HTNet *net, BOOL leave_open)
240: {
241: return NULL;
242: }
2.26 frystyk 243: #endif /* WWW_WIN_DLL */
244: #endif /* NOT_ASCII */
Webmaster