Annotation of libwww/Library/src/HTWriter.c, revision 2.56

2.11      frystyk     1: /*                                                                   HTWrite.c
2.24      frystyk     2: **     FILE WRITER BASED ON A SOCKET
2.1       timbl       3: **
2.15      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.11      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.56    ! kahan       6: **     @(#) $Id: HTWriter.c,v 2.55 1999/04/04 00:13:21 frystyk Exp $
2.14      frystyk     7: **
                      8: **     This is a try with a non-buffered output stream which remembers
                      9: **     state using the write_pointer. As normally we have a big buffer
                     10: **     somewhere else in the stream chain an extra output buffer will often
2.34      frystyk    11: **     not be needed.
2.1       timbl      12: */
2.11      frystyk    13: 
2.13      frystyk    14: /* Library include files */
2.49      frystyk    15: #include "wwwsys.h"
2.33      frystyk    16: #include "WWWUtil.h"
2.34      frystyk    17: #include "WWWCore.h"
2.41      frystyk    18: #include "HTNet.h"
2.18      frystyk    19: #include "HTNetMan.h"
2.14      frystyk    20: #include "HTWriter.h"                                   /* Implemented here */
2.1       timbl      21: 
2.50      frystyk    22: #include "HTHstMan.h"
                     23: 
2.1       timbl      24: struct _HTStream {
2.33      frystyk    25:     const HTStreamClass *      isa;
                     26:     /* ... */
                     27: };
                     28: 
                     29: struct _HTOutputStream {
                     30:     const HTOutputStreamClass *        isa;
                     31:     HTChannel *                        ch;
2.41      frystyk    32:     HTHost *                   host;
2.48      frystyk    33:     int                                offset;
2.1       timbl      34: #ifdef NOT_ASCII
2.33      frystyk    35:     char *                     ascbuf;     /* Buffer for TOASCII conversion */
2.1       timbl      36: #endif
                     37: };
                     38: 
2.14      frystyk    39: /* ------------------------------------------------------------------------- */
2.1       timbl      40: 
2.33      frystyk    41: PRIVATE int HTWriter_flush (HTOutputStream * me)
                     42: {
                     43:     return HT_OK;                     /* As we don't have any output buffer */
                     44: }
                     45: 
                     46: PRIVATE int HTWriter_free (HTOutputStream * me)
                     47: {
                     48:     return HT_OK;
                     49: }
                     50: 
                     51: PRIVATE int HTWriter_abort (HTOutputStream * me, HTList * e)
                     52: {
                     53:     return HT_ERROR;
                     54: }
                     55: 
2.14      frystyk    56: /*     Write to the socket
                     57: **
                     58: ** According to Solaris 2.3 man on write:
                     59: **
                     60: **    o        If O_NONBLOCK and O_NDELAY are clear, write() blocks
                     61: **     until the data can be accepted.
                     62: **
                     63: **    o        If O_NONBLOCK or O_NDELAY is set, write()  does  not
                     64: **     block  the  process.   If  some  data  can be written
                     65: **     without blocking the process, write() writes what  it
                     66: **     can  and returns the number of bytes written.  Other-
                     67: **     wise, if O_NONBLOCK is set, it returns - 1  and  sets
                     68: **     errno to EAGAIN or if O_NDELAY is set, it returns 0.
                     69: **
                     70: ** According to SunOS 4.1.1 man on write:
                     71: **
                     72: **   + If the descriptor is  marked  for  non-blocking  I/O
                     73: **     using  fcntl()  to  set  the FNONBLOCK or O_NONBLOCK
                     74: **     flag (defined in  <sys/fcntl.h>),  write()  requests
                     75: **     for  {PIPE_BUF}  (see  pathconf(2V))  or fewer bytes
                     76: **     either  succeed  completely  and  return  nbyte,  or
                     77: **     return -1 and set errno to EAGAIN. A write() request
                     78: **     for greater than {PIPE_BUF} bytes  either  transfers
                     79: **     what it can and returns the number of bytes written,
                     80: **     or transfers no data and returns -1 and  sets  errno
                     81: **     to  EAGAIN.  If  a  write()  request is greater than
                     82: **     {PIPE_BUF} bytes and all data previously written  to
                     83: **     the  pipe  has been read, write() transfers at least
                     84: **     {PIPE_BUF} bytes.
                     85: */
2.33      frystyk    86: PRIVATE int HTWriter_write (HTOutputStream * me, const char * buf, int len)
2.14      frystyk    87: {
2.41      frystyk    88:     HTHost * host = me->host;
                     89:     SOCKET soc = HTChannel_socket(HTHost_channel(host));
                     90:     HTNet * net = HTHost_getWriteNet(host);
2.14      frystyk    91:     int b_write;
2.48      frystyk    92:     char * wrtp;
2.31      frystyk    93:     const char *limit = buf+len;
2.1       timbl      94: 
2.50      frystyk    95:     /* If we don't have a Net object then return right away */
                     96:     if (!net) {
2.55      frystyk    97:        HTTRACE(STREAM_TRACE, "Write Socket No Net object %d (offset %d)\n" _ soc _ me->offset);
2.50      frystyk    98:        return HT_ERROR;
                     99:     }
                    100: 
2.9       frystyk   101: #ifdef NOT_ASCII
2.34      frystyk   102:     if (len && !me->ascbuf) {                        /* Generate new buffer */
                    103:        const char *orig = buf;
2.14      frystyk   104:        char *dest;
                    105:        int cnt;
2.29      frystyk   106:        if ((me->ascbuf = (char  *) HT_MALLOC(len)) == NULL)
2.34      frystyk   107:            HT_OUTOFMEM("HTWriter_write");
2.14      frystyk   108:        dest = me->ascbuf;
2.20      frystyk   109:        for (cnt=0; cnt<len; cnt++) {
                    110:            *dest = TOASCII(*orig);
                    111:            dest++, orig++;
                    112:        }
2.48      frystyk   113:        wrtp = me->ascbuf;
2.14      frystyk   114:        limit = me->ascbuf+len;
2.1       timbl     115:     }
2.14      frystyk   116: #else
2.48      frystyk   117:     if (!me->offset)
                    118:        wrtp = (char *) buf;
                    119:     else {
                    120:        wrtp = (char *) buf + me->offset;
                    121:        len -= me->offset;
                    122:        me->offset = 0;
                    123:     }
2.14      frystyk   124: #endif
                    125: 
                    126:     /* Write data to the network */
2.48      frystyk   127:     while (wrtp < limit) {
                    128:        if ((b_write = NETWRITE(soc, wrtp, len)) < 0) {
2.14      frystyk   129: #ifdef EAGAIN
2.19      frystyk   130:            if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
2.14      frystyk   131: #else
2.19      frystyk   132:            if (socerrno == EWOULDBLOCK)                              /* BSD */
2.1       timbl     133: #endif
2.14      frystyk   134:            {
2.48      frystyk   135:                HTHost_register(host, net, HTEvent_WRITE);
                    136:                me->offset = wrtp - buf;
2.54      frystyk   137:                HTTRACE(STREAM_TRACE, "Write Socket WOULD BLOCK %d (offset %d)\n" _ soc _ me->offset);
2.14      frystyk   138:                return HT_WOULD_BLOCK;
2.39      frystyk   139: #ifdef EINTR
2.37      frystyk   140:            } else if (socerrno == EINTR) {
                    141:                /*
                    142:                **      EINTR   A signal was caught during the  write  opera-
                    143:                **              tion and no data was transferred.
                    144:                */
2.56    ! kahan     145:                HTTRACE(STREAM_TRACE, "Write Socket call interrupted - try again\n");
2.37      frystyk   146:                continue;
2.39      frystyk   147: #endif
2.14      frystyk   148:            } else {
2.56    ! kahan     149:                host->broken_pipe = YES;
2.43      frystyk   150: #ifdef EPIPE
2.56    ! kahan     151:                if (socerrno == EPIPE) {
        !           152:                    /* JK: an experimental bug solution proposed by
        !           153:                        Olga and Mikhael */
2.54      frystyk   154:                    HTTRACE(STREAM_TRACE, "Write Socket got EPIPE\n");
2.56    ! kahan     155:                    HTHost_unregister(host, net, HTEvent_WRITE);
        !           156:                    HTHost_register(host, net, HTEvent_CLOSE);
        !           157:                    /* @@ JK: seems that some functions check the errors 
        !           158:                       as part of the flow control */
        !           159:                     HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
        !           160:                                             "NETWRITE");
        !           161:                    return HT_CLOSED;               
        !           162:                }
2.43      frystyk   163: #endif /* EPIPE */
2.56    ! kahan     164:                /* all errors that aren't EPIPE */
2.33      frystyk   165:                HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
2.28      frystyk   166:                                         "NETWRITE");
2.14      frystyk   167:                return HT_ERROR;
                    168:            }
2.1       timbl     169:        }
2.47      frystyk   170: 
2.41      frystyk   171:        /* We do this unconditionally, should we check to see if we ever blocked? */
2.54      frystyk   172:        HTTRACEDATA(wrtp, b_write, "Writing to socket %d" _ soc);
2.51      frystyk   173:        HTNet_addBytesWritten(net, b_write);
2.48      frystyk   174:        wrtp += b_write;
2.14      frystyk   175:        len -= b_write;
2.54      frystyk   176:        HTTRACE(STREAM_TRACE, "Write Socket %d bytes written to %d\n" _ b_write _ soc);
2.28      frystyk   177:        {
2.52      frystyk   178:            HTAlertCallback *cbf = HTAlert_find(HT_PROG_WRITE);
2.53      frystyk   179:            if (cbf) {
                    180:                int tw = HTNet_bytesWritten(net);
                    181:                (*cbf)(net->request, HT_PROG_WRITE,
                    182:                       HT_MSG_NULL, NULL, &tw, NULL);
                    183:            }
2.28      frystyk   184:        }
2.1       timbl     185:     }
2.14      frystyk   186: #ifdef NOT_ASCII
2.29      frystyk   187:     HT_FREE(me->ascbuf);
2.14      frystyk   188: #endif
                    189:     return HT_OK;
2.1       timbl     190: }
                    191: 
                    192: /*     Character handling
                    193: **     ------------------
                    194: */
2.33      frystyk   195: PRIVATE int HTWriter_put_character (HTOutputStream * me, char c)
2.1       timbl     196: {
2.14      frystyk   197:     return HTWriter_write(me, &c, 1);
2.1       timbl     198: }
                    199: 
                    200: /*     String handling
                    201: **     ---------------
                    202: **
                    203: **     Strings must be smaller than this buffer size.
                    204: */
2.33      frystyk   205: PRIVATE int HTWriter_put_string (HTOutputStream * me, const char * s)
2.1       timbl     206: {
2.14      frystyk   207:     return HTWriter_write(me, s, (int) strlen(s));
2.1       timbl     208: }
2.33      frystyk   209: /*
                    210: **     The difference between the close and the free method is that we don't
                    211: **     close the connection in the free method - we only call the free method
                    212: **     of the target stream. That way, we can keep the output stream as long 
                    213: **     as the channel itself.
                    214: */
                    215: PRIVATE int HTWriter_close (HTOutputStream * me)
2.1       timbl     216: {
2.54      frystyk   217:     HTTRACE(STREAM_TRACE, "Socket write FREEING....\n");
2.29      frystyk   218:     HT_FREE(me);
2.33      frystyk   219:     return HT_OK;
2.1       timbl     220: }
                    221: 
2.33      frystyk   222: PRIVATE const HTOutputStreamClass HTWriter =
2.1       timbl     223: {              
2.14      frystyk   224:     "SocketWriter",
                    225:     HTWriter_flush,
                    226:     HTWriter_free,
                    227:     HTWriter_abort,
                    228:     HTWriter_put_character,
                    229:     HTWriter_put_string,
2.33      frystyk   230:     HTWriter_write,
                    231:     HTWriter_close
2.1       timbl     232: }; 
                    233: 
2.41      frystyk   234: PUBLIC HTOutputStream * HTWriter_new (HTHost * host, HTChannel * ch,
2.33      frystyk   235:                                      void * param, int mode)
2.1       timbl     236: {
2.41      frystyk   237:     if (host && ch) {
2.33      frystyk   238:        HTOutputStream * me = HTChannel_output(ch);
2.41      frystyk   239:        if (!me) {
2.33      frystyk   240:            if ((me=(HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL)
                    241:                HT_OUTOFMEM("HTWriter_new");
                    242:            me->isa = &HTWriter;
                    243:            me->ch = ch;
2.41      frystyk   244:            me->host = host;
2.33      frystyk   245:        }
2.48      frystyk   246:        return me;
2.33      frystyk   247:     }
                    248:     return NULL;
2.21      frystyk   249: }

Webmaster