Annotation of libwww/Library/src/HTWriter.c, revision 2.56
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.56 ! kahan 6: ** @(#) $Id: HTWriter.c,v 2.55 1999/04/04 00:13:21 frystyk 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.49 frystyk 15: #include "wwwsys.h"
2.33 frystyk 16: #include "WWWUtil.h"
2.34 frystyk 17: #include "WWWCore.h"
2.41 frystyk 18: #include "HTNet.h"
2.18 frystyk 19: #include "HTNetMan.h"
2.14 frystyk 20: #include "HTWriter.h" /* Implemented here */
2.1 timbl 21:
2.50 frystyk 22: #include "HTHstMan.h"
23:
2.1 timbl 24: struct _HTStream {
2.33 frystyk 25: const HTStreamClass * isa;
26: /* ... */
27: };
28:
29: struct _HTOutputStream {
30: const HTOutputStreamClass * isa;
31: HTChannel * ch;
2.41 frystyk 32: HTHost * host;
2.48 frystyk 33: int offset;
2.1 timbl 34: #ifdef NOT_ASCII
2.33 frystyk 35: char * ascbuf; /* Buffer for TOASCII conversion */
2.1 timbl 36: #endif
37: };
38:
2.14 frystyk 39: /* ------------------------------------------------------------------------- */
2.1 timbl 40:
2.33 frystyk 41: PRIVATE int HTWriter_flush (HTOutputStream * me)
42: {
43: return HT_OK; /* As we don't have any output buffer */
44: }
45:
46: PRIVATE int HTWriter_free (HTOutputStream * me)
47: {
48: return HT_OK;
49: }
50:
51: PRIVATE int HTWriter_abort (HTOutputStream * me, HTList * e)
52: {
53: return HT_ERROR;
54: }
55:
2.14 frystyk 56: /* Write to the socket
57: **
58: ** According to Solaris 2.3 man on write:
59: **
60: ** o If O_NONBLOCK and O_NDELAY are clear, write() blocks
61: ** until the data can be accepted.
62: **
63: ** o If O_NONBLOCK or O_NDELAY is set, write() does not
64: ** block the process. If some data can be written
65: ** without blocking the process, write() writes what it
66: ** can and returns the number of bytes written. Other-
67: ** wise, if O_NONBLOCK is set, it returns - 1 and sets
68: ** errno to EAGAIN or if O_NDELAY is set, it returns 0.
69: **
70: ** According to SunOS 4.1.1 man on write:
71: **
72: ** + If the descriptor is marked for non-blocking I/O
73: ** using fcntl() to set the FNONBLOCK or O_NONBLOCK
74: ** flag (defined in <sys/fcntl.h>), write() requests
75: ** for {PIPE_BUF} (see pathconf(2V)) or fewer bytes
76: ** either succeed completely and return nbyte, or
77: ** return -1 and set errno to EAGAIN. A write() request
78: ** for greater than {PIPE_BUF} bytes either transfers
79: ** what it can and returns the number of bytes written,
80: ** or transfers no data and returns -1 and sets errno
81: ** to EAGAIN. If a write() request is greater than
82: ** {PIPE_BUF} bytes and all data previously written to
83: ** the pipe has been read, write() transfers at least
84: ** {PIPE_BUF} bytes.
85: */
2.33 frystyk 86: PRIVATE int HTWriter_write (HTOutputStream * me, const char * buf, int len)
2.14 frystyk 87: {
2.41 frystyk 88: HTHost * host = me->host;
89: SOCKET soc = HTChannel_socket(HTHost_channel(host));
90: HTNet * net = HTHost_getWriteNet(host);
2.14 frystyk 91: int b_write;
2.48 frystyk 92: char * wrtp;
2.31 frystyk 93: const char *limit = buf+len;
2.1 timbl 94:
2.50 frystyk 95: /* If we don't have a Net object then return right away */
96: if (!net) {
2.55 frystyk 97: HTTRACE(STREAM_TRACE, "Write Socket No Net object %d (offset %d)\n" _ soc _ me->offset);
2.50 frystyk 98: return HT_ERROR;
99: }
100:
2.9 frystyk 101: #ifdef NOT_ASCII
2.34 frystyk 102: if (len && !me->ascbuf) { /* Generate new buffer */
103: const char *orig = buf;
2.14 frystyk 104: char *dest;
105: int cnt;
2.29 frystyk 106: if ((me->ascbuf = (char *) HT_MALLOC(len)) == NULL)
2.34 frystyk 107: HT_OUTOFMEM("HTWriter_write");
2.14 frystyk 108: dest = me->ascbuf;
2.20 frystyk 109: for (cnt=0; cnt<len; cnt++) {
110: *dest = TOASCII(*orig);
111: dest++, orig++;
112: }
2.48 frystyk 113: wrtp = me->ascbuf;
2.14 frystyk 114: limit = me->ascbuf+len;
2.1 timbl 115: }
2.14 frystyk 116: #else
2.48 frystyk 117: if (!me->offset)
118: wrtp = (char *) buf;
119: else {
120: wrtp = (char *) buf + me->offset;
121: len -= me->offset;
122: me->offset = 0;
123: }
2.14 frystyk 124: #endif
125:
126: /* Write data to the network */
2.48 frystyk 127: while (wrtp < limit) {
128: if ((b_write = NETWRITE(soc, wrtp, len)) < 0) {
2.14 frystyk 129: #ifdef EAGAIN
2.19 frystyk 130: if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
2.14 frystyk 131: #else
2.19 frystyk 132: if (socerrno == EWOULDBLOCK) /* BSD */
2.1 timbl 133: #endif
2.14 frystyk 134: {
2.48 frystyk 135: HTHost_register(host, net, HTEvent_WRITE);
136: me->offset = wrtp - buf;
2.54 frystyk 137: HTTRACE(STREAM_TRACE, "Write Socket WOULD BLOCK %d (offset %d)\n" _ soc _ me->offset);
2.14 frystyk 138: return HT_WOULD_BLOCK;
2.39 frystyk 139: #ifdef EINTR
2.37 frystyk 140: } else if (socerrno == EINTR) {
141: /*
142: ** EINTR A signal was caught during the write opera-
143: ** tion and no data was transferred.
144: */
2.56 ! kahan 145: HTTRACE(STREAM_TRACE, "Write Socket call interrupted - try again\n");
2.37 frystyk 146: continue;
2.39 frystyk 147: #endif
2.14 frystyk 148: } else {
2.56 ! kahan 149: host->broken_pipe = YES;
2.43 frystyk 150: #ifdef EPIPE
2.56 ! kahan 151: if (socerrno == EPIPE) {
! 152: /* JK: an experimental bug solution proposed by
! 153: Olga and Mikhael */
2.54 frystyk 154: HTTRACE(STREAM_TRACE, "Write Socket got EPIPE\n");
2.56 ! kahan 155: HTHost_unregister(host, net, HTEvent_WRITE);
! 156: HTHost_register(host, net, HTEvent_CLOSE);
! 157: /* @@ JK: seems that some functions check the errors
! 158: as part of the flow control */
! 159: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
! 160: "NETWRITE");
! 161: return HT_CLOSED;
! 162: }
2.43 frystyk 163: #endif /* EPIPE */
2.56 ! kahan 164: /* all errors that aren't EPIPE */
2.33 frystyk 165: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
2.28 frystyk 166: "NETWRITE");
2.14 frystyk 167: return HT_ERROR;
168: }
2.1 timbl 169: }
2.47 frystyk 170:
2.41 frystyk 171: /* We do this unconditionally, should we check to see if we ever blocked? */
2.54 frystyk 172: HTTRACEDATA(wrtp, b_write, "Writing to socket %d" _ soc);
2.51 frystyk 173: HTNet_addBytesWritten(net, b_write);
2.48 frystyk 174: wrtp += b_write;
2.14 frystyk 175: len -= b_write;
2.54 frystyk 176: HTTRACE(STREAM_TRACE, "Write Socket %d bytes written to %d\n" _ b_write _ soc);
2.28 frystyk 177: {
2.52 frystyk 178: HTAlertCallback *cbf = HTAlert_find(HT_PROG_WRITE);
2.53 frystyk 179: if (cbf) {
180: int tw = HTNet_bytesWritten(net);
181: (*cbf)(net->request, HT_PROG_WRITE,
182: HT_MSG_NULL, NULL, &tw, NULL);
183: }
2.28 frystyk 184: }
2.1 timbl 185: }
2.14 frystyk 186: #ifdef NOT_ASCII
2.29 frystyk 187: HT_FREE(me->ascbuf);
2.14 frystyk 188: #endif
189: return HT_OK;
2.1 timbl 190: }
191:
192: /* Character handling
193: ** ------------------
194: */
2.33 frystyk 195: PRIVATE int HTWriter_put_character (HTOutputStream * me, char c)
2.1 timbl 196: {
2.14 frystyk 197: return HTWriter_write(me, &c, 1);
2.1 timbl 198: }
199:
200: /* String handling
201: ** ---------------
202: **
203: ** Strings must be smaller than this buffer size.
204: */
2.33 frystyk 205: PRIVATE int HTWriter_put_string (HTOutputStream * me, const char * s)
2.1 timbl 206: {
2.14 frystyk 207: return HTWriter_write(me, s, (int) strlen(s));
2.1 timbl 208: }
2.33 frystyk 209: /*
210: ** The difference between the close and the free method is that we don't
211: ** close the connection in the free method - we only call the free method
212: ** of the target stream. That way, we can keep the output stream as long
213: ** as the channel itself.
214: */
215: PRIVATE int HTWriter_close (HTOutputStream * me)
2.1 timbl 216: {
2.54 frystyk 217: HTTRACE(STREAM_TRACE, "Socket write FREEING....\n");
2.29 frystyk 218: HT_FREE(me);
2.33 frystyk 219: return HT_OK;
2.1 timbl 220: }
221:
2.33 frystyk 222: PRIVATE const HTOutputStreamClass HTWriter =
2.1 timbl 223: {
2.14 frystyk 224: "SocketWriter",
225: HTWriter_flush,
226: HTWriter_free,
227: HTWriter_abort,
228: HTWriter_put_character,
229: HTWriter_put_string,
2.33 frystyk 230: HTWriter_write,
231: HTWriter_close
2.1 timbl 232: };
233:
2.41 frystyk 234: PUBLIC HTOutputStream * HTWriter_new (HTHost * host, HTChannel * ch,
2.33 frystyk 235: void * param, int mode)
2.1 timbl 236: {
2.41 frystyk 237: if (host && ch) {
2.33 frystyk 238: HTOutputStream * me = HTChannel_output(ch);
2.41 frystyk 239: if (!me) {
2.33 frystyk 240: if ((me=(HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL)
241: HT_OUTOFMEM("HTWriter_new");
242: me->isa = &HTWriter;
243: me->ch = ch;
2.41 frystyk 244: me->host = host;
2.33 frystyk 245: }
2.48 frystyk 246: return me;
2.33 frystyk 247: }
248: return NULL;
2.21 frystyk 249: }
Webmaster