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