Annotation of libwww/Library/src/HTReader.c, revision 2.2
2.1 frystyk 1: /* HTReader.c
2: ** READ STREAM FROM THE NETWORK USING TCP
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.2 ! eric 6: ** @(#) $Id: HTReader.c,v 2.1 1996/04/12 17:48:35 frystyk Exp $
2.1 frystyk 7: **
8: ** HISTORY:
9: ** 6 June 95 HFN Written
10: */
11:
12: /* Library Include files */
13: #include "sysdep.h"
14: #include "WWWUtil.h"
15: #include "HTReqMan.h"
16: #include "HTProt.h"
17: #include "HTIOStream.h"
18: #include "HTChannl.h"
19: #include "HTAlert.h"
20: #include "HTFormat.h"
21: #include "HTNetMan.h"
22: #include "HTError.h"
23: #include "HTReader.h" /* Implemented here */
24:
25: struct _HTStream {
26: const HTStreamClass * isa;
27: /* ... */
28: };
29:
30: struct _HTInputStream {
31: const HTInputStreamClass * isa;
32: HTChannel * ch;
33: HTNet * net;
34: HTStream * target; /* Target for incoming data */
35: char * write; /* Last byte written */
36: char * read; /* Last byte read */
37: char data [INPUT_BUFFER_SIZE]; /* buffer */
38: };
39:
40: /* ------------------------------------------------------------------------- */
41:
42: PRIVATE int HTReader_flush (HTInputStream * me)
43: {
44: return me->target ? (*me->target->isa->flush)(me->target) : HT_OK;
45: }
46:
47: PRIVATE int HTReader_free (HTInputStream * me)
48: {
49: if (me->target) {
50: int status = (*me->target->isa->_free)(me->target);
51: if (status != HT_WOULD_BLOCK) me->target = NULL;
52: return status;
53: }
54: return HT_OK;
55: }
56:
57: PRIVATE int HTReader_abort (HTInputStream * me, HTList * e)
58: {
59: if (me->target) {
60: (*me->target->isa->abort)(me->target, NULL);
61: me->target = NULL;
62: }
63: return HT_ERROR;
64: }
65:
66: /* Push data from a socket down a stream
67: ** -------------------------------------
68: **
69: ** This routine is responsible for creating and PRESENTING any
70: ** graphic (or other) objects described by the file. As this function
71: ** max reads a chunk of data on size INPUT_BUFFER_SIZE, it can be used
72: ** with both blocking or non-blocking sockets. It will always return to
73: ** the event loop, however if we are using blocking I/O then we get a full
74: ** buffer read, otherwise we get what's available.
75: **
76: ** Returns HT_LOADED if finished reading
77: ** HT_OK if OK, but more to read
78: ** HT_ERROR if error,
79: ** HT_WOULD_BLOCK if read or write would block
80: ** HT_PAUSE if stream is paused
81: */
82: PRIVATE int HTReader_read (HTInputStream * me)
83: {
84: HTNet * net = me->net;
85: SOCKET soc = net->sockfd;
86: int b_read = me->read - me->data;
87: int status;
88:
89: /* Read from socket if we got rid of all the data previously read */
90: do {
91: if (me->write >= me->read) {
92: if ((b_read = NETREAD(soc, me->data, INPUT_BUFFER_SIZE)) < 0) {
93: #ifdef EAGAIN
94: if (socerrno==EAGAIN || socerrno==EWOULDBLOCK) /* POSIX */
95: #else
96: if (socerrno==EWOULDBLOCK) /* BSD */
97: #endif
98: {
99: if (PROT_TRACE)
100: HTTrace("Read Socket. WOULD BLOCK fd %d\n",soc);
2.2 ! eric 101: HTEvent_register(soc, net->request, (SockOps) FD_READ,
2.1 frystyk 102: net->cbf, net->priority);
103: return HT_WOULD_BLOCK;
104: #ifdef __svr4__
105: /*
106: ** In Solaris envirnoment, SIGPOLL is used to signal end of buffer for
107: ** /dev/audio. If your process is also doing a socket read, it will cause
108: ** an EINTR error. This error will cause the www library request to
109: ** terminate prematurly.
110: */
111: } else if (socerrno == EINTR) {
112: continue;
113: #endif /* __svr4__ */
114: } else { /* We have a real error */
115:
116: /* HERE WE SHOULD RETURN target abort */
117:
118: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno,
119: NO, "NETREAD");
120: return HT_ERROR;
121: }
122: } else if (!b_read) {
123: HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
124: if (PROT_TRACE)
125: HTTrace("Read Socket. Finished loading socket %d\n",
126: soc);
127: if (cbf) (*cbf)(net->request, HT_PROG_DONE,
128: HT_MSG_NULL, NULL, NULL, NULL);
2.2 ! eric 129: HTEvent_unregister(soc, FD_READ);
2.1 frystyk 130: return HT_CLOSED;
131: }
132:
133: /* Remember how much we have read from the input socket */
134: me->write = me->data;
135: me->read = me->data + b_read;
136:
137: #ifdef NOT_ASCII
138: {
139: char *p = me->data;
140: while (p < me->read) {
141: *p = FROMASCII(*p);
142: p++;
143: }
144: }
145: #endif /* NOT_ASCII */
146:
147: if (PROT_TRACE)
148: HTTrace("Read Socket. %d bytes read from socket %d\n",
149: b_read, soc);
150: {
151: HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
152: net->bytes_read += b_read;
153: if (cbf) (*cbf)(net->request, HT_PROG_READ,
154: HT_MSG_NULL, NULL, NULL, NULL);
155: }
156: }
157:
158: /* Now push the data down the stream */
159: if ((status = (*me->target->isa->put_block)
160: (me->target, me->data, b_read)) != HT_OK) {
161: if (status == HT_WOULD_BLOCK) {
162: if (PROT_TRACE) HTTrace("Read Socket. Target WOULD BLOCK\n");
2.2 ! eric 163: HTEvent_unregister(soc, FD_READ);
2.1 frystyk 164: return HT_WOULD_BLOCK;
165: } else if (status == HT_PAUSE) {
166: if (PROT_TRACE) HTTrace("Read Socket. Target PAUSED\n");
2.2 ! eric 167: HTEvent_unregister(soc, FD_READ);
2.1 frystyk 168: return HT_PAUSE;
169: } else if (status>0) { /* Stream specific return code */
170: if (PROT_TRACE)
171: HTTrace("Read Socket. Target returns %d\n", status);
172: me->write = me->data + b_read;
173: return status;
174: } else { /* We have a real error */
175: if (PROT_TRACE) HTTrace("Read Socket. Target ERROR\n");
176: return status;
177: }
178: }
179: me->write = me->data + b_read;
180: } while (net->preemptive);
2.2 ! eric 181: HTEvent_register(soc, net->request, (SockOps) FD_READ,
2.1 frystyk 182: net->cbf, net->priority);
183: return HT_WOULD_BLOCK;
184: }
185:
186: /*
187: ** The difference between the close and the free method is that we don't
188: ** close the connection in the free method - we only call the free method
189: ** of the target stream. That way, we can keep the input stream as long
190: ** as the channel itself.
191: */
192: PRIVATE int HTReader_close (HTInputStream * me)
193: {
194: int status = HT_OK;
195: if (me->target) {
196: if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK)
197: return HT_WOULD_BLOCK;
198: }
199: if (PROT_TRACE) HTTrace("Socket read. FREEING....\n");
200: HT_FREE(me);
201: return status;
202: }
203:
204: PRIVATE const HTInputStreamClass HTReader =
205: {
206: "SocketReader",
207: HTReader_flush,
208: HTReader_free,
209: HTReader_abort,
210: HTReader_read,
211: HTReader_close
212: };
213:
214: /*
215: ** Create a new input read stream. Before we actually create it we check
216: ** to see whether we already have an input stream for this channel and if
217: ** so we just return that. This means that we can reuse input streams
218: ** in persistent connections, for example.
219: */
220: PUBLIC HTInputStream * HTReader_new (HTNet * net, HTChannel * ch,
221: HTStream * target, void * param, int mode)
222: {
223: if (net && ch) {
224: HTInputStream * me = HTChannel_input(ch);
225: if (me == NULL) {
226: if ((me=(HTInputStream *) HT_CALLOC(1, sizeof(HTInputStream))) == NULL)
227: HT_OUTOFMEM("HTReader_new");
228: me->isa = &HTReader;
229: me->ch = ch;
230: }
231: me->target = target;
232: me->net = net;
233: return me;
234: }
235: return NULL;
236: }
Webmaster