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

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.47    ! frystyk     6: **     @(#) $Id: HTWriter.c,v 2.46 1997/03/21 19:33:27 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.31      frystyk    15: #include "sysdep.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: 
                     22: struct _HTStream {
2.33      frystyk    23:     const HTStreamClass *      isa;
                     24:     /* ... */
                     25: };
                     26: 
                     27: struct _HTOutputStream {
                     28:     const HTOutputStreamClass *        isa;
                     29:     HTChannel *                        ch;
2.41      frystyk    30:     HTHost *                   host;
2.33      frystyk    31:     char *                     write;
2.1       timbl      32: #ifdef NOT_ASCII
2.33      frystyk    33:     char *                     ascbuf;     /* Buffer for TOASCII conversion */
2.1       timbl      34: #endif
                     35: };
                     36: 
2.14      frystyk    37: /* ------------------------------------------------------------------------- */
2.1       timbl      38: 
2.33      frystyk    39: PRIVATE int HTWriter_flush (HTOutputStream * me)
                     40: {
                     41:     return HT_OK;                     /* As we don't have any output buffer */
                     42: }
                     43: 
                     44: PRIVATE int HTWriter_free (HTOutputStream * me)
                     45: {
                     46:     return HT_OK;
                     47: }
                     48: 
                     49: PRIVATE int HTWriter_abort (HTOutputStream * me, HTList * e)
                     50: {
                     51:     return HT_ERROR;
                     52: }
                     53: 
2.14      frystyk    54: /*     Write to the socket
                     55: **
                     56: ** According to Solaris 2.3 man on write:
                     57: **
                     58: **    o        If O_NONBLOCK and O_NDELAY are clear, write() blocks
                     59: **     until the data can be accepted.
                     60: **
                     61: **    o        If O_NONBLOCK or O_NDELAY is set, write()  does  not
                     62: **     block  the  process.   If  some  data  can be written
                     63: **     without blocking the process, write() writes what  it
                     64: **     can  and returns the number of bytes written.  Other-
                     65: **     wise, if O_NONBLOCK is set, it returns - 1  and  sets
                     66: **     errno to EAGAIN or if O_NDELAY is set, it returns 0.
                     67: **
                     68: ** According to SunOS 4.1.1 man on write:
                     69: **
                     70: **   + If the descriptor is  marked  for  non-blocking  I/O
                     71: **     using  fcntl()  to  set  the FNONBLOCK or O_NONBLOCK
                     72: **     flag (defined in  <sys/fcntl.h>),  write()  requests
                     73: **     for  {PIPE_BUF}  (see  pathconf(2V))  or fewer bytes
                     74: **     either  succeed  completely  and  return  nbyte,  or
                     75: **     return -1 and set errno to EAGAIN. A write() request
                     76: **     for greater than {PIPE_BUF} bytes  either  transfers
                     77: **     what it can and returns the number of bytes written,
                     78: **     or transfers no data and returns -1 and  sets  errno
                     79: **     to  EAGAIN.  If  a  write()  request is greater than
                     80: **     {PIPE_BUF} bytes and all data previously written  to
                     81: **     the  pipe  has been read, write() transfers at least
                     82: **     {PIPE_BUF} bytes.
                     83: */
2.33      frystyk    84: PRIVATE int HTWriter_write (HTOutputStream * me, const char * buf, int len)
2.14      frystyk    85: {
2.41      frystyk    86:     HTHost * host = me->host;
                     87:     SOCKET soc = HTChannel_socket(HTHost_channel(host));
                     88:     HTNet * net = HTHost_getWriteNet(host);
2.14      frystyk    89:     int b_write;
2.31      frystyk    90:     const char *limit = buf+len;
2.1       timbl      91: 
2.9       frystyk    92: #ifdef NOT_ASCII
2.34      frystyk    93:     if (len && !me->ascbuf) {                        /* Generate new buffer */
                     94:        const char *orig = buf;
2.14      frystyk    95:        char *dest;
                     96:        int cnt;
2.29      frystyk    97:        if ((me->ascbuf = (char  *) HT_MALLOC(len)) == NULL)
2.34      frystyk    98:            HT_OUTOFMEM("HTWriter_write");
2.14      frystyk    99:        dest = me->ascbuf;
2.20      frystyk   100:        for (cnt=0; cnt<len; cnt++) {
                    101:            *dest = TOASCII(*orig);
                    102:            dest++, orig++;
                    103:        }
2.33      frystyk   104:        me->write = me->ascbuf;
2.14      frystyk   105:        limit = me->ascbuf+len;
2.1       timbl     106:     }
2.14      frystyk   107: #else
2.47    ! frystyk   108:     me->write = (char *) buf;
2.14      frystyk   109: #endif
                    110: 
                    111:     /* Write data to the network */
2.33      frystyk   112:     while (me->write < limit) {
2.47    ! frystyk   113:         b_write = NETWRITE(soc, me->write, len);
        !           114:         if (b_write < 0) {
        !           115: 
2.14      frystyk   116: #ifdef EAGAIN
2.19      frystyk   117:            if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
2.14      frystyk   118: #else
2.19      frystyk   119:            if (socerrno == EWOULDBLOCK)                              /* BSD */
2.1       timbl     120: #endif
2.14      frystyk   121:            {
                    122:                if (PROT_TRACE)
2.33      frystyk   123:                    HTTrace("Write Socket WOULD BLOCK %d\n",soc);
2.41      frystyk   124:                HTHost_register(host, net, HTEvent_WRITE);
2.14      frystyk   125:                return HT_WOULD_BLOCK;
2.39      frystyk   126: #ifdef EINTR
2.37      frystyk   127:            } else if (socerrno == EINTR) {
                    128:                /*
                    129:                **      EINTR   A signal was caught during the  write  opera-
                    130:                **              tion and no data was transferred.
                    131:                */
                    132:                if (PROT_TRACE)
                    133:                    HTTrace("Write Socket call interruted - try again\n");
                    134:                continue;
2.39      frystyk   135: #endif
2.14      frystyk   136:            } else {
2.43      frystyk   137: #ifdef EPIPE
                    138:                if (socerrno == EPIPE)
2.44      frystyk   139:                    if (PROT_TRACE) HTTrace("Write Socket got EPIPE\n");
2.43      frystyk   140: #endif /* EPIPE */
2.33      frystyk   141:                HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
2.28      frystyk   142:                                         "NETWRITE");
2.14      frystyk   143:                return HT_ERROR;
                    144:            }
2.1       timbl     145:        }
2.47    ! frystyk   146: 
2.41      frystyk   147:        /* We do this unconditionally, should we check to see if we ever blocked? */
2.45      frystyk   148:        HTTraceData(me->write, b_write, "HTWriter.... Writing");
2.47    ! frystyk   149:         me->write += b_write;
2.14      frystyk   150:        len -= b_write;
                    151:        if (PROT_TRACE)
2.30      eric      152:            HTTrace("Write Socket %d bytes written to socket %d\n",
2.33      frystyk   153:                    b_write, soc);
2.28      frystyk   154:        {
                    155:            HTAlertCallback *cbf = HTAlert_find(HT_PROG_READ);
2.33      frystyk   156:            if (cbf) (*cbf)(net->request, HT_PROG_WRITE,
                    157:                            HT_MSG_NULL, NULL, NULL, NULL);
2.28      frystyk   158:        }
2.1       timbl     159:     }
2.14      frystyk   160: #ifdef NOT_ASCII
2.29      frystyk   161:     HT_FREE(me->ascbuf);
2.14      frystyk   162: #endif
                    163:     return HT_OK;
2.1       timbl     164: }
                    165: 
                    166: /*     Character handling
                    167: **     ------------------
                    168: */
2.33      frystyk   169: PRIVATE int HTWriter_put_character (HTOutputStream * me, char c)
2.1       timbl     170: {
2.14      frystyk   171:     return HTWriter_write(me, &c, 1);
2.1       timbl     172: }
                    173: 
                    174: /*     String handling
                    175: **     ---------------
                    176: **
                    177: **     Strings must be smaller than this buffer size.
                    178: */
2.33      frystyk   179: PRIVATE int HTWriter_put_string (HTOutputStream * me, const char * s)
2.1       timbl     180: {
2.14      frystyk   181:     return HTWriter_write(me, s, (int) strlen(s));
2.1       timbl     182: }
2.33      frystyk   183: /*
                    184: **     The difference between the close and the free method is that we don't
                    185: **     close the connection in the free method - we only call the free method
                    186: **     of the target stream. That way, we can keep the output stream as long 
                    187: **     as the channel itself.
                    188: */
                    189: PRIVATE int HTWriter_close (HTOutputStream * me)
2.1       timbl     190: {
2.33      frystyk   191:     if (PROT_TRACE) HTTrace("Socket write FREEING....\n");
2.29      frystyk   192:     HT_FREE(me);
2.33      frystyk   193:     return HT_OK;
2.1       timbl     194: }
                    195: 
2.33      frystyk   196: PRIVATE const HTOutputStreamClass HTWriter =
2.1       timbl     197: {              
2.14      frystyk   198:     "SocketWriter",
                    199:     HTWriter_flush,
                    200:     HTWriter_free,
                    201:     HTWriter_abort,
                    202:     HTWriter_put_character,
                    203:     HTWriter_put_string,
2.33      frystyk   204:     HTWriter_write,
                    205:     HTWriter_close
2.1       timbl     206: }; 
                    207: 
2.41      frystyk   208: PUBLIC HTOutputStream * HTWriter_new (HTHost * host, HTChannel * ch,
2.33      frystyk   209:                                      void * param, int mode)
2.1       timbl     210: {
2.41      frystyk   211:     if (host && ch) {
2.33      frystyk   212:        HTOutputStream * me = HTChannel_output(ch);
2.41      frystyk   213:        if (!me) {
2.33      frystyk   214:            if ((me=(HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL)
                    215:                HT_OUTOFMEM("HTWriter_new");
                    216:            me->isa = &HTWriter;
                    217:            me->ch = ch;
2.41      frystyk   218:            me->host = host;
2.33      frystyk   219:        }
2.47    ! frystyk   220:         return me;
2.33      frystyk   221:     }
                    222:     return NULL;
2.21      frystyk   223: }

Webmaster