Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5.2.3
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.3 ! frystyk 6: ** @(#) $Id: HTBufWrt.c,v 2.5.2.2 1996/10/30 23:21:52 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"
20: #include "HTBufWrt.h" /* Implemented here */
21:
22: struct _HTOutputStream {
23: const HTOutputStreamClass * isa;
24: HTOutputStream * target; /* Target for outgoing data */
2.5.2.2 frystyk 25: HTHost * host;
2.1 frystyk 26: int size; /* Buffer size */
2.3 frystyk 27: int bb;
2.1 frystyk 28: char * block;
29: char * read; /* Position in 'data' */
30: char * data; /* buffer */
2.5.2.3 ! frystyk 31:
! 32: BOOL delay_output;
! 33: BOOL delaying;
! 34: int delay_ms; /* Delay in ms */
! 35: HTEvent * delay_event;
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.3 ! frystyk 42: PRIVATE int HTBufferWriter_flush (HTOutputStream * me);
! 43: PRIVATE int FlushEvent (SOCKET soc, void * pVoid, HTEventType type)
! 44: {
! 45: HTOutputStream * me = (HTOutputStream *) pVoid;
! 46: me->delay_output = NO;
! 47: HTBufferWriter_flush(me);
! 48: me->delay_output = YES;
! 49: return HT_OK;
! 50: }
! 51:
2.1 frystyk 52: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
53: {
54: int status = HT_OK;
2.5.2.3 ! frystyk 55:
! 56: /*
! 57: ** If we are allowed to delay the flush then register an event with the
! 58: ** delay descibed by our delay variable. If we can't delay then flush
! 59: ** right away.
! 60: */
! 61: if (me->delay_output) {
! 62: HTChannel * ch = HTHost_channel(me->host);
! 63: me->delay_event = HTEvent_new(FlushEvent, me, HT_PRIORITY_MAX, me->delay_ms);
! 64: HTEvent_register(HTChannel_socket(ch), HTEvent_TIMEOUT, me->delay_event);
! 65: me->delaying = YES;
! 66: if (PROT_TRACE) HTTrace("Buffer...... Waiting...\n");
! 67: } else if (me->read > me->data) {
2.1 frystyk 68: if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
69: return HT_WOULD_BLOCK;
70: me->read = me->data;
71: me->block = NULL;
72: }
73: return status;
74: }
75:
76: PRIVATE int HTBufferWriter_free (HTOutputStream * me)
77: {
2.5.2.3 ! frystyk 78: me->delay_output = NO;
2.1 frystyk 79: return HTBufferWriter_flush(me);
80: }
81:
82: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
83: {
84: if (me->target) (*me->target->isa->abort)(me->target, e);
85: if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
86: return HT_ERROR;
87: }
88:
2.5.2.2 frystyk 89: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1 frystyk 90: {
2.5.2.2 frystyk 91: HTNet * net = HTHost_getReadNet(me->host);
2.4 frystyk 92: long total = len;
2.1 frystyk 93: int status;
2.4 frystyk 94:
2.3 frystyk 95: if (me->bb > 0) {
2.1 frystyk 96: len -= (me->block - buf);
2.3 frystyk 97: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
98: me->block += me->bb;
99: len -= me->bb;
100: me->bb = 0;
101: } else {
102: int available = me->data + me->size - me->read;
103:
104: /* Still room in buffer */
105: if (len <= available) {
106: memcpy(me->read, buf, len);
107: me->read += len;
108: return HT_OK;
109: }
110:
111: /* If already data in buffer then fill it and flush */
112: if (me->read > me->data) {
113: memcpy(me->read, buf, available);
114: me->block = (char *) buf+available;
2.5.2.3 ! frystyk 115: if (me->delay_event && me->delaying) {
! 116: HTChannel * ch = HTHost_channel(me->host);
! 117: HTEvent_unregister(HTChannel_socket(ch), HTEvent_TIMEOUT);
! 118: me->delaying = NO;
! 119: }
2.4 frystyk 120: if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
2.3 frystyk 121: }
122:
123: /* If more data then write n times buffer size */
124: if (!me->block)
125: me->block = (char *) buf;
126: else {
127: len -= (me->block - buf);
128: }
129: me->bb = len - len%me->size;
130: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
131: me->block += me->bb;
132: len -= me->bb;
133: me->bb = 0;
2.1 frystyk 134: }
135:
136: /* If data is not aligned then save the rest in our buffer */
137: if (len > 0) {
138: memcpy(me->data, me->block, len);
139: me->read = me->data + len;
140: } else
141: me->read = me->data;
142: me->block = NULL;
2.5.2.2 frystyk 143: net->bytesWritten += total;
2.1 frystyk 144: return HT_OK;
145: }
146:
147: /* Character handling
148: ** ------------------
149: */
150: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
151: {
152: return HTBufferWriter_write(me, &c, 1);
153: }
154:
155: /* String handling
156: ** ---------------
157: **
158: ** Strings must be smaller than this buffer size.
159: */
160: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
161: {
162: return HTBufferWriter_write(me, s, (int) strlen(s));
163: }
164: /*
165: ** The difference between the close and the free method is that we don't
166: ** close the connection in the free method - we only call the free method
167: ** of the target stream. That way, we can keep the output stream as long
168: ** as the channel itself.
169: */
170: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
171: {
172: if (me) {
2.5.2.3 ! frystyk 173: me->delay_output = NO;
2.1 frystyk 174: HTBufferWriter_flush(me);
175: if (me->target) (*me->target->isa->close)(me->target);
176: HT_FREE(me->data);
177: HT_FREE(me);
178: }
179: return HT_OK;
180: }
181:
182: PRIVATE const HTOutputStreamClass HTBufferWriter =
183: {
184: "SocketWriter",
185: HTBufferWriter_flush,
186: HTBufferWriter_free,
187: HTBufferWriter_abort,
188: HTBufferWriter_put_character,
189: HTBufferWriter_put_string,
190: HTBufferWriter_write,
191: HTBufferWriter_close
192: };
193:
2.5.2.2 frystyk 194: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1 frystyk 195: void * param, int bufsize)
196: {
2.5.2.2 frystyk 197: if (host && ch) {
2.1 frystyk 198: HTOutputStream * me = HTChannel_output(ch);
2.5.2.2 frystyk 199: if (!me) {
200: HTOutputStream * me;
2.1 frystyk 201: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.5.2.2 frystyk 202: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1 frystyk 203: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
204: HT_OUTOFMEM("HTBufferWriter_new");
205: me->isa = &HTBufferWriter;
206: me->read = me->data;
207: me->size = bufsize;
2.5.2.2 frystyk 208: me->target = HTWriter_new(host, ch, param, 0);
209: me->host = host;
2.5.2.3 ! frystyk 210: me->delay_output = YES;
! 211: me->delay_ms = 10000;
2.5.2.2 frystyk 212: return me;
213: }
2.1 frystyk 214: }
215: return NULL;
216: }
Webmaster