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