Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5.2.7
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.5.2.7 ! eric 6: ** @(#) $Id: HTBufWrt.c,v 2.5.2.6 1996/11/22 16:46:22 eric 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.5.2.4 eric 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.5.2.2 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.5.2.3 frystyk 32:
33: BOOL delaying;
2.5.2.4 eric 34: int lastFlushTime; /* polar coordinates of the moon */
35: HTTimer * timer;
2.1 frystyk 36: };
37:
38: #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
39:
40: /* ------------------------------------------------------------------------- */
41:
2.5.2.4 eric 42: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
43: {
44: int status = HT_OK;
45: if (me == NULL) return HT_ERROR;
46: if (me->read > me->data) {
47: if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
48: return HT_WOULD_BLOCK;
49: me->lastFlushTime = HTGetTimeInMillis();
50: me->read = me->data;
51: me->block = NULL;
52: }
53: if (me->timer) {
54: HTTimer_delete(me->timer);
55: me->timer = NULL;
56: }
57: return status;
58: }
59:
60: PRIVATE int FlushEvent (HTTimer * timer, void * param)
2.5.2.3 frystyk 61: {
2.5.2.4 eric 62: HTOutputStream * me = (HTOutputStream *) param;
63: if (timer != me->timer) HTDebugBreak();
2.5.2.3 frystyk 64: HTBufferWriter_flush(me);
65: return HT_OK;
66: }
67:
2.5.2.4 eric 68: PRIVATE int HTBufferWriter_lazyFlush (HTOutputStream * me)
2.1 frystyk 69: {
2.5.2.4 eric 70: HTNet * net;
71: int delay;
2.5.2.3 frystyk 72:
2.5.2.4 eric 73: if (me->read <= me->data)
74: return HT_OK; /* nothing to flush */
2.5.2.3 frystyk 75: /*
2.5.2.4 eric 76: ** If we are allowed to delay the flush then set a timer with the
2.5.2.3 frystyk 77: ** delay descibed by our delay variable. If we can't delay then flush
78: ** right away.
79: */
2.5.2.4 eric 80: delay = HTHost_writeDelay(me->host, me->lastFlushTime, me->read - me->data);
81:
82: /*
83: ** Flush immediately
84: */
85: if (!delay)
86: return HTBufferWriter_flush(me);
87:
88: /*
89: ** Delayed flush
90: */
91: if (me->timer) /* already queued to flush */
92: return HT_OK;
93:
94: /*
95: ** Set a timer and tell the host we've done the write
96: */
97: net = HTHost_getWriteNet(me->host);
98: me->timer = HTTimer_new(NULL, FlushEvent, me, delay, YES);
99: HTHost_unregister(me->host, net, HTEvent_WRITE);
100: if (PROT_TRACE) HTTrace("Buffer...... Waiting...\n");
101: return HT_OK;
2.1 frystyk 102: }
103:
104: PRIVATE int HTBufferWriter_free (HTOutputStream * me)
105: {
2.5.2.5 eric 106: return HTBufferWriter_flush(me);
2.1 frystyk 107: }
108:
109: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
110: {
111: if (me->target) (*me->target->isa->abort)(me->target, e);
112: if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
113: return HT_ERROR;
114: }
115:
2.5.2.2 frystyk 116: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1 frystyk 117: {
2.5.2.4 eric 118: HTNet * net = HTHost_getWriteNet(me->host);
2.4 frystyk 119: long total = len;
2.1 frystyk 120: int status;
2.4 frystyk 121:
2.3 frystyk 122: if (me->bb > 0) {
2.1 frystyk 123: len -= (me->block - buf);
2.3 frystyk 124: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
2.5.2.4 eric 125: me->lastFlushTime = HTGetTimeInMillis();
2.3 frystyk 126: me->block += me->bb;
127: len -= me->bb;
128: me->bb = 0;
129: } else {
130: int available = me->data + me->size - me->read;
131:
132: /* Still room in buffer */
133: if (len <= available) {
134: memcpy(me->read, buf, len);
135: me->read += len;
136: return HT_OK;
137: }
138:
139: /* If already data in buffer then fill it and flush */
140: if (me->read > me->data) {
141: memcpy(me->read, buf, available);
142: me->block = (char *) buf+available;
2.5.2.4 eric 143: if (me->timer && me->delaying) {
144: HTTimer_delete(me->timer);
145: me->timer=NULL;
2.5.2.3 frystyk 146: me->delaying = NO;
147: }
2.4 frystyk 148: if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
2.5.2.4 eric 149: me->lastFlushTime = HTGetTimeInMillis();
2.3 frystyk 150: }
151:
152: /* If more data then write n times buffer size */
153: if (!me->block)
154: me->block = (char *) buf;
155: else {
156: len -= (me->block - buf);
157: }
158: me->bb = len - len%me->size;
2.5.2.4 eric 159: if (me->bb) {
160: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
161: me->lastFlushTime = HTGetTimeInMillis();
162: }
2.3 frystyk 163: me->block += me->bb;
164: len -= me->bb;
165: me->bb = 0;
2.1 frystyk 166: }
167:
168: /* If data is not aligned then save the rest in our buffer */
169: if (len > 0) {
170: memcpy(me->data, me->block, len);
171: me->read = me->data + len;
172: } else
173: me->read = me->data;
174: me->block = NULL;
2.5.2.4 eric 175: HTNet_addBytesWritten(net, total);
2.1 frystyk 176: return HT_OK;
177: }
178:
179: /* Character handling
180: ** ------------------
181: */
182: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
183: {
184: return HTBufferWriter_write(me, &c, 1);
185: }
186:
187: /* String handling
188: ** ---------------
189: **
190: ** Strings must be smaller than this buffer size.
191: */
192: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
193: {
194: return HTBufferWriter_write(me, s, (int) strlen(s));
195: }
196: /*
197: ** The difference between the close and the free method is that we don't
198: ** close the connection in the free method - we only call the free method
199: ** of the target stream. That way, we can keep the output stream as long
200: ** as the channel itself.
201: */
202: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
203: {
204: if (me) {
205: HTBufferWriter_flush(me);
206: if (me->target) (*me->target->isa->close)(me->target);
207: HT_FREE(me->data);
208: HT_FREE(me);
209: }
210: return HT_OK;
211: }
212:
213: PRIVATE const HTOutputStreamClass HTBufferWriter =
214: {
2.5.2.5 eric 215: "BufferedSocketWriter",
2.5.2.4 eric 216: HTBufferWriter_lazyFlush,
2.1 frystyk 217: HTBufferWriter_free,
218: HTBufferWriter_abort,
219: HTBufferWriter_put_character,
220: HTBufferWriter_put_string,
221: HTBufferWriter_write,
222: HTBufferWriter_close
223: };
224:
2.5.2.2 frystyk 225: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1 frystyk 226: void * param, int bufsize)
227: {
2.5.2.2 frystyk 228: if (host && ch) {
2.1 frystyk 229: HTOutputStream * me = HTChannel_output(ch);
2.5.2.2 frystyk 230: if (!me) {
231: HTOutputStream * me;
2.1 frystyk 232: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.5.2.2 frystyk 233: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1 frystyk 234: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
235: HT_OUTOFMEM("HTBufferWriter_new");
236: me->isa = &HTBufferWriter;
237: me->read = me->data;
238: me->size = bufsize;
2.5.2.2 frystyk 239: me->target = HTWriter_new(host, ch, param, 0);
240: me->host = host;
241: return me;
242: }
2.1 frystyk 243: }
244: return NULL;
245: }
Webmaster