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

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.51    ! frystyk     6: **     @(#) $Id: HTWriter.c,v 2.50 1998/05/19 16:49:46 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) {
                     97:        if (STREAM_TRACE)
                     98:            HTTrace("Write Socket WOULD BLOCK %d (offset %d)\n",soc, me->offset);
                     99:        return HT_ERROR;
                    100:     }
                    101: 
2.9       frystyk   102: #ifdef NOT_ASCII
2.34      frystyk   103:     if (len && !me->ascbuf) {                        /* Generate new buffer */
                    104:        const char *orig = buf;
2.14      frystyk   105:        char *dest;
                    106:        int cnt;
2.29      frystyk   107:        if ((me->ascbuf = (char  *) HT_MALLOC(len)) == NULL)
2.34      frystyk   108:            HT_OUTOFMEM("HTWriter_write");
2.14      frystyk   109:        dest = me->ascbuf;
2.20      frystyk   110:        for (cnt=0; cnt<len; cnt++) {
                    111:            *dest = TOASCII(*orig);
                    112:            dest++, orig++;
                    113:        }
2.48      frystyk   114:        wrtp = me->ascbuf;
2.14      frystyk   115:        limit = me->ascbuf+len;
2.1       timbl     116:     }
2.14      frystyk   117: #else
2.48      frystyk   118:     if (!me->offset)
                    119:        wrtp = (char *) buf;
                    120:     else {
                    121:        wrtp = (char *) buf + me->offset;
                    122:        len -= me->offset;
                    123:        me->offset = 0;
                    124:     }
2.14      frystyk   125: #endif
                    126: 
                    127:     /* Write data to the network */
2.48      frystyk   128:     while (wrtp < limit) {
                    129:        if ((b_write = NETWRITE(soc, wrtp, len)) < 0) {
2.14      frystyk   130: #ifdef EAGAIN
2.19      frystyk   131:            if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
2.14      frystyk   132: #else
2.19      frystyk   133:            if (socerrno == EWOULDBLOCK)                              /* BSD */
2.1       timbl     134: #endif
2.14      frystyk   135:            {
2.48      frystyk   136:                HTHost_register(host, net, HTEvent_WRITE);
                    137:                me->offset = wrtp - buf;
2.50      frystyk   138:                if (STREAM_TRACE)
2.48      frystyk   139:                    HTTrace("Write Socket WOULD BLOCK %d (offset %d)\n",soc, me->offset);
2.14      frystyk   140:                return HT_WOULD_BLOCK;
2.39      frystyk   141: #ifdef EINTR
2.37      frystyk   142:            } else if (socerrno == EINTR) {
                    143:                /*
                    144:                **      EINTR   A signal was caught during the  write  opera-
                    145:                **              tion and no data was transferred.
                    146:                */
2.50      frystyk   147:                if (STREAM_TRACE)
2.37      frystyk   148:                    HTTrace("Write Socket call interruted - try again\n");
                    149:                continue;
2.39      frystyk   150: #endif
2.14      frystyk   151:            } else {
2.43      frystyk   152: #ifdef EPIPE
                    153:                if (socerrno == EPIPE)
2.50      frystyk   154:                    if (STREAM_TRACE) HTTrace("Write Socket got EPIPE\n");
2.43      frystyk   155: #endif /* EPIPE */
2.50      frystyk   156:                host->broken_pipe = YES;
2.33      frystyk   157:                HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
2.28      frystyk   158:                                         "NETWRITE");
2.14      frystyk   159:                return HT_ERROR;
                    160:            }
2.1       timbl     161:        }
2.47      frystyk   162: 
2.41      frystyk   163:        /* We do this unconditionally, should we check to see if we ever blocked? */
2.50      frystyk   164:        HTTraceData(wrtp, b_write, "Writing to socket %d", soc);
2.51    ! frystyk   165:        HTNet_addBytesWritten(net, b_write);
2.48      frystyk   166:        wrtp += b_write;
2.14      frystyk   167:        len -= b_write;
2.50      frystyk   168:        if (STREAM_TRACE) HTTrace("Write Socket %d bytes written to %d\n", b_write, soc);
2.28      frystyk   169:        {
                    170:            HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
2.33      frystyk   171:            if (cbf) (*cbf)(net->request, HT_PROG_WRITE,
                    172:                            HT_MSG_NULL, NULL, NULL, NULL);
2.28      frystyk   173:        }
2.1       timbl     174:     }
2.14      frystyk   175: #ifdef NOT_ASCII
2.29      frystyk   176:     HT_FREE(me->ascbuf);
2.14      frystyk   177: #endif
                    178:     return HT_OK;
2.1       timbl     179: }
                    180: 
                    181: /*     Character handling
                    182: **     ------------------
                    183: */
2.33      frystyk   184: PRIVATE int HTWriter_put_character (HTOutputStream * me, char c)
2.1       timbl     185: {
2.14      frystyk   186:     return HTWriter_write(me, &c, 1);
2.1       timbl     187: }
                    188: 
                    189: /*     String handling
                    190: **     ---------------
                    191: **
                    192: **     Strings must be smaller than this buffer size.
                    193: */
2.33      frystyk   194: PRIVATE int HTWriter_put_string (HTOutputStream * me, const char * s)
2.1       timbl     195: {
2.14      frystyk   196:     return HTWriter_write(me, s, (int) strlen(s));
2.1       timbl     197: }
2.33      frystyk   198: /*
                    199: **     The difference between the close and the free method is that we don't
                    200: **     close the connection in the free method - we only call the free method
                    201: **     of the target stream. That way, we can keep the output stream as long 
                    202: **     as the channel itself.
                    203: */
                    204: PRIVATE int HTWriter_close (HTOutputStream * me)
2.1       timbl     205: {
2.50      frystyk   206:     if (STREAM_TRACE) HTTrace("Socket write FREEING....\n");
2.29      frystyk   207:     HT_FREE(me);
2.33      frystyk   208:     return HT_OK;
2.1       timbl     209: }
                    210: 
2.33      frystyk   211: PRIVATE const HTOutputStreamClass HTWriter =
2.1       timbl     212: {              
2.14      frystyk   213:     "SocketWriter",
                    214:     HTWriter_flush,
                    215:     HTWriter_free,
                    216:     HTWriter_abort,
                    217:     HTWriter_put_character,
                    218:     HTWriter_put_string,
2.33      frystyk   219:     HTWriter_write,
                    220:     HTWriter_close
2.1       timbl     221: }; 
                    222: 
2.41      frystyk   223: PUBLIC HTOutputStream * HTWriter_new (HTHost * host, HTChannel * ch,
2.33      frystyk   224:                                      void * param, int mode)
2.1       timbl     225: {
2.41      frystyk   226:     if (host && ch) {
2.33      frystyk   227:        HTOutputStream * me = HTChannel_output(ch);
2.41      frystyk   228:        if (!me) {
2.33      frystyk   229:            if ((me=(HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL)
                    230:                HT_OUTOFMEM("HTWriter_new");
                    231:            me->isa = &HTWriter;
                    232:            me->ch = ch;
2.41      frystyk   233:            me->host = host;
2.33      frystyk   234:        }
2.48      frystyk   235:        return me;
2.33      frystyk   236:     }
                    237:     return NULL;
2.21      frystyk   238: }

Webmaster