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

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.15    ! frystyk     6: **     @(#) $Id: HTBufWrt.c,v 2.14 1997/11/26 16:05:14 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.15    ! frystyk    27: 
        !            28:     int                                allocated;          /* Allocated Buffer size */
        !            29:     int                         growby;
        !            30: 
2.1       frystyk    31:     char *                     read;                  /* Position in 'data' */
                     32:     char *                     data;                              /* buffer */
2.6       frystyk    33: 
2.7       frystyk    34:     ms_t                       lastFlushTime;  /* polar coordinates of the moon */
2.6       frystyk    35:     HTTimer *                  timer;
2.1       frystyk    36: };
                     37: 
                     38: #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
                     39: 
                     40: /* ------------------------------------------------------------------------- */
                     41: 
2.11      frystyk    42: /*
                     43: **  This function is only called from either FlushEvent or HTBufferWriter_lazyFlush
                     44: **  which means that only the host object or timeout can cause a flush
                     45: */
2.1       frystyk    46: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
                     47: {
2.11      frystyk    48:     int status = HT_ERROR;
                     49:     if (me && me->read > me->data) {
2.1       frystyk    50:        if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
                     51:            return HT_WOULD_BLOCK;
2.6       frystyk    52:        me->lastFlushTime = HTGetTimeInMillis();
2.1       frystyk    53:        me->read = me->data;
                     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:     me->timer = NULL;
2.6       frystyk    73:     return HT_OK;
                     74: }
                     75: 
                     76: PRIVATE int HTBufferWriter_lazyFlush (HTOutputStream * me)
                     77: {
                     78:     HTNet * net;
                     79:     int delay;
                     80: 
                     81:     if (me->read <= me->data)
                     82:        return HT_OK;                   /* nothing to flush */
                     83:     /*
                     84:     **  If we are allowed to delay the flush then set a timer with the
                     85:     **  delay descibed by our delay variable. If we can't delay then flush 
                     86:     **  right away.
                     87:     */
2.12      frystyk    88:     delay = HTHost_findWriteDelay(me->host, me->lastFlushTime, me->read - me->data);
2.6       frystyk    89: 
                     90:     /*
                     91:     ** Flush immediately
                     92:     */
2.11      frystyk    93:     if (!delay) {
                     94:        int status;
                     95:        if (PROT_TRACE) HTTrace("Buffer...... Flushing\n");
                     96:        if ((status = HTBufferWriter_flush(me)) && me->timer) {
                     97:            HTTimer_delete(me->timer);
                     98:            me->timer = NULL;
                     99:        }
                    100:        return status;
                    101:     }
2.6       frystyk   102: 
                    103:     /*
2.11      frystyk   104:     ** Set a timer and tell the host we've done the write if
                    105:     **  we have not already started a timer earlier.
2.6       frystyk   106:     */
2.11      frystyk   107:     if (!me->timer) {
2.14      frystyk   108:        ms_t exp = HTGetTimeInMillis() + delay;
2.11      frystyk   109:        net = HTHost_getWriteNet(me->host);
2.14      frystyk   110:        me->timer = HTTimer_new(NULL, FlushEvent, me, exp, NO);
2.11      frystyk   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: 
2.15    ! frystyk   122: PRIVATE BOOL HTBufferWriter_addBuffer(HTOutputStream * me, int addthis)
        !           123: {
        !           124:     if (me) {
        !           125:         me->allocated += (addthis - addthis%me->growby + me->growby);
        !           126:         HTTrace("Buffer...... Increasing buffer to %d bytes\n", me->allocated);
        !           127:         if (me->data) {
        !           128:             int size = me->read-me->data;
        !           129:             if ((me->data = (char *) HT_REALLOC(me->data, me->allocated)) == NULL)
        !           130:                 HT_OUTOFMEM("HTBufferWriter_addBuffer");
        !           131:             me->read = me->data + size;
        !           132:         } else {
        !           133:             if ((me->data = (char *) HT_CALLOC(1, me->allocated)) == NULL)
        !           134:                 HT_OUTOFMEM("HTBufferWriter_addBuffer");
        !           135:             me->read = me->data;
        !           136:         }
        !           137:        return YES;
        !           138:     }
        !           139:     return NO;
        !           140: }
        !           141: 
2.1       frystyk   142: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
                    143: {
2.8       frystyk   144:     if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
2.1       frystyk   145:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.8       frystyk   146:     if (me->timer) {
                    147:        HTTimer_delete(me->timer);
                    148:        me->timer = NULL;
                    149:     }
2.1       frystyk   150:     return HT_ERROR;
                    151: }
                    152: 
2.6       frystyk   153: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1       frystyk   154: {
2.6       frystyk   155:     HTNet * net = HTHost_getWriteNet(me->host);
2.1       frystyk   156:     int status;
2.15    ! frystyk   157:     int available = me->data + me->allocated - me->read;
        !           158:     
        !           159:     /* Still room in buffer */
        !           160:     if (len <= available) {
        !           161:         int size = 0;
        !           162:         memcpy(me->read, buf, len);
        !           163:         me->read += len;
        !           164:         
        !           165:         /* If we have accumulated data then flush */
        !           166:         size = me->read - me->data;
        !           167:         if (size > me->growby) {
        !           168:             status = PUTBLOCK(me->data, size);
        !           169:             me->lastFlushTime = HTGetTimeInMillis();
        !           170:             if (status == HT_OK) {
        !           171:                 HTNet_addBytesWritten(net, size);
        !           172:                 me->read = me->data;
        !           173:             } else {
        !           174:                 return (status == HT_WOULD_BLOCK) ? HT_OK : HT_ERROR;
        !           175:             }
        !           176:         }
        !           177:         return HT_OK;
        !           178:     }
        !           179:     
        !           180:     /* If already data in buffer then fill it and flush */
        !           181:     if (me->read > me->data) {
        !           182:         if (available) {
        !           183:             memcpy(me->read, buf, available);
        !           184:             buf += available;
        !           185:             len -= available;
        !           186:             me->read += available;
        !           187:         }
        !           188:         status = PUTBLOCK(me->data, me->allocated);
        !           189:         me->lastFlushTime = HTGetTimeInMillis();
        !           190:         if (status == HT_OK) {
        !           191:             HTNet_addBytesWritten(net, me->allocated);
        !           192:             me->read = me->data;
        !           193:         } else if (status == HT_WOULD_BLOCK) {
        !           194:             HTBufferWriter_addBuffer(me, len);
        !           195:             memcpy(me->read, buf, len);
        !           196:             me->read += len;
        !           197:             return HT_OK;
        !           198:         }
        !           199:     }
2.4       frystyk   200: 
2.15    ! frystyk   201:     /*
        !           202:     ** If more than a new full buffer of data remains then
        !           203:     ** write it. Otherwise carry it over to the next write
        !           204:     */
        !           205:     if (len > me->allocated) {
        !           206:         status = PUTBLOCK(buf, len);
        !           207:         me->lastFlushTime = HTGetTimeInMillis();
        !           208:         if (status == HT_OK) {
        !           209:             HTNet_addBytesWritten(net, len);
        !           210:             me->read = me->data;
        !           211:         } else {
        !           212:             if (status == HT_WOULD_BLOCK) {
        !           213:                 HTBufferWriter_addBuffer(me, len);
        !           214:                 memcpy(me->read, buf, len);
        !           215:                 me->read += len;
        !           216:                 return HT_OK;
        !           217:             }
        !           218:             return status;
        !           219:         }
2.3       frystyk   220:     } else {
2.15    ! frystyk   221:         memcpy(me->data, buf, len);
        !           222:         me->read += len;
2.1       frystyk   223:     }
                    224:     return HT_OK;
                    225: }
                    226: 
                    227: /*     Character handling
                    228: **     ------------------
                    229: */
                    230: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
                    231: {
                    232:     return HTBufferWriter_write(me, &c, 1);
                    233: }
                    234: 
                    235: /*     String handling
                    236: **     ---------------
                    237: **
                    238: **     Strings must be smaller than this buffer size.
                    239: */
                    240: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
                    241: {
                    242:     return HTBufferWriter_write(me, s, (int) strlen(s));
                    243: }
                    244: /*
                    245: **     The difference between the close and the free method is that we don't
                    246: **     close the connection in the free method - we only call the free method
                    247: **     of the target stream. That way, we can keep the output stream as long 
                    248: **     as the channel itself.
                    249: */
                    250: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
                    251: {
                    252:     if (me) {
                    253:        if (me->target) (*me->target->isa->close)(me->target);
                    254:        HT_FREE(me->data);
                    255:        HT_FREE(me);
                    256:     }
                    257:     return HT_OK;
                    258: }
                    259: 
                    260: PRIVATE const HTOutputStreamClass HTBufferWriter =
                    261: {              
2.6       frystyk   262:     "BufferedSocketWriter",
                    263:     HTBufferWriter_lazyFlush,
2.1       frystyk   264:     HTBufferWriter_free,
                    265:     HTBufferWriter_abort,
                    266:     HTBufferWriter_put_character,
                    267:     HTBufferWriter_put_string,
                    268:     HTBufferWriter_write,
                    269:     HTBufferWriter_close
                    270: }; 
                    271: 
2.6       frystyk   272: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1       frystyk   273:                                            void * param, int bufsize)
                    274: {
2.6       frystyk   275:     if (host && ch) {
2.1       frystyk   276:        HTOutputStream * me = HTChannel_output(ch);
2.6       frystyk   277:        if (!me) {
                    278:            HTOutputStream * me;
2.1       frystyk   279:            if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.6       frystyk   280:            if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1       frystyk   281:                (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
                    282:                HT_OUTOFMEM("HTBufferWriter_new");
                    283:            me->isa = &HTBufferWriter;
                    284:            me->read = me->data;
2.15    ! frystyk   285:            me->allocated = bufsize;
        !           286:             me->growby = bufsize;
2.6       frystyk   287:            me->target = HTWriter_new(host, ch, param, 0);
                    288:            me->host = host;
2.15    ! frystyk   289:            return me;
2.6       frystyk   290:        }
2.1       frystyk   291:     }
                    292:     return NULL;
                    293: }

Webmaster