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