Annotation of libwww/Library/src/HTSocket.c, revision 2.26
2.1 frystyk 1: /* HTSocket.c
2: ** MANAGES READ AND WRITE TO AND FROM THE NETWORK
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
6: **
7: **
8: ** HISTORY:
9: ** 6 June 95 HFN Spawned off from HTFormat
10: */
11:
12: /* Library Include files */
2.25 frystyk 13: #include "sysdep.h"
2.1 frystyk 14: #include "HTUtils.h"
15: #include "HTString.h"
2.7 frystyk 16: #include "HTReqMan.h"
2.4 frystyk 17: #include "HTProt.h"
2.1 frystyk 18: #include "HTTCP.h"
19: #include "HTStream.h"
2.6 frystyk 20: #include "HTAlert.h"
2.1 frystyk 21: #include "HTFormat.h"
2.8 frystyk 22: #include "HTNetMan.h"
2.1 frystyk 23: #include "HTError.h"
24: #include "HTSocket.h" /* Implemented here */
25:
2.2 frystyk 26: struct _HTInputSocket {
2.7 frystyk 27: char buffer[INPUT_BUFFER_SIZE];
28: char * write; /* Last byte written */
29: char * read; /* Last byte read */
2.17 frystyk 30: SOCKET sockfd;
2.2 frystyk 31: };
32:
2.1 frystyk 33: struct _HTStream {
2.25 frystyk 34: const HTStreamClass * isa;
2.1 frystyk 35: };
36:
37: /* ------------------------------------------------------------------------- */
38: /* SOCKET INPUT BUFFERING */
39: /* ------------------------------------------------------------------------- */
40: /*
41: ** This code is used because one cannot in general open a
42: ** file descriptor for a socket.
43: **
44: ** The input file is read using the macro which can read from
45: ** a socket or a file, but this should not be used for files
46: ** as fopen() etc is more portable of course.
47: **
48: ** The input buffer size, if large will give greater efficiency and
49: ** release the server faster, and if small will save space on PCs etc.
50: */
51:
52:
53: /* Set up the buffering
54: **
55: ** These routines are public because they are in fact needed by
56: ** many parsers, and on PCs and Macs we should not duplicate
57: ** the static buffer area.
58: */
2.17 frystyk 59: PUBLIC HTInputSocket * HTInputSocket_new (SOCKET file_number)
2.1 frystyk 60: {
2.23 frystyk 61: HTInputSocket *isoc;
62: if ((isoc = (HTInputSocket *) HT_CALLOC(1, sizeof(*isoc))) == NULL)
63: HT_OUTOFMEM("HTInputSocket_new");
2.7 frystyk 64: isoc->sockfd = file_number;
65: isoc->write = isoc->read = isoc->buffer;
2.1 frystyk 66: return isoc;
67: }
68:
2.12 frystyk 69: PUBLIC void HTInputSocket_free (HTInputSocket * me)
70: {
2.23 frystyk 71: if (me) HT_FREE(me);
2.12 frystyk 72: }
73:
2.1 frystyk 74: /* Push data from a socket down a stream
75: ** -------------------------------------
76: **
77: ** This routine is responsible for creating and PRESENTING any
78: ** graphic (or other) objects described by the file. As this function
79: ** max reads a chunk of data on size INPUT_BUFFER_SIZE, it can be used
80: ** with both blocking or non-blocking sockets. It will always return to
81: ** the event loop, however if we are using blocking I/O then we get a full
82: ** buffer read, otherwise we get what's available.
83: **
84: ** Returns HT_LOADED if finished reading
2.3 frystyk 85: ** HT_OK if OK, but more to read
2.1 frystyk 86: ** HT_ERROR if error,
2.21 frystyk 87: ** HT_WOULD_BLOCK if read or write would block
88: ** HT_PAUSE if stream is paused
2.1 frystyk 89: */
2.10 frystyk 90: PUBLIC int HTSocketRead (HTRequest * request, HTNet * net)
2.1 frystyk 91: {
2.7 frystyk 92: HTInputSocket *isoc = net->isoc;
2.10 frystyk 93: HTStream *target = net->target;
2.7 frystyk 94: int b_read = isoc->read - isoc->buffer;
2.1 frystyk 95: int status;
2.7 frystyk 96: if (!isoc || isoc->sockfd==INVSOC) {
2.24 eric 97: if (PROT_TRACE) HTTrace("Read Socket. Bad argument\n");
2.1 frystyk 98: return HT_ERROR;
99: }
100:
2.3 frystyk 101: /* Read from socket if we got rid of all the data previously read */
2.4 frystyk 102: do {
2.7 frystyk 103: if (isoc->write >= isoc->read) {
104: if ((b_read = NETREAD(isoc->sockfd, isoc->buffer,
2.4 frystyk 105: INPUT_BUFFER_SIZE)) < 0) {
2.1 frystyk 106: #ifdef EAGAIN
2.4 frystyk 107: if (socerrno==EAGAIN || socerrno==EWOULDBLOCK) /* POSIX */
2.1 frystyk 108: #else
2.11 frystyk 109: if (socerrno==EWOULDBLOCK) /* BSD */
110: #endif
111: {
112: if (PROT_TRACE)
2.24 eric 113: HTTrace("Read Socket. WOULD BLOCK soc %d\n",
2.11 frystyk 114: isoc->sockfd);
115: HTEvent_Register(isoc->sockfd, request, (SockOps) FD_READ,
116: net->cbf, net->priority);
117: return HT_WOULD_BLOCK;
2.21 frystyk 118: #ifdef __svr4__
119: /*
120: ** In Solaris envirnoment, SIGPOLL is used to signal end of buffer for
121: ** /dev/audio. If your process is also doing a socket read, it will cause
122: ** an EINTR error. This error will cause the www library request to
123: ** terminate prematurly.
124: */
125: } else if (socerrno == EINTR) {
126: continue;
127: #endif
2.11 frystyk 128: } else { /* We have a real error */
2.20 frystyk 129: HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO,
130: "NETREAD");
2.11 frystyk 131: return HT_ERROR;
132: }
2.4 frystyk 133: } else if (!b_read) {
2.16 frystyk 134: HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
2.3 frystyk 135: if (PROT_TRACE)
2.24 eric 136: HTTrace("Read Socket. Finished loading socket %d\n",
2.16 frystyk 137: isoc->sockfd);
138: if(cbf)(*cbf)(request,HT_PROG_DONE,HT_MSG_NULL,NULL,NULL,NULL);
2.7 frystyk 139: HTEvent_UnRegister(isoc->sockfd, FD_READ);
2.21 frystyk 140: return HT_CLOSED;
2.1 frystyk 141: }
142:
2.4 frystyk 143: /* Remember how much we have read from the input socket */
2.7 frystyk 144: isoc->write = isoc->buffer;
145: isoc->read = isoc->buffer + b_read;
2.1 frystyk 146:
147: #ifdef NOT_ASCII
2.4 frystyk 148: {
2.7 frystyk 149: char *p = isoc->buffer;
150: while (p < isoc->read) {
2.4 frystyk 151: *p = FROMASCII(*p);
152: p++;
153: }
2.1 frystyk 154: }
155: #endif
2.3 frystyk 156: if (PROT_TRACE)
2.24 eric 157: HTTrace("Read Socket. %d bytes read from socket %d\n",
2.7 frystyk 158: b_read, isoc->sockfd);
2.8 frystyk 159: net->bytes_read += b_read;
2.16 frystyk 160:
161: {
162: HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
163: if (cbf)
164: (*cbf)(request, HT_PROG_READ, HT_MSG_NULL,NULL,NULL,NULL);
165: }
2.4 frystyk 166: }
167:
168: /* Now push the data down the stream */
2.7 frystyk 169: if ((status = (*target->isa->put_block)(target, isoc->buffer,
2.4 frystyk 170: b_read)) != HT_OK) {
171: if (status==HT_WOULD_BLOCK) {
172: if (PROT_TRACE)
2.24 eric 173: HTTrace("Read Socket. Target WOULD BLOCK\n");
2.7 frystyk 174: HTEvent_UnRegister(isoc->sockfd, FD_READ);
2.4 frystyk 175: return HT_WOULD_BLOCK;
2.21 frystyk 176: } else if (status == HT_PAUSE) {
2.24 eric 177: if (PROT_TRACE) HTTrace("Read Socket. Target PAUSED\n");
2.21 frystyk 178: HTEvent_UnRegister(isoc->sockfd, FD_READ);
179: return HT_PAUSE;
2.5 frystyk 180: } else if (status>0) { /* Stream specific return code */
181: if (PROT_TRACE)
2.24 eric 182: HTTrace("Read Socket. Target returns %d\n",status);
2.10 frystyk 183: isoc->write = isoc->buffer + b_read;
2.5 frystyk 184: return status;
185: } else { /* We have a real error */
2.4 frystyk 186: if (PROT_TRACE)
2.24 eric 187: HTTrace("Read Socket. Target ERROR\n");
2.4 frystyk 188: return status;
189: }
2.1 frystyk 190: }
2.7 frystyk 191: isoc->write = isoc->buffer + b_read;
2.20 frystyk 192: } while (net->preemptive);
2.10 frystyk 193: HTEvent_Register(isoc->sockfd, request, (SockOps) FD_READ,
194: net->cbf, net->priority);
2.1 frystyk 195: return HT_WOULD_BLOCK;
196: }
2.2 frystyk 197:
2.26 ! eric 198: /* HTSocket_DLLHackFopen and close
! 199: ** -------------------------------
2.19 frystyk 200: ** Work around the problem that an app can't open a file and have a dll
201: ** read from it!
202: */
203: #ifdef WWW_WIN_DLL
204: PUBLIC FILE * HTSocket_DLLHackFopen (const char * filename, const char * mode)
205: {
206: return (fopen(filename, mode));
2.26 ! eric 207: }
! 208:
! 209: PUBLIC int HTSocket_DLLHackFclose (FILE * file)
! 210: {
! 211: return (fclose(file));
2.19 frystyk 212: }
213: #endif /* WWW_WIN_DLL */
214:
2.2 frystyk 215: /* Push data from an ANSI file descriptor down a stream
216: ** ----------------------------------------------------
217: **
218: ** This routine is responsible for creating and PRESENTING any
219: ** graphic (or other) objects described by the file.
220: **
221: ** Bugs: When we can wait on a file then this should also check interrupts!
222: **
223: ** Returns HT_LOADED if finished reading
224: ** HT_ERROR if error,
225: */
2.10 frystyk 226: PUBLIC int HTFileRead (HTRequest * request, HTNet * net, FILE * fp)
2.2 frystyk 227: {
2.10 frystyk 228: HTInputSocket *isoc = net->isoc;
229: HTStream *target = net->target;
2.2 frystyk 230: int b_read;
231: int status;
232: if (!fp) {
2.24 eric 233: if (PROT_TRACE) HTTrace("Read File... Bad argument\n");
2.2 frystyk 234: return HT_ERROR;
235: }
236:
237: while(1) {
2.7 frystyk 238: if ((b_read = fread(isoc->buffer, 1, INPUT_BUFFER_SIZE, fp))==0){
2.2 frystyk 239: if (ferror(fp)) {
240: if (PROT_TRACE)
2.24 eric 241: HTTrace("Read File... READ ERROR\n");
2.2 frystyk 242: } else
243: return HT_LOADED;
244: }
2.7 frystyk 245: isoc->write = isoc->buffer;
246: isoc->read = isoc->buffer + b_read;
2.2 frystyk 247: if (PROT_TRACE)
2.24 eric 248: HTTrace("Read File... %d bytes read from file %p\n",
2.2 frystyk 249: b_read, fp);
250:
251: /* Now push the data down the stream (we use blocking I/O) */
2.7 frystyk 252: if ((status = (*target->isa->put_block)(target, isoc->buffer,
2.2 frystyk 253: b_read)) != HT_OK) {
254: if (PROT_TRACE)
2.24 eric 255: HTTrace("Read File... Target ERROR\n");
2.2 frystyk 256: return status;
257: }
2.7 frystyk 258: isoc->write = isoc->buffer + b_read;
2.2 frystyk 259: }
260: }
261:
2.17 frystyk 262: /* HTLoadSocket
263: ** ------------
264: ** Given an open socket, this routine loads what ever is on the socket
265: **
266: ** On entry,
267: ** request This is the request structure
268: ** On Exit
269: ** returns HT_ERROR Error has occured in call back
270: ** HT_OK Call back was OK
271: */
272: PUBLIC int HTLoadSocket (SOCKET soc, HTRequest * request, SockOps ops)
273: {
2.18 frystyk 274: HTNet * net = NULL;
275: if (!request) return HT_ERROR;
2.17 frystyk 276: if (ops == FD_NONE) {
2.18 frystyk 277: HTNet * me;
2.17 frystyk 278: if (soc==INVSOC) {
2.24 eric 279: if (PROT_TRACE) HTTrace("Load Socket. invalid socket\n");
2.17 frystyk 280: return HT_ERROR;
281: }
2.24 eric 282: if (PROT_TRACE) HTTrace("Load Socket. Loading socket %d\n",soc);
2.18 frystyk 283: me = HTNet_new(request, soc);
284: me->sockfd = soc;
285: me->target = request->output_stream;
286: me->isoc = HTInputSocket_new(soc);
287: net = me;
2.17 frystyk 288: } else if (ops == FD_CLOSE) { /* Interrupted */
289: HTNet_delete(request->net, HT_INTERRUPTED);
290: return HT_OK;
2.18 frystyk 291: } else
292: net = request->net;
293: if (!net) {
2.24 eric 294: if (PROT_TRACE) HTTrace("Load Socket. invalid argument\n");
2.18 frystyk 295: return HT_ERROR;
2.17 frystyk 296: }
297:
298: /* In this load function we only have one state: READ */
299: {
300: int status = HTSocketRead(request, net);
301: if (status == HT_WOULD_BLOCK)
302: return HT_OK;
2.22 frystyk 303: else if (status == HT_CLOSED)
2.17 frystyk 304: HTNet_delete(request->net, HT_LOADED);
305: else
306: HTNet_delete(request->net, HT_ERROR);
307: }
308: return HT_OK;
309: }
Webmaster