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

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

Webmaster