Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5.2.6

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

Webmaster