Annotation of libwww/Library/src/HTSocket.c, revision 2.18
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 */
13: #include "tcp.h"
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 {
34: CONST HTStreamClass * isa;
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: {
61: HTInputSocket *isoc = (HTInputSocket *)calloc(1, sizeof(*isoc));
62: if (!isoc) outofmem(__FILE__, "HTInputSocket_new");
2.7 frystyk 63: isoc->sockfd = file_number;
64: isoc->write = isoc->read = isoc->buffer;
2.1 frystyk 65: return isoc;
66: }
67:
2.12 frystyk 68: PUBLIC void HTInputSocket_free (HTInputSocket * me)
69: {
70: if (me) free(me);
71: }
72:
2.1 frystyk 73: /* Push data from a socket down a stream
74: ** -------------------------------------
75: **
76: ** This routine is responsible for creating and PRESENTING any
77: ** graphic (or other) objects described by the file. As this function
78: ** max reads a chunk of data on size INPUT_BUFFER_SIZE, it can be used
79: ** with both blocking or non-blocking sockets. It will always return to
80: ** the event loop, however if we are using blocking I/O then we get a full
81: ** buffer read, otherwise we get what's available.
82: **
83: ** Returns HT_LOADED if finished reading
2.3 frystyk 84: ** HT_OK if OK, but more to read
2.1 frystyk 85: ** HT_ERROR if error,
86: ** HT_WOULD_BLOCK if read would block
87: */
2.10 frystyk 88: PUBLIC int HTSocketRead (HTRequest * request, HTNet * net)
2.1 frystyk 89: {
2.7 frystyk 90: HTInputSocket *isoc = net->isoc;
2.10 frystyk 91: HTStream *target = net->target;
2.7 frystyk 92: int b_read = isoc->read - isoc->buffer;
2.1 frystyk 93: int status;
2.7 frystyk 94: if (!isoc || isoc->sockfd==INVSOC) {
2.14 frystyk 95: if (PROT_TRACE) TTYPrint(TDEST, "Read Socket. Bad argument\n");
2.1 frystyk 96: return HT_ERROR;
97: }
98:
2.3 frystyk 99: /* Read from socket if we got rid of all the data previously read */
2.4 frystyk 100: do {
2.7 frystyk 101: if (isoc->write >= isoc->read) {
102: if ((b_read = NETREAD(isoc->sockfd, isoc->buffer,
2.4 frystyk 103: INPUT_BUFFER_SIZE)) < 0) {
2.1 frystyk 104: #ifdef EAGAIN
2.4 frystyk 105: if (socerrno==EAGAIN || socerrno==EWOULDBLOCK) /* POSIX */
2.1 frystyk 106: #else
2.11 frystyk 107: if (socerrno==EWOULDBLOCK) /* BSD */
108: #endif
109: {
110: if (PROT_TRACE)
2.14 frystyk 111: TTYPrint(TDEST, "Read Socket. WOULD BLOCK soc %d\n",
2.11 frystyk 112: isoc->sockfd);
113: HTEvent_Register(isoc->sockfd, request, (SockOps) FD_READ,
114: net->cbf, net->priority);
115: return HT_WOULD_BLOCK;
116: } else { /* We have a real error */
117: if (PROT_TRACE)
2.14 frystyk 118: TTYPrint(TDEST, "Read Socket. READ ERROR %d\n",
2.11 frystyk 119: socerrno);
120: return HT_ERROR;
121: }
2.4 frystyk 122: } else if (!b_read) {
2.16 frystyk 123: HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
2.3 frystyk 124: if (PROT_TRACE)
2.16 frystyk 125: TTYPrint(TDEST,"Read Socket. Finished loading socket %d\n",
126: isoc->sockfd);
127: if(cbf)(*cbf)(request,HT_PROG_DONE,HT_MSG_NULL,NULL,NULL,NULL);
2.7 frystyk 128: HTEvent_UnRegister(isoc->sockfd, FD_READ);
2.4 frystyk 129: return HT_LOADED;
2.1 frystyk 130: }
131:
2.4 frystyk 132: /* Remember how much we have read from the input socket */
2.7 frystyk 133: isoc->write = isoc->buffer;
134: isoc->read = isoc->buffer + b_read;
2.1 frystyk 135:
136: #ifdef NOT_ASCII
2.4 frystyk 137: {
2.7 frystyk 138: char *p = isoc->buffer;
139: while (p < isoc->read) {
2.4 frystyk 140: *p = FROMASCII(*p);
141: p++;
142: }
2.1 frystyk 143: }
144: #endif
2.3 frystyk 145: if (PROT_TRACE)
2.14 frystyk 146: TTYPrint(TDEST, "Read Socket. %d bytes read from socket %d\n",
2.7 frystyk 147: b_read, isoc->sockfd);
2.8 frystyk 148: net->bytes_read += b_read;
2.16 frystyk 149:
150: {
151: HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
152: if (cbf)
153: (*cbf)(request, HT_PROG_READ, HT_MSG_NULL,NULL,NULL,NULL);
154: }
2.4 frystyk 155: }
156:
157: /* Now push the data down the stream */
2.7 frystyk 158: if ((status = (*target->isa->put_block)(target, isoc->buffer,
2.4 frystyk 159: b_read)) != HT_OK) {
160: if (status==HT_WOULD_BLOCK) {
161: if (PROT_TRACE)
2.14 frystyk 162: TTYPrint(TDEST, "Read Socket. Target WOULD BLOCK\n");
2.7 frystyk 163: HTEvent_UnRegister(isoc->sockfd, FD_READ);
2.4 frystyk 164: return HT_WOULD_BLOCK;
2.5 frystyk 165: } else if (status>0) { /* Stream specific return code */
166: if (PROT_TRACE)
2.17 frystyk 167: TTYPrint(TDEST, "Read Socket. Target returns %d\n",status);
2.10 frystyk 168: isoc->write = isoc->buffer + b_read;
2.5 frystyk 169: return status;
170: } else { /* We have a real error */
2.4 frystyk 171: if (PROT_TRACE)
2.14 frystyk 172: TTYPrint(TDEST, "Read Socket. Target ERROR\n");
2.4 frystyk 173: return status;
174: }
2.1 frystyk 175: }
2.7 frystyk 176: isoc->write = isoc->buffer + b_read;
177: } while (net->preemtive);
2.10 frystyk 178: HTEvent_Register(isoc->sockfd, request, (SockOps) FD_READ,
179: net->cbf, net->priority);
2.1 frystyk 180: return HT_WOULD_BLOCK;
181: }
2.2 frystyk 182:
183: /* Push data from an ANSI file descriptor down a stream
184: ** ----------------------------------------------------
185: **
186: ** This routine is responsible for creating and PRESENTING any
187: ** graphic (or other) objects described by the file.
188: **
189: ** Bugs: When we can wait on a file then this should also check interrupts!
190: **
191: ** Returns HT_LOADED if finished reading
192: ** HT_ERROR if error,
193: */
2.10 frystyk 194: PUBLIC int HTFileRead (HTRequest * request, HTNet * net, FILE * fp)
2.2 frystyk 195: {
2.10 frystyk 196: HTInputSocket *isoc = net->isoc;
197: HTStream *target = net->target;
2.2 frystyk 198: int b_read;
199: int status;
200: if (!fp) {
2.14 frystyk 201: if (PROT_TRACE) TTYPrint(TDEST, "Read File... Bad argument\n");
2.2 frystyk 202: return HT_ERROR;
203: }
204:
205: while(1) {
2.7 frystyk 206: if ((b_read = fread(isoc->buffer, 1, INPUT_BUFFER_SIZE, fp))==0){
2.2 frystyk 207: if (ferror(fp)) {
208: if (PROT_TRACE)
2.14 frystyk 209: TTYPrint(TDEST, "Read File... READ ERROR\n");
2.2 frystyk 210: } else
211: return HT_LOADED;
212: }
2.7 frystyk 213: isoc->write = isoc->buffer;
214: isoc->read = isoc->buffer + b_read;
2.2 frystyk 215: if (PROT_TRACE)
2.14 frystyk 216: TTYPrint(TDEST, "Read File... %d bytes read from file %p\n",
2.2 frystyk 217: b_read, fp);
218:
219: /* Now push the data down the stream (we use blocking I/O) */
2.7 frystyk 220: if ((status = (*target->isa->put_block)(target, isoc->buffer,
2.2 frystyk 221: b_read)) != HT_OK) {
222: if (PROT_TRACE)
2.14 frystyk 223: TTYPrint(TDEST, "Read File... Target ERROR\n");
2.2 frystyk 224: return status;
225: }
2.7 frystyk 226: isoc->write = isoc->buffer + b_read;
2.2 frystyk 227: }
228: }
229:
2.17 frystyk 230: /* HTLoadSocket
231: ** ------------
232: ** Given an open socket, this routine loads what ever is on the socket
233: **
234: ** On entry,
235: ** request This is the request structure
236: ** On Exit
237: ** returns HT_ERROR Error has occured in call back
238: ** HT_OK Call back was OK
239: */
240: PUBLIC int HTLoadSocket (SOCKET soc, HTRequest * request, SockOps ops)
241: {
2.18 ! frystyk 242: HTNet * net = NULL;
! 243: if (!request) return HT_ERROR;
2.17 frystyk 244: if (ops == FD_NONE) {
2.18 ! frystyk 245: HTNet * me;
2.17 frystyk 246: if (soc==INVSOC) {
247: if (PROT_TRACE) TTYPrint(TDEST, "Load Socket. invalid socket\n");
248: return HT_ERROR;
249: }
250: if (PROT_TRACE) TTYPrint(TDEST,"Load Socket. Loading socket %d\n",soc);
2.18 ! frystyk 251: me = HTNet_new(request, soc);
! 252: me->sockfd = soc;
! 253: me->target = request->output_stream;
! 254: me->isoc = HTInputSocket_new(soc);
! 255: net = me;
2.17 frystyk 256: } else if (ops == FD_CLOSE) { /* Interrupted */
257: HTNet_delete(request->net, HT_INTERRUPTED);
258: return HT_OK;
2.18 ! frystyk 259: } else
! 260: net = request->net;
! 261: if (!net) {
! 262: if (PROT_TRACE) TTYPrint(TDEST, "Load Socket. invalid argument\n");
! 263: return HT_ERROR;
2.17 frystyk 264: }
265:
266: /* In this load function we only have one state: READ */
267: {
268: int status = HTSocketRead(request, net);
269: if (status == HT_WOULD_BLOCK)
270: return HT_OK;
271: else if (status == HT_LOADED)
272: HTNet_delete(request->net, HT_LOADED);
273: else
274: HTNet_delete(request->net, HT_ERROR);
275: }
276: return HT_OK;
277: }
Webmaster