Annotation of libwww/Library/src/HTBufWrt.c, revision 2.13
2.1 frystyk 1: /*
2: ** BUFFERED TRANSPORT WRITER STREAM
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.13 ! frystyk 6: ** @(#) $Id: HTBufWrt.c,v 2.12 1997/02/01 16:16:22 frystyk Exp $
2.1 frystyk 7: **
8: ** A buffered output stream. This stream lets you write characters to a
9: ** stream without causing a write every time. The data is first written
10: ** into a buffer. Data is written to the actual stream only when the
11: ** buffer is full, or when the stream is flushed.
12: */
13:
14: /* Library include files */
15: #include "sysdep.h"
16: #include "WWWUtil.h"
17: #include "WWWCore.h"
18: #include "HTNetMan.h"
19: #include "HTWriter.h"
2.6 frystyk 20: #include "HTTimer.h"
2.1 frystyk 21: #include "HTBufWrt.h" /* Implemented here */
22:
23: struct _HTOutputStream {
24: const HTOutputStreamClass * isa;
25: HTOutputStream * target; /* Target for outgoing data */
2.6 frystyk 26: HTHost * host;
2.1 frystyk 27: int size; /* Buffer size */
2.3 frystyk 28: int bb;
2.1 frystyk 29: char * block;
30: char * read; /* Position in 'data' */
31: char * data; /* buffer */
2.6 frystyk 32:
2.7 frystyk 33: ms_t lastFlushTime; /* polar coordinates of the moon */
2.6 frystyk 34: HTTimer * timer;
2.1 frystyk 35: };
36:
37: #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
38:
39: /* ------------------------------------------------------------------------- */
40:
2.11 frystyk 41: /*
42: ** This function is only called from either FlushEvent or HTBufferWriter_lazyFlush
43: ** which means that only the host object or timeout can cause a flush
44: */
2.1 frystyk 45: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
46: {
2.11 frystyk 47: int status = HT_ERROR;
48: if (me && me->read > me->data) {
2.1 frystyk 49: if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
50: return HT_WOULD_BLOCK;
2.6 frystyk 51: me->lastFlushTime = HTGetTimeInMillis();
2.1 frystyk 52: me->read = me->data;
53: me->block = NULL;
54: }
55: return status;
56: }
57:
2.9 eric 58: PRIVATE int FlushEvent (HTTimer * timer, void * param, HTEventType type)
2.6 frystyk 59: {
60: HTOutputStream * me = (HTOutputStream *) param;
61: if (timer != me->timer) HTDebugBreak();
2.11 frystyk 62: if (PROT_TRACE) HTTrace("Buffer...... Timeout Flushing...\n");
63:
64: /*
65: ** We ignore the return code here which we shouldn't!!!
66: */
2.6 frystyk 67: HTBufferWriter_flush(me);
2.11 frystyk 68:
69: /*
70: ** Delete the timer
71: */
72: HTTimer_delete(me->timer);
73: me->timer = NULL;
2.6 frystyk 74: return HT_OK;
75: }
76:
77: PRIVATE int HTBufferWriter_lazyFlush (HTOutputStream * me)
78: {
79: HTNet * net;
80: int delay;
81:
82: if (me->read <= me->data)
83: return HT_OK; /* nothing to flush */
84: /*
85: ** If we are allowed to delay the flush then set a timer with the
86: ** delay descibed by our delay variable. If we can't delay then flush
87: ** right away.
88: */
2.12 frystyk 89: delay = HTHost_findWriteDelay(me->host, me->lastFlushTime, me->read - me->data);
2.6 frystyk 90:
91: /*
92: ** Flush immediately
93: */
2.11 frystyk 94: if (!delay) {
95: int status;
96: if (PROT_TRACE) HTTrace("Buffer...... Flushing\n");
97: if ((status = HTBufferWriter_flush(me)) && me->timer) {
98: HTTimer_delete(me->timer);
99: me->timer = NULL;
100: }
101: return status;
102: }
2.6 frystyk 103:
104: /*
2.11 frystyk 105: ** Set a timer and tell the host we've done the write if
106: ** we have not already started a timer earlier.
2.6 frystyk 107: */
2.11 frystyk 108: if (!me->timer) {
109: net = HTHost_getWriteNet(me->host);
110: me->timer = HTTimer_new(NULL, FlushEvent, me, delay, YES);
111: HTHost_unregister(me->host, net, HTEvent_WRITE);
112: if (PROT_TRACE) HTTrace("Buffer...... Waiting...\n");
113: }
2.6 frystyk 114: return HT_OK;
115: }
116:
2.1 frystyk 117: PRIVATE int HTBufferWriter_free (HTOutputStream * me)
118: {
2.11 frystyk 119: return HTBufferWriter_lazyFlush(me);
2.1 frystyk 120: }
121:
122: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
123: {
2.8 frystyk 124: if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
2.1 frystyk 125: if (me->target) (*me->target->isa->abort)(me->target, e);
2.8 frystyk 126: if (me->timer) {
127: HTTimer_delete(me->timer);
128: me->timer = NULL;
129: }
2.1 frystyk 130: return HT_ERROR;
131: }
132:
2.6 frystyk 133: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1 frystyk 134: {
2.6 frystyk 135: HTNet * net = HTHost_getWriteNet(me->host);
2.4 frystyk 136: long total = len;
2.1 frystyk 137: int status;
2.4 frystyk 138:
2.3 frystyk 139: if (me->bb > 0) {
2.1 frystyk 140: len -= (me->block - buf);
2.3 frystyk 141: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
2.6 frystyk 142: me->lastFlushTime = HTGetTimeInMillis();
2.3 frystyk 143: me->block += me->bb;
144: len -= me->bb;
145: me->bb = 0;
146: } else {
147: int available = me->data + me->size - me->read;
148:
149: /* Still room in buffer */
150: if (len <= available) {
151: memcpy(me->read, buf, len);
152: me->read += len;
153: return HT_OK;
154: }
155:
156: /* If already data in buffer then fill it and flush */
157: if (me->read > me->data) {
158: memcpy(me->read, buf, available);
159: me->block = (char *) buf+available;
2.4 frystyk 160: if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
2.6 frystyk 161: me->lastFlushTime = HTGetTimeInMillis();
2.3 frystyk 162: }
163:
164: /* If more data then write n times buffer size */
165: if (!me->block)
166: me->block = (char *) buf;
167: else {
168: len -= (me->block - buf);
169: }
2.13 ! frystyk 170: #if 0
2.3 frystyk 171: me->bb = len - len%me->size;
2.13 ! frystyk 172: #else
! 173: me->bb = (len >= me->size) ? len : len - len%me->size;
! 174: #endif
2.6 frystyk 175: if (me->bb) {
176: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
177: me->lastFlushTime = HTGetTimeInMillis();
178: }
2.3 frystyk 179: me->block += me->bb;
180: len -= me->bb;
181: me->bb = 0;
2.1 frystyk 182: }
183:
184: /* If data is not aligned then save the rest in our buffer */
185: if (len > 0) {
186: memcpy(me->data, me->block, len);
187: me->read = me->data + len;
2.11 frystyk 188: if (PROT_TRACE) HTTrace("Buffer...... Carrying %d bytes over...\n", len);
189: #if 0
190: if ((status = HTBufferWriter_lazyFlush(me)) != HT_OK) return status;
191: #endif
2.1 frystyk 192: } else
193: me->read = me->data;
194: me->block = NULL;
2.6 frystyk 195: HTNet_addBytesWritten(net, total);
2.1 frystyk 196: return HT_OK;
197: }
198:
199: /* Character handling
200: ** ------------------
201: */
202: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
203: {
204: return HTBufferWriter_write(me, &c, 1);
205: }
206:
207: /* String handling
208: ** ---------------
209: **
210: ** Strings must be smaller than this buffer size.
211: */
212: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
213: {
214: return HTBufferWriter_write(me, s, (int) strlen(s));
215: }
216: /*
217: ** The difference between the close and the free method is that we don't
218: ** close the connection in the free method - we only call the free method
219: ** of the target stream. That way, we can keep the output stream as long
220: ** as the channel itself.
221: */
222: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
223: {
224: if (me) {
2.10 frystyk 225: #if 0
226: /*
227: ** The channel has been closed so we shouldn't do any more on
228: ** it at all
229: */
2.1 frystyk 230: HTBufferWriter_flush(me);
2.10 frystyk 231: #endif
2.1 frystyk 232: if (me->target) (*me->target->isa->close)(me->target);
233: HT_FREE(me->data);
234: HT_FREE(me);
235: }
236: return HT_OK;
237: }
238:
239: PRIVATE const HTOutputStreamClass HTBufferWriter =
240: {
2.6 frystyk 241: "BufferedSocketWriter",
242: HTBufferWriter_lazyFlush,
2.1 frystyk 243: HTBufferWriter_free,
244: HTBufferWriter_abort,
245: HTBufferWriter_put_character,
246: HTBufferWriter_put_string,
247: HTBufferWriter_write,
248: HTBufferWriter_close
249: };
250:
2.6 frystyk 251: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1 frystyk 252: void * param, int bufsize)
253: {
2.6 frystyk 254: if (host && ch) {
2.1 frystyk 255: HTOutputStream * me = HTChannel_output(ch);
2.6 frystyk 256: if (!me) {
257: HTOutputStream * me;
2.1 frystyk 258: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.6 frystyk 259: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1 frystyk 260: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
261: HT_OUTOFMEM("HTBufferWriter_new");
262: me->isa = &HTBufferWriter;
263: me->read = me->data;
264: me->size = bufsize;
2.6 frystyk 265: me->target = HTWriter_new(host, ch, param, 0);
266: me->host = host;
267: return me;
268: }
2.1 frystyk 269: }
270: return NULL;
271: }
Webmaster