Annotation of libwww/Library/src/HTSocket.c, revision 2.20
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 */
2.20 ! frystyk 117: HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO,
! 118: "NETREAD");
2.11 frystyk 119: return HT_ERROR;
120: }
2.4 frystyk 121: } else if (!b_read) {
2.16 frystyk 122: HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
2.3 frystyk 123: if (PROT_TRACE)
2.16 frystyk 124: TTYPrint(TDEST,"Read Socket. Finished loading socket %d\n",
125: isoc->sockfd);
126: if(cbf)(*cbf)(request,HT_PROG_DONE,HT_MSG_NULL,NULL,NULL,NULL);
2.7 frystyk 127: HTEvent_UnRegister(isoc->sockfd, FD_READ);
2.4 frystyk 128: return HT_LOADED;
2.1 frystyk 129: }
130:
2.4 frystyk 131: /* Remember how much we have read from the input socket */
2.7 frystyk 132: isoc->write = isoc->buffer;
133: isoc->read = isoc->buffer + b_read;
2.1 frystyk 134:
135: #ifdef NOT_ASCII
2.4 frystyk 136: {
2.7 frystyk 137: char *p = isoc->buffer;
138: while (p < isoc->read) {
2.4 frystyk 139: *p = FROMASCII(*p);
140: p++;
141: }
2.1 frystyk 142: }
143: #endif
2.3 frystyk 144: if (PROT_TRACE)
2.14 frystyk 145: TTYPrint(TDEST, "Read Socket. %d bytes read from socket %d\n",
2.7 frystyk 146: b_read, isoc->sockfd);
2.8 frystyk 147: net->bytes_read += b_read;
2.16 frystyk 148:
149: {
150: HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
151: if (cbf)
152: (*cbf)(request, HT_PROG_READ, HT_MSG_NULL,NULL,NULL,NULL);
153: }
2.4 frystyk 154: }
155:
156: /* Now push the data down the stream */
2.7 frystyk 157: if ((status = (*target->isa->put_block)(target, isoc->buffer,
2.4 frystyk 158: b_read)) != HT_OK) {
159: if (status==HT_WOULD_BLOCK) {
160: if (PROT_TRACE)
2.14 frystyk 161: TTYPrint(TDEST, "Read Socket. Target WOULD BLOCK\n");
2.7 frystyk 162: HTEvent_UnRegister(isoc->sockfd, FD_READ);
2.4 frystyk 163: return HT_WOULD_BLOCK;
2.5 frystyk 164: } else if (status>0) { /* Stream specific return code */
165: if (PROT_TRACE)
2.17 frystyk 166: TTYPrint(TDEST, "Read Socket. Target returns %d\n",status);
2.10 frystyk 167: isoc->write = isoc->buffer + b_read;
2.5 frystyk 168: return status;
169: } else { /* We have a real error */
2.4 frystyk 170: if (PROT_TRACE)
2.14 frystyk 171: TTYPrint(TDEST, "Read Socket. Target ERROR\n");
2.4 frystyk 172: return status;
173: }
2.1 frystyk 174: }
2.7 frystyk 175: isoc->write = isoc->buffer + b_read;
2.20 ! frystyk 176: } while (net->preemptive);
2.10 frystyk 177: HTEvent_Register(isoc->sockfd, request, (SockOps) FD_READ,
178: net->cbf, net->priority);
2.1 frystyk 179: return HT_WOULD_BLOCK;
180: }
2.2 frystyk 181:
2.19 frystyk 182: /* HTSocket_DLLHackFopen
183: ** ---------------------
184: ** Work around the problem that an app can't open a file and have a dll
185: ** read from it!
186: */
187: #ifdef WWW_WIN_DLL
188: PUBLIC FILE * HTSocket_DLLHackFopen (const char * filename, const char * mode)
189: {
190: return (fopen(filename, mode));
191: }
192: #endif /* WWW_WIN_DLL */
193:
2.2 frystyk 194: /* Push data from an ANSI file descriptor down a stream
195: ** ----------------------------------------------------
196: **
197: ** This routine is responsible for creating and PRESENTING any
198: ** graphic (or other) objects described by the file.
199: **
200: ** Bugs: When we can wait on a file then this should also check interrupts!
201: **
202: ** Returns HT_LOADED if finished reading
203: ** HT_ERROR if error,
204: */
2.10 frystyk 205: PUBLIC int HTFileRead (HTRequest * request, HTNet * net, FILE * fp)
2.2 frystyk 206: {
2.10 frystyk 207: HTInputSocket *isoc = net->isoc;
208: HTStream *target = net->target;
2.2 frystyk 209: int b_read;
210: int status;
211: if (!fp) {
2.14 frystyk 212: if (PROT_TRACE) TTYPrint(TDEST, "Read File... Bad argument\n");
2.2 frystyk 213: return HT_ERROR;
214: }
215:
216: while(1) {
2.7 frystyk 217: if ((b_read = fread(isoc->buffer, 1, INPUT_BUFFER_SIZE, fp))==0){
2.2 frystyk 218: if (ferror(fp)) {
219: if (PROT_TRACE)
2.14 frystyk 220: TTYPrint(TDEST, "Read File... READ ERROR\n");
2.2 frystyk 221: } else
222: return HT_LOADED;
223: }
2.7 frystyk 224: isoc->write = isoc->buffer;
225: isoc->read = isoc->buffer + b_read;
2.2 frystyk 226: if (PROT_TRACE)
2.14 frystyk 227: TTYPrint(TDEST, "Read File... %d bytes read from file %p\n",
2.2 frystyk 228: b_read, fp);
229:
230: /* Now push the data down the stream (we use blocking I/O) */
2.7 frystyk 231: if ((status = (*target->isa->put_block)(target, isoc->buffer,
2.2 frystyk 232: b_read)) != HT_OK) {
233: if (PROT_TRACE)
2.14 frystyk 234: TTYPrint(TDEST, "Read File... Target ERROR\n");
2.2 frystyk 235: return status;
236: }
2.7 frystyk 237: isoc->write = isoc->buffer + b_read;
2.2 frystyk 238: }
239: }
240:
2.17 frystyk 241: /* HTLoadSocket
242: ** ------------
243: ** Given an open socket, this routine loads what ever is on the socket
244: **
245: ** On entry,
246: ** request This is the request structure
247: ** On Exit
248: ** returns HT_ERROR Error has occured in call back
249: ** HT_OK Call back was OK
250: */
251: PUBLIC int HTLoadSocket (SOCKET soc, HTRequest * request, SockOps ops)
252: {
2.18 frystyk 253: HTNet * net = NULL;
254: if (!request) return HT_ERROR;
2.17 frystyk 255: if (ops == FD_NONE) {
2.18 frystyk 256: HTNet * me;
2.17 frystyk 257: if (soc==INVSOC) {
258: if (PROT_TRACE) TTYPrint(TDEST, "Load Socket. invalid socket\n");
259: return HT_ERROR;
260: }
261: if (PROT_TRACE) TTYPrint(TDEST,"Load Socket. Loading socket %d\n",soc);
2.18 frystyk 262: me = HTNet_new(request, soc);
263: me->sockfd = soc;
264: me->target = request->output_stream;
265: me->isoc = HTInputSocket_new(soc);
266: net = me;
2.17 frystyk 267: } else if (ops == FD_CLOSE) { /* Interrupted */
268: HTNet_delete(request->net, HT_INTERRUPTED);
269: return HT_OK;
2.18 frystyk 270: } else
271: net = request->net;
272: if (!net) {
273: if (PROT_TRACE) TTYPrint(TDEST, "Load Socket. invalid argument\n");
274: return HT_ERROR;
2.17 frystyk 275: }
276:
277: /* In this load function we only have one state: READ */
278: {
279: int status = HTSocketRead(request, net);
280: if (status == HT_WOULD_BLOCK)
281: return HT_OK;
282: else if (status == HT_LOADED)
283: HTNet_delete(request->net, HT_LOADED);
284: else
285: HTNet_delete(request->net, HT_ERROR);
286: }
287: return HT_OK;
288: }
Webmaster