Annotation of libwww/Library/src/HTReader.c, revision 2.3
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.3 ! frystyk 6: ** @(#) $Id: HTReader.c,v 2.2 1996/05/15 22:34:25 eric 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)
2.3 ! frystyk 125: HTTrace("Read Socket. FIN received on socket %d\n", soc);
2.1 frystyk 126: if (cbf) (*cbf)(net->request, HT_PROG_DONE,
127: HT_MSG_NULL, NULL, NULL, NULL);
2.3 ! frystyk 128: HTEvent_unRegister(soc, FD_READ);
! 129:
! 130: /* Update host information if persistent connection */
! 131: if (HTNet_persistent(net))
! 132: HTHost_catchClose(soc, net->request, FD_CLOSE);
2.1 frystyk 133: return HT_CLOSED;
134: }
135:
136: /* Remember how much we have read from the input socket */
137: me->write = me->data;
138: me->read = me->data + b_read;
139:
140: #ifdef NOT_ASCII
141: {
142: char *p = me->data;
143: while (p < me->read) {
144: *p = FROMASCII(*p);
145: p++;
146: }
147: }
148: #endif /* NOT_ASCII */
149:
150: if (PROT_TRACE)
151: HTTrace("Read Socket. %d bytes read from socket %d\n",
152: b_read, soc);
153: {
154: HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
155: net->bytes_read += b_read;
156: if (cbf) (*cbf)(net->request, HT_PROG_READ,
157: HT_MSG_NULL, NULL, NULL, NULL);
158: }
159: }
160:
161: /* Now push the data down the stream */
162: if ((status = (*me->target->isa->put_block)
163: (me->target, me->data, b_read)) != HT_OK) {
164: if (status == HT_WOULD_BLOCK) {
165: if (PROT_TRACE) HTTrace("Read Socket. Target WOULD BLOCK\n");
2.2 eric 166: HTEvent_unregister(soc, FD_READ);
2.1 frystyk 167: return HT_WOULD_BLOCK;
168: } else if (status == HT_PAUSE) {
169: if (PROT_TRACE) HTTrace("Read Socket. Target PAUSED\n");
2.2 eric 170: HTEvent_unregister(soc, FD_READ);
2.1 frystyk 171: return HT_PAUSE;
172: } else if (status>0) { /* Stream specific return code */
173: if (PROT_TRACE)
174: HTTrace("Read Socket. Target returns %d\n", status);
175: me->write = me->data + b_read;
176: return status;
177: } else { /* We have a real error */
178: if (PROT_TRACE) HTTrace("Read Socket. Target ERROR\n");
179: return status;
180: }
181: }
182: me->write = me->data + b_read;
183: } while (net->preemptive);
2.2 eric 184: HTEvent_register(soc, net->request, (SockOps) FD_READ,
2.1 frystyk 185: net->cbf, net->priority);
186: return HT_WOULD_BLOCK;
187: }
188:
189: /*
190: ** The difference between the close and the free method is that we don't
191: ** close the connection in the free method - we only call the free method
192: ** of the target stream. That way, we can keep the input stream as long
193: ** as the channel itself.
194: */
195: PRIVATE int HTReader_close (HTInputStream * me)
196: {
197: int status = HT_OK;
198: if (me->target) {
199: if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK)
200: return HT_WOULD_BLOCK;
201: }
202: if (PROT_TRACE) HTTrace("Socket read. FREEING....\n");
203: HT_FREE(me);
204: return status;
205: }
206:
207: PRIVATE const HTInputStreamClass HTReader =
208: {
209: "SocketReader",
210: HTReader_flush,
211: HTReader_free,
212: HTReader_abort,
213: HTReader_read,
214: HTReader_close
215: };
216:
217: /*
218: ** Create a new input read stream. Before we actually create it we check
219: ** to see whether we already have an input stream for this channel and if
220: ** so we just return that. This means that we can reuse input streams
221: ** in persistent connections, for example.
222: */
223: PUBLIC HTInputStream * HTReader_new (HTNet * net, HTChannel * ch,
224: HTStream * target, void * param, int mode)
225: {
226: if (net && ch) {
227: HTInputStream * me = HTChannel_input(ch);
228: if (me == NULL) {
229: if ((me=(HTInputStream *) HT_CALLOC(1, sizeof(HTInputStream))) == NULL)
230: HT_OUTOFMEM("HTReader_new");
231: me->isa = &HTReader;
232: me->ch = ch;
233: }
234: me->target = target;
235: me->net = net;
236: return me;
237: }
238: return NULL;
239: }
Webmaster