1 /*
2 ** BUFFERED MUX OUTPUT STREAM
3 **
4 ** (c) COPYRIGHT MIT 1995.
5 ** Please first read the full copyright statement in the file COPYRIGH.
6 ** @(#) $Id$
7 **
8 ** A buffered output MUX stream.
9 **
10 ** Authors
11 ** HFN Henrik Frystyk Nielsen <frystyk@w3.org>
12 **
13 ** History:
14 ** Oct 96 Written
15 */
16
17 /* Library include files */
18 #include "wwwsys.h"
19 #include "WWWUtil.h"
20 #include "WWWCore.h"
21 #include "WWWTrans.h"
22 #include "HTMuxHeader.h"
23 #include "HTMuxCh.h"
24 #include "HTMuxTx.h" /* Implemented here */
25
26 struct _HTOutputStream {
27 const HTOutputStreamClass * isa;
28 HTOutputStream * target; /* Target for outgoing data */
29 HTChannel * ch;
30 int size; /* Buffer size */
31 int bb;
32 char * block;
33 char * read; /* Position in 'data' */
34 char * data; /* buffer */
35 };
36
37 #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
38
39 /* ------------------------------------------------------------------------- */
40
HTMuxBuffer_write(HTOutputStream * me,const char * buf,int len)41 PRIVATE int HTMuxBuffer_write (HTOutputStream *me, const char *buf, int len)
42 {
43 int status;
44
45 if (me->bb > 0) {
46 len -= (me->block - buf);
47 if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
48 me->block += me->bb;
49 len -= me->bb;
50 me->bb = 0;
51 } else {
52 int available = me->data + me->size - me->read;
53
54 /* Still room in buffer */
55 if (len <= available) {
56 memcpy(me->read, buf, len);
57 me->read += len;
58 return HT_OK;
59 }
60
61 /* If already data in buffer then fill it and flush */
62 if (me->read > me->data) {
63 memcpy(me->read, buf, available);
64 me->block = (char *) buf+available;
65 if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
66 }
67
68 /* If more data then write n times buffer size */
69 if (!me->block)
70 me->block = (char *) buf;
71 else {
72 len -= (me->block - buf);
73 }
74 me->bb = len - len%me->size;
75 if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
76 me->block += me->bb;
77 len -= me->bb;
78 me->bb = 0;
79 }
80
81 /* If data is not aligned then save the rest in our buffer */
82 if (len > 0) {
83 memcpy(me->data, me->block, len);
84 me->read = me->data + len;
85 } else
86 me->read = me->data;
87 me->block = NULL;
88 return HT_OK;
89 }
90
HTMuxBuffer_put_character(HTOutputStream * me,char c)91 PRIVATE int HTMuxBuffer_put_character (HTOutputStream * me, char c)
92 {
93 return HTMuxBuffer_write(me, &c, 1);
94 }
95
HTMuxBuffer_put_string(HTOutputStream * me,const char * s)96 PRIVATE int HTMuxBuffer_put_string (HTOutputStream * me, const char * s)
97 {
98 return HTMuxBuffer_write(me, s, (int) strlen(s));
99 }
100
HTMuxBuffer_flush(HTOutputStream * me)101 PRIVATE int HTMuxBuffer_flush (HTOutputStream * me)
102 {
103 int status = HT_OK;
104 if (me->read > me->data) {
105 if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
106 return HT_WOULD_BLOCK;
107 me->read = me->data;
108 me->block = NULL;
109 }
110 return status;
111 }
112
HTMuxBuffer_free(HTOutputStream * me)113 PRIVATE int HTMuxBuffer_free (HTOutputStream * me)
114 {
115 #if 0
116 return HTMuxBuffer_flush(me);
117 #else
118 return HT_OK;
119 #endif
120 }
121
HTMuxBuffer_abort(HTOutputStream * me,HTList * e)122 PRIVATE int HTMuxBuffer_abort (HTOutputStream * me, HTList * e)
123 {
124 if (me->target) (*me->target->isa->abort)(me->target, e);
125 HTTRACE(PROT_TRACE, "MUX Tx...... ABORTING...\n");
126 return HT_ERROR;
127 }
128
129 /*
130 ** The difference between the close and the free method is that we don't
131 ** close the connection in the free method - we only call the free method
132 ** of the target stream. That way, we can keep the output stream as long
133 ** as the channel itself.
134 */
HTMuxBuffer_close(HTOutputStream * me)135 PRIVATE int HTMuxBuffer_close (HTOutputStream * me)
136 {
137 if (me) {
138 HTMuxBuffer_flush(me);
139 if (me->target) (*me->target->isa->close)(me->target);
140 HT_FREE(me->data);
141 HT_FREE(me);
142 }
143 return HT_OK;
144 }
145
146 PRIVATE const HTOutputStreamClass HTMuxBuffer =
147 {
148 "MuxBuffer",
149 HTMuxBuffer_flush,
150 HTMuxBuffer_free,
151 HTMuxBuffer_abort,
152 HTMuxBuffer_put_character,
153 HTMuxBuffer_put_string,
154 HTMuxBuffer_write,
155 HTMuxBuffer_close
156 };
157
HTMuxBuffer_new(HTHost * host,HTChannel * ch,void * param,int bufsize)158 PUBLIC HTOutputStream * HTMuxBuffer_new (HTHost * host, HTChannel * ch,
159 void * param, int bufsize)
160 {
161 if (host && ch) {
162 HTOutputStream * me = HTChannel_output(ch);
163 if (me == NULL) {
164 if (bufsize <= 0) bufsize = MUX_BUFFER_SIZE;
165 if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream))) == NULL ||
166 (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
167 HT_OUTOFMEM("HTMuxBuffer_new");
168 me->isa = &HTMuxBuffer;
169 me->target = HTWriter_new(host, ch, param, 0);
170 me->ch = ch;
171 me->size = bufsize;
172 me->read = me->data;
173 }
174 return me;
175 }
176 return NULL;
177 }
178