dgaudet     99/06/18 16:35:01

  Modified:    mpm/src  CHANGES
               mpm/src/include buff.h
               mpm/src/main Makefile.tmpl buff.c http_connection.c
                        http_protocol.c http_request.c
  Added:       mpm/src/docs buff.txt
               mpm/src/include ap_iol.h
               mpm/src/main iol_unix.c
  Log:
  I'm sure this is wrong... but it's my start.  i/o layering.  Lots of stuff
  disabled/still to be implemented.  This served up a few static requests.
  
  Revision  Changes    Path
  1.3       +7 -0      apache-2.0/mpm/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/CHANGES,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CHANGES   1999/06/18 18:58:45     1.2
  +++ CHANGES   1999/06/18 23:34:56     1.3
  @@ -0,0 +1,7 @@
  +Changes with MPM
  +
  +    * I/O layering and BUFF revamp.  See docs/buff.txt. [Dean Gaudet]
  +
  +    * Basic restructuring to introduce the MPM concept; includes various
  +      changes to the module API... better described by
  +      docs/initial_blurb.txt.  [Dean Gaudet]
  
  
  
  1.1                  apache-2.0/mpm/src/docs/buff.txt
  
  Index: buff.txt
  ===================================================================
  - ap_bungetc added
  - ap_blookc changed to return the character, rather than take a char *buff
  - in theory, errno is always useful on return from a BUFF routine
  - ap_bhalfduplex, B_SAFEREAD will be re-implemented using a layer I think
  - chunking gone for now, will return as a layer
  - ebcdic gone for now... it should be a layer
  
  
  
  1.3       +15 -15    apache-2.0/mpm/src/include/buff.h
  
  Index: buff.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/include/buff.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- buff.h    1999/06/18 19:20:47     1.2
  +++ buff.h    1999/06/18 23:34:58     1.3
  @@ -63,6 +63,7 @@
   #endif
   
   #include <stdarg.h>
  +#include "ap_iol.h"
   
   /* Reading is buffered */
   #define B_RD     (1)
  @@ -83,16 +84,22 @@
   #define B_ERROR (48)
   /* TODO: implement chunked encoding as a layer */
   /* bflush() if a read would block */
  -#define B_SAFEREAD (128)
  +/* TODO: #define B_SAFEREAD (128) */
   /* buffer is a socket */
   #define B_SOCKET (256)
   
  +/* caller expects non-blocking behaviour */
  +#define B_NONBLOCK (512)
  +/* non-blocking bit set on fd */
  +#define B_NONBLOCK_SET (1024)
  +
   /* TODO: implement a ebcdic/ascii conversion layers */
   
   typedef struct buff_struct BUFF;
   
   struct buff_struct {
       int flags;                       /* flags */
  +    int saved_errno;         /* saved errno */
       unsigned char *inptr;    /* pointer to next location to read */
       int incnt;                       /* number of bytes left to read from 
input buffer;
                                 * always 0 if had a read error  */
  @@ -106,14 +113,13 @@
   
       ap_pool *pool;
   
  -/* could also put pointers to the basic I/O routines here */
  -    int fd;                  /* the file descriptor */
  -    time_t timeout;          /* timeout for B_SOCKET operations */
  +    ap_iol iol;
   };
   
   /* Options to bset/getopt */
   #define BO_BYTECT (1)
   #define BO_TIMEOUT (2)
  +#define BO_ERROR (3)
   
   /* Stream creation and modification */
   API_EXPORT(BUFF *) ap_bcreate(pool *p, int flags);
  @@ -136,8 +142,7 @@
   /* I/O */
   API_EXPORT(int) ap_bread(BUFF *fb, void *buf, int nbyte);
   API_EXPORT(int) ap_bgets(char *s, int n, BUFF *fb);
  -API_EXPORT(int) ap_blookc(char *buff, BUFF *fb);
  -API_EXPORT(int) ap_bskiplf(BUFF *fb);
  +API_EXPORT(int) ap_blookc(BUFF *fb);
   API_EXPORT(int) ap_bwrite(BUFF *fb, const void *buf, int nbyte);
   API_EXPORT(int) ap_bflush(BUFF *fb);
   API_EXPORT(int) ap_bputs(const char *x, BUFF *fb);
  @@ -153,6 +158,10 @@
   #define ap_bgetc(fb)   ( ((fb)->incnt == 0) ? ap_bfilbuf(fb) : \
                    ((fb)->incnt--, *((fb)->inptr++)) )
   
  +/* can only unput a single character that was read by ap_bgetc */
  +#define ap_bungetc(c, fb)  ((fb)->incnt++, *(--(fb)->inptr) = (c))
  +                     
  +
   #define ap_bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \
                     (fb)->outcnt == (fb)->bufsiz) ? ap_bflsbuf(c, (fb)) : \
                     ((fb)->outbase[(fb)->outcnt++] = (c), 0))
  @@ -181,15 +190,6 @@
   API_EXPORT(int) ap_bspawn_child(pool *, int (*)(void *, child_info *), void 
*,
                                        enum kill_conditions, BUFF **pipe_in, 
BUFF **pipe_out,
                                        BUFF **pipe_err);
  -
  -/* enable non-blocking operations */
  -API_EXPORT(int) ap_bnonblock(int fd);
  -API_EXPORT(int) ap_bblock(int fd);
  -/* and get an fd to select() on */
  -API_EXPORT(int) ap_bfileno(BUFF *fb, int direction);
  -
  -/* bflush() if a read now would block, but don't actually read anything */
  -API_EXPORT(void) ap_bhalfduplex(BUFF *fb);
   
   #ifdef __cplusplus
   }
  
  
  
  1.1                  apache-2.0/mpm/src/include/ap_iol.h
  
  Index: ap_iol.h
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  /* i/o layering support */
  
  #ifndef AP_IOL_H
  #define AP_IOL_H
  
  typedef struct ap_iol ap_iol;
  typedef struct ap_iol_methods ap_iol_methods;
  
  typedef enum {
      AP_IOL_TIMEOUT
  } ap_iol_option;
  
  /*
      write, writev, read, readv guarantee they won't return EINTR.
  
      If no error occurs, they return the number of bytes read/written.
  
      If timeout is negative, they may block forever, and they still don't
      guarantee they'll write/read the full length.
      
      If timeout is 0, they will never block, and will return -1 and
      EWOULDBLOCK in the event that they can't read/write any bytes.
  
      If the timeout is positive, they will block up to the specified number
      of seconds.  If the read/write can't be completed in that time,
      a -1 will be returned and errno will be set to ETIME.
  
      TODO: we've all agreed errno is somewhat evil, and it must be replaced
      by a status result code.  I'll leave that to someone else.
  
      Just to drive the point home again -- none of these functions guarantee
      they will read/write the entire length specified.
  
      Note:  timeout == 0 is non-blocking operation... which requires a lot
      of care if you're implementing filters.  It may mean you have to keep
      state from one call to the next.  The chunking filter will have an
      example of this.  If you're not sure how to handle the state sitatuation
      you will want to return EINVAL when the timeout is set to 0.  This may
      break various things... hopefully we'll be able to recover gracefully.
  */
  
  struct ap_iol_methods {
      int (*close)(ap_iol *fd);
      int (*write)(ap_iol *fd, const char *buf, int len);
      int (*writev)(ap_iol *fd, const struct iovec *vec, int nvec);
      int (*read)(ap_iol *fd, char *buf, int len);
      int (*readv)(ap_iol *fd, struct iovec *vec, int nvec);
      int (*setopt)(ap_iol *fd, ap_iol_option opt, const void *value);
      int (*getopt)(ap_iol *fd, ap_iol_option opt, void *value);
      /* TODO: accept, connect, ... */
  };
  
  struct ap_iol {
      void *iol_data;
      const ap_iol_methods *methods;
  };
  
  #define iol_close(iol)        ((iol)->methods->close((iol)))
  #define iol_write(iol, a, b) ((iol)->methods->write((iol), (a), (b)))
  #define iol_writev(iol, a, b) ((iol)->methods->writev((iol), (a), (b)))
  #define iol_read(iol, a, b) ((iol)->methods->read((iol), (a), (b)))
  #define iol_readv(iol, a, b) ((iol)->methods->readv((iol), (a), (b)))
  #define iol_setopt(iol, a, b) ((iol)->methods->setopt((iol), (a), (b)))
  #define iol_getopt(iol, a, b) ((iol)->methods->getopt((iol), (a), (b)))
  
  /* clean this up later as well */
  
  void unix_attach_fd(ap_iol *, int fd);
  
  #endif
  
  
  
  1.3       +1 -1      apache-2.0/mpm/src/main/Makefile.tmpl
  
  Index: Makefile.tmpl
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/main/Makefile.tmpl,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Makefile.tmpl     1999/06/18 19:08:01     1.2
  +++ Makefile.tmpl     1999/06/18 23:34:59     1.3
  @@ -11,7 +11,7 @@
         http_config.o http_core.o http_log.o \
         http_main.o http_protocol.o http_request.o http_vhost.o \
         util.o util_date.o util_script.o util_uri.o util_md5.o \
  -      rfc1413.o mpm_prefork.o http_connection.o
  +      rfc1413.o mpm_prefork.o http_connection.o iol_unix.o
   
   .c.o:
        $(CC) -c $(INCLUDES) $(CFLAGS) $<
  
  
  
  1.3       +86 -336   apache-2.0/mpm/src/main/buff.c
  
  Index: buff.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/main/buff.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- buff.c    1999/06/18 19:20:48     1.2
  +++ buff.c    1999/06/18 23:34:59     1.3
  @@ -113,77 +113,7 @@
    * futher I/O will be done
    */
   
  -static int sendwithtimeout(int sock, const char *buf, int len, time_t sec)
  -{
  -    fd_set fdset;
  -    struct timeval tv;
  -    int err = EAGAIN;
  -    int rv;
  -    
  -    if (sec == -1) {
  -        return (write(sock, buf, len));
  -    }
  -    ap_bnonblock(sock);
  -    rv = write(sock, buf, len);
  -
  -    if (rv == -1 && sec != 0) {
  -        err = errno;
  -     if (err == EAGAIN || errno == EINTR) {
  -         FD_ZERO(&fdset);
  -         FD_SET(sock, &fdset);
  -            tv.tv_sec = sec;
  -         tv.tv_usec = 0;
  -            do {
  -             rv = select(FD_SETSIZE, NULL, &fdset, NULL, &tv);
  -         } while (rv == -1 && errno == EINTR);
  -            if (rv == -1 || rv == 0) {
  -             err = errno;
  -         }
  -         else {
  -             rv = write(sock, buf, len);
  -         }
  -     }
  -    }
  -    ap_bblock(sock);
  -    return (rv);
  -}
   
  -static int recvwithtimeout(int sock, char *buf, int len, time_t sec)
  -{
  -    fd_set fdset;
  -    struct timeval tv;
  -    int err = EAGAIN;
  -    int rv;
  -
  -    if (sec == -1) {
  -     return (read(sock, buf, len));
  -    }
  -    ap_bnonblock(sock);
  -    rv = read(sock, buf, len);
  -    if (rv == -1 && sec != 0) {
  -     err = errno;
  -     if (err == EAGAIN || errno == EINTR) {
  -         FD_ZERO(&fdset);
  -         FD_SET(sock, &fdset);
  -            tv.tv_sec = sec;
  -         tv.tv_usec = 0;
  -         do {
  -                rv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
  -         } while (rv == -1 && errno == EINTR);
  -            if (rv == -1 || rv == 0) {
  -             err = errno;
  -         }
  -         else {
  -             rv = read(sock, buf, len);
  -             if (rv == -1)
  -                 err = errno;
  -         }
  -        }
  -    }
  -    ap_bblock(sock);
  -    return (rv);
  -}
  -
   static void doerror(BUFF *fb, int direction)
   {
       int errsave = errno;     /* Save errno to prevent overwriting it below */
  @@ -225,18 +155,24 @@
       fb->error = NULL;
       fb->bytes_sent = 0;
   
  -    fb->fd = -1;
  -    fb->timeout = -1;
  -
       return fb;
   }
   
  +static void bcleanup(void *v)
  +{
  +    BUFF *fb = v;
  +
  +    iol_close(&fb->iol);
  +}
  +
   /*
    * Push some I/O file descriptors onto the stream
    */
   API_EXPORT(void) ap_bpushfd(BUFF *fb, APRFile fd)
   {
  -    fb->fd = fd;
  +    ap_kill_cleanups_for_fd(fb->pool, fd);
  +    ap_register_cleanup(fb->pool, fb, bcleanup, bcleanup);
  +    unix_attach_fd(&fb->iol, fd);
   }
   
   API_EXPORT(int) ap_bsetopt(BUFF *fb, int optname, const void *optval)
  @@ -247,8 +183,7 @@
        return 0;
   
       case BO_TIMEOUT:
  -        fb->timeout = *(time_t *)optval;
  -        return 0;
  +     return iol_setopt(&fb->iol, AP_IOL_TIMEOUT, optval);
       }
       errno = EINVAL;
       return -1;
  @@ -267,8 +202,7 @@
        return 0;
   
       case BO_TIMEOUT:
  -        *(time_t *)optval = fb->timeout;
  -        return 0;
  +     return iol_getopt(&fb->iol, AP_IOL_TIMEOUT, optval);
       }
       errno = EINVAL;
       return -1;
  @@ -276,7 +210,6 @@
   
   static int bflush_core(BUFF *fb);
   
  -
   /*
    * Set a flag on (1) or off (0).
    */
  @@ -291,123 +224,21 @@
       return value;
   }
   
  -API_EXPORT(int) ap_bnonblock(int fd)
  -{
  -    int fd_flags;
  -
  -    fd_flags = fcntl(fd, F_GETFL, 0);
  -#if defined(O_NONBLOCK)
  -    fd_flags |= O_NONBLOCK;
  -    return fcntl(fd, F_SETFL, fd_flags);
  -#elif defined(O_NDELAY)
  -    fd_flags |= O_NDELAY;
  -    return fcntl(fd, F_SETFL, fd_flags);
  -#elif defined(FNDELAY)
  -    fd_flags |= O_FNDELAY;
  -    return fcntl(fd, F_SETFL, fd_flags);
  -#else
  -    /* XXXX: this breaks things, but an alternative isn't obvious...*/
  -    return 0;
  -#endif
  -}
  -
  -API_EXPORT(int) ap_bblock(int fd)
  -{
  -    int fd_flags;
  -
  -    fd_flags = fcntl(fd, F_GETFL, 0);
  -#if defined(O_NONBLOCK)
  -    fd_flags &= ~O_NONBLOCK;
  -    return fcntl(fd, F_SETFL, fd_flags);
  -#elif defined(O_NDELAY)
  -    fd_flags &= ~O_NDELAY;
  -    return fcntl(fd, F_SETFL, fd_flags);
  -#elif defined(FNDELAY)
  -    fd_flags &= ~O_FNDELAY;
  -    return fcntl(fd, F_SETFL, fd_flags);
  -#else
  -    /* XXXX: this breaks things, but an alternative isn't obvious...*/
  -    return 0;
  -#endif
  -}
  -
  -API_EXPORT(int) ap_bfileno(BUFF *fb, int direction)
  -{
  -    return fb->fd;
  -}
  -
  -/*
  - * This is called instead of read() everywhere in here.  It implements
  - * the B_SAFEREAD functionality -- which is to force a flush() if a read()
  - * would block.  It also deals with the EINTR errno result from read().
  - * return code is like read() except EINTR is eliminated.
  - */
  -
   
  -#define saferead saferead_guts
  -
  -
  -/* Test the descriptor and flush the output buffer if it looks like
  - * we will block on the next read.
  - *
  - * Note we assume the caller has ensured that fb->fd <= FD_SETSIZE
  - */
  -API_EXPORT(void) ap_bhalfduplex(BUFF *fb)
  -{
  -    int rv;
  -    fd_set fds;
  -    struct timeval tv;
  -
  -    /* We don't need to do anything if the connection has been closed
  -     * or there is something readable in the incoming buffer
  -     * or there is nothing flushable in the output buffer.
  -     */
  -    if (fb == NULL || fb->fd < 0 || fb->incnt > 0 || fb->outcnt == 0) {
  -     return;
  -    }
  -    /* test for a block */
  -    do {
  -     FD_ZERO(&fds);
  -     FD_SET(fb->fd, &fds);
  -     tv.tv_sec = 0;
  -     tv.tv_usec = 0;
  -     rv = ap_select(fb->fd + 1, &fds, NULL, NULL, &tv);
  -    } while (rv < 0 && errno == EINTR && !(fb->flags & B_EOUT));
  -
  -    /* treat any error as if it would block as well */
  -    if (rv != 1) {
  -     ap_bflush(fb);
  -    }
  -}
  -
  -static ap_inline int saferead_guts(BUFF *fb, void *buf, int nbyte)
  -{
  -    int rv;
  -
  -    if (fb->flags & B_SAFEREAD) {
  -     ap_bhalfduplex(fb);
  -    }
  -    do {
  -     rv = recvwithtimeout(fb->fd, buf, nbyte, fb->timeout);
  -    } while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
  -    return (rv);
  -}
  -
  -
  -/* A wrapper around saferead which does error checking and EOF checking
  - * yeah, it's confusing, this calls saferead, which calls recvwithtimeout...
  - * Note that saferead takes care of EINTR.
  - */
  +/* a wrapper around iol_read which checks for errors and EOFs */
   static int read_with_errors(BUFF *fb, void *buf, int nbyte)
   {
       int rv;
   
  -    rv = saferead(fb, buf, nbyte);
  +    rv = iol_read(&fb->iol, buf, nbyte);
       if (rv == 0) {
        fb->flags |= B_EOF;
       }
  -    else if (rv == -1 && errno != EAGAIN) {
  -     doerror(fb, B_RD);
  +    else if (rv == -1) {
  +     fb->saved_errno = errno;
  +     if (errno != EWOULDBLOCK) {
  +         doerror(fb, B_RD);
  +     }
       }
       return rv;
   }
  @@ -421,8 +252,10 @@
   {
       int i, nrd;
   
  -    if (fb->flags & B_RDERR)
  +    if (fb->flags & B_RDERR) {
  +     errno = fb->saved_errno;
        return -1;
  +    }
       if (nbyte == 0)
        return 0;
   
  @@ -436,8 +269,7 @@
            fb->inptr += i;
            return i;
        }
  -     i = read_with_errors(fb, buf, nbyte);
  -     return i;
  +     return read_with_errors(fb, buf, nbyte);
       }
   
       nrd = fb->incnt;
  @@ -511,8 +343,10 @@
        errno = EINVAL;
        return -1;
       }
  -    if (fb->flags & B_RDERR)
  +    if (fb->flags & B_RDERR) {
  +     errno = fb->saved_errno;
        return -1;
  +    }
   
       ct = 0;
       i = 0;
  @@ -569,73 +403,18 @@
    * Returns 1 on success, zero on end of transmission, or -1 on an error.
    *
    */
  -API_EXPORT(int) ap_blookc(char *buff, BUFF *fb)
  +API_EXPORT(int) ap_blookc(BUFF *fb)
   {
  -    int i;
  -
  -    *buff = '\0';
  +    int c;
   
  -    if (!(fb->flags & B_RD)) {       /* Can't do blookc on an unbuffered 
stream */
  -     errno = EINVAL;
  -     return -1;
  +    c = ap_bgetc(fb);
  +    if (c != -1) {
  +     ap_bungetc(c, fb);
       }
  -    if (fb->flags & B_RDERR)
  -     return -1;
  -
  -    if (fb->incnt == 0) {    /* no characters left in stream buffer */
  -     fb->inptr = fb->inbase;
  -     if (fb->flags & B_EOF)
  -         return 0;
  -
  -     i = read_with_errors(fb, fb->inptr, fb->bufsiz);
  -     if (i <= 0) {
  -         return i;
  -     }
  -     fb->incnt = i;
  -    }
  -
  -    *buff = fb->inptr[0];
  -    return 1;
  +    return c;
   }
   
   /*
  - * Skip data until a linefeed character is read
  - * Returns 1 on success, 0 if no LF found, or -1 on error
  - */
  -API_EXPORT(int) ap_bskiplf(BUFF *fb)
  -{
  -    unsigned char *x;
  -    int i;
  -
  -/* Can't do bskiplf on an unbuffered stream */
  -    if (!(fb->flags & B_RD)) {
  -     errno = EINVAL;
  -     return -1;
  -    }
  -    if (fb->flags & B_RDERR)
  -     return -1;
  -
  -    for (;;) {
  -     x = (unsigned char *) memchr(fb->inptr, '\012', fb->incnt);
  -     if (x != NULL) {
  -         x++;
  -         fb->incnt -= x - fb->inptr;
  -         fb->inptr = x;
  -         return 1;
  -     }
  -
  -     fb->inptr = fb->inbase;
  -     fb->incnt = 0;
  -     if (fb->flags & B_EOF)
  -         return 0;
  -     i = read_with_errors(fb, fb->inptr, fb->bufsiz);
  -     if (i <= 0)
  -         return i;
  -     fb->incnt = i;
  -    }
  -}
  -
  -/*
    * output a single character.  Used by ap_bputs when the buffer
    * is full... and so it'll cause the buffer to be flushed first.
    */
  @@ -663,65 +442,40 @@
       else
        return buf[0];
   }
  -
   
  -#ifndef NO_WRITEV
  -/* Similar to previous, but uses writev.  Note that it modifies vec.
  - * return 0 if successful, -1 otherwise.
  - *
  - * Deals with doerror() and bytes_sent.
  +/* A wrapper for write which deals with error conditions and
  + * bytes_sent.
    */
  -static int writev_it_all(BUFF *fb, struct iovec *vec, int nvec)
  +static int write_with_errors(BUFF *fb, const void *buf, int nbyte)
   {
  -    int i, rv;
  +    int rv;
   
  -    /* while it's nice an easy to build the vector and crud, it's painful
  -     * to deal with a partial writev()
  -     */
  -    i = 0;
  -    while (i < nvec) {
  -     do
  -         rv = writev(fb->fd, &vec[i], nvec - i);
  -     while (rv == -1 && (errno == EINTR || errno == EAGAIN)
  -            && !(fb->flags & B_EOUT));
  -     if (rv == -1) {
  -         if (errno != EINTR && errno != EAGAIN) {
  -             doerror(fb, B_WR);
  -         }
  -         return -1;
  -     }
  -     fb->bytes_sent += rv;
  -     /* recalculate vec to deal with partial writes */
  -     while (rv > 0) {
  -         if (rv < vec[i].iov_len) {
  -             vec[i].iov_base = (char *) vec[i].iov_base + rv;
  -             vec[i].iov_len -= rv;
  -             rv = 0;
  -         }
  -         else {
  -             rv -= vec[i].iov_len;
  -             ++i;
  -         }
  +    rv = iol_write(&fb->iol, buf, nbyte);
  +    if (rv == -1) {
  +     fb->saved_errno = errno;
  +     if (errno != EAGAIN) {
  +         doerror(fb, B_WR);
        }
  -     if (fb->flags & B_EOUT)
  -         return -1;
  +     return -1;
       }
  -    /* if we got here, we wrote it all */
  -    return 0;
  +    else if (rv == 0) {
  +     errno = EAGAIN;
  +     return -1;
  +    }
  +    fb->bytes_sent += rv;
  +    return rv;
   }
  -#endif
   
  -/* A wrapper for sendwithtimeout which deals with error conditions and
  - * bytes_sent.  Also handles non-blocking writes.
  +/* A wrapper for writev which deals with error conditions and
  + * bytes_sent.
    */
  -static int write_with_errors(BUFF *fb, const void *buf, int nbyte)
  +static int writev_with_errors(BUFF *fb, const struct iovec *vec, int nvec)
   {
       int rv;
   
  -    do
  -     rv = sendwithtimeout(fb->fd, buf, nbyte, fb->timeout);
  -    while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
  +    rv = iol_writev(&fb->iol, vec, nvec);
       if (rv == -1) {
  +     fb->saved_errno = errno;
        if (errno != EAGAIN) {
            doerror(fb, B_WR);
        }
  @@ -736,33 +490,34 @@
   }
   
   
  -#ifndef NO_WRITEV
   /*
    * Used to combine the contents of the fb buffer, and a large buffer
  - * passed in.
  + * passed in.  The return code is how many bytes of buf were written,
  + * or -1.
    */
   static int large_write(BUFF *fb, const void *buf, int nbyte)
   {
  -    struct iovec vec[4];
  -    int nvec;
  -
  -    nvec = 0;
  -    if (fb->outcnt > 0) {
  -     vec[nvec].iov_base = (void *) fb->outbase;
  -     vec[nvec].iov_len = fb->outcnt;
  -     ++nvec;
  -    }
  -    vec[nvec].iov_base = (void *) buf;
  -    vec[nvec].iov_len = nbyte;
  -    ++nvec;
  +    struct iovec vec[2];
  +    int rv;
   
  -    fb->outcnt = 0;
  -    if (writev_it_all(fb, vec, nvec)) {
  -     return -1;
  +    vec[0].iov_base = (void *) fb->outbase;
  +    vec[0].iov_len = fb->outcnt;
  +    vec[1].iov_base = (void *) buf;
  +    vec[1].iov_len = nbyte;
  +    rv = writev_with_errors(fb, vec, 2);
  +    if (rv >= fb->outcnt) {
  +     rv -= fb->outcnt;
  +     fb->outcnt = 0;
  +     return rv;
  +    }
  +    else if (rv > 0) {
  +     /* shift bytes forward in buffer */
  +     memmove(fb->outbase, fb->outbase + rv, fb->outcnt - rv);
  +     fb->outcnt -= rv;
  +     return 0;
       }
  -    return nbyte;
  +    return rv;
   }
  -#endif
   
   
   /*
  @@ -776,8 +531,10 @@
   {
       int i, nwr;
   
  -    if (fb->flags & (B_WRERR | B_EOUT))
  +    if (fb->flags & (B_WRERR | B_EOUT)) {
  +     errno = fb->saved_errno;
        return -1;
  +    }
       if (nbyte == 0)
        return 0;
   
  @@ -785,7 +542,6 @@
        return write_with_errors(fb, buf, nbyte);
       }
   
  -#ifndef NO_WRITEV
   /*
    * Detect case where we're asked to write a large buffer, and combine our
    * current buffer with it in a single writev().  Note we don't consider
  @@ -797,7 +553,6 @@
        && nbyte + fb->outcnt >= fb->bufsiz) {
        return large_write(fb, buf, nbyte);
       }
  -#endif
   
   /*
    * Whilst there is data in the buffer, keep on adding to it and writing it
  @@ -827,10 +582,7 @@
   
        /* deal with a partial write */
        if (i < fb->outcnt) {
  -         int j, n = fb->outcnt;
  -         unsigned char *x = fb->outbase;
  -         for (j = i; j < n; j++)
  -             x[j - i] = x[j];
  +         memmove(fb->outbase, fb->outbase + i, fb->outcnt - i);
            fb->outcnt -= i;
        }
        else
  @@ -856,10 +608,10 @@
            return -1;
       }
   /* copy what's left to the file buffer */
  -    fb->outcnt = 0;
  +    /* assert(fb->outcnt == 0); */
       if (nbyte > 0)
  -     memcpy(fb->outbase + fb->outcnt, buf, nbyte);
  -    fb->outcnt += nbyte;
  +     memcpy(fb->outbase, buf, nbyte);
  +    fb->outcnt = nbyte;
       nwr += nbyte;
       return nwr;
   }
  @@ -879,10 +631,7 @@
         * strange (non-blocking) mode, then we might not have done so.
         */
        if (i < fb->outcnt) {
  -         int j, n = fb->outcnt;
  -         unsigned char *x = fb->outbase;
  -         for (j = i; j < n; j++)
  -             x[j - i] = x[j];
  +         memmove(fb->outbase, fb->outbase + i, fb->outcnt - i);
        }
        fb->outcnt -= i;
   
  @@ -925,15 +674,15 @@
       if (fb->flags & B_WR)
        rc1 = ap_bflush(fb);
       else
  -    rc1 = 0;
  -    rc2 = ap_pclosef(fb->pool, fb->fd);
  +     rc1 = 0;
  +    ap_kill_cleanup(fb->pool, fb, bcleanup);
  +    rc2 = iol_close(&fb->iol);
   
       fb->inptr = fb->inbase;
       fb->incnt = 0;
       fb->outcnt = 0;
   
       fb->flags |= B_EOF | B_EOUT;
  -    fb->fd = -1;
   
       if (rc1 != 0)
        return rc1;
  @@ -1056,7 +805,8 @@
       fd = ap_popenf(a, name, flg, mode);
       if (!fd) {
           return NULL;
  -    }fb = ap_bcreate(a, ((flg &(B_RD|B_RDWR)) ? B_RD : 0)
  +    }
  +    fb = ap_bcreate(a, ((flg &(B_RD|B_RDWR)) ? B_RD : 0)
                     | ((flg & (B_WR|B_RDWR)) ? B_WR : 0));
       ap_bpushfd(fb, fd);
       return fb;
  
  
  
  1.2       +3 -0      apache-2.0/mpm/src/main/http_connection.c
  
  Index: http_connection.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/main/http_connection.c,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- http_connection.c 1999/06/18 18:39:31     1.1
  +++ http_connection.c 1999/06/18 23:34:59     1.2
  @@ -66,6 +66,9 @@
   
   #include <poll.h>
   
  +/* TODO: re-implement the lingering close stuff */
  +#define NO_LINGCLOSE
  +
   /*
    * More machine-dependent networking gooo... on some systems,
    * you've got to be *really* sure that all the packets are acknowledged
  
  
  
  1.3       +10 -4     apache-2.0/mpm/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/main/http_protocol.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- http_protocol.c   1999/06/18 19:20:49     1.2
  +++ http_protocol.c   1999/06/18 23:34:59     1.3
  @@ -712,7 +712,7 @@
            * the next line begins with a continuation character.
            */
       } while (fold && (retval != 1) && (n > 1)
  -                  && (ap_blookc(&next, in) == 1)
  +                  && (next = ap_blookc(in))
                     && ((next == ' ') || (next == '\t')));
   
       return total;
  @@ -796,10 +796,12 @@
        * read().  B_SAFEREAD ensures that the BUFF layer flushes if it will
        * have to block during a read.
        */
  -    ap_bsetflag(conn->client, B_SAFEREAD, 1);
  +    /* TODO: re-implement SAFEREAD external to BUFF using a layer */
  +    //ap_bsetflag(conn->client, B_SAFEREAD, 1);
  +    ap_bflush(conn->client);
       while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
           if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
  -            ap_bsetflag(conn->client, B_SAFEREAD, 0);
  +            //ap_bsetflag(conn->client, B_SAFEREAD, 0);
            /* this is a hack to make sure that request time is set,
             * it's not perfect, but it's better than nothing 
             */
  @@ -820,7 +822,7 @@
   #endif
       */
   
  -    ap_bsetflag(conn->client, B_SAFEREAD, 0);
  +    //ap_bsetflag(conn->client, B_SAFEREAD, 0);
   
       r->request_time = time(NULL);
       r->the_request = ap_pstrdup(r->pool, l);
  @@ -1969,6 +1971,9 @@
       return total_bytes_sent;
   }
   
  +
  +/* TODO: re-implement ap_send_fb */
  +#if 0
   /*
    * Send the body of a response to the client.
    */
  @@ -2079,6 +2084,7 @@
       SET_BYTES_SENT(r);
       return total_bytes_sent;
   }
  +#endif
   
   
   
  
  
  
  1.2       +2 -1      apache-2.0/mpm/src/main/http_request.c
  
  Index: http_request.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/main/http_request.c,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- http_request.c    1999/06/18 18:39:30     1.1
  +++ http_request.c    1999/06/18 23:35:00     1.2
  @@ -1240,7 +1240,8 @@
        * this packet, then it'll appear like the link is stalled when really
        * it's the application that's stalled.
        */
  -    ap_bhalfduplex(r->connection->client);
  +    /* TODO: re-implement ap_bhalfduplex... not sure how yet */
  +    //ap_bhalfduplex(r->connection->client);
       ap_log_transaction(r);
   }
   
  
  
  
  1.1                  apache-2.0/mpm/src/main/iol_unix.c
  
  Index: iol_unix.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  
  #include "httpd.h"
  #include "http_main.h"
  #include "http_log.h"
  #include "ap_iol.h"
  
  #include <errno.h>
  #include <sys/types.h>
  #include <sys/uio.h>
  
  
  #define FD_NONBLOCKING_SET    (1)
  
  typedef struct {
      int fd;
      int flags;
      int timeout;
  } fd_data;
  
  static int unix_setopt(ap_iol *_fd, ap_iol_option opt, const void *value)
  {
      fd_data *fd = _fd->iol_data;
  
      switch (opt) {
      case AP_IOL_TIMEOUT:
        fd->timeout = *(const int *)value;
        break;
      default:
        errno = EINVAL;
        return -1;
      }
      return 0;
  }
  
  static int unix_getopt(ap_iol *_fd, ap_iol_option opt, void *value)
  {
      fd_data *fd = _fd->iol_data;
  
      switch (opt) {
      case AP_IOL_TIMEOUT:
        *(int *)value = fd->timeout;
        break;
      default:
        errno = EINVAL;
        return -1;
      }
      return 0;
  }
  
  static int set_nonblock(int fd)
  {
      int fd_flags;
  
      fd_flags = fcntl(fd, F_GETFL, 0);
  #if defined(O_NONBLOCK)
      fd_flags |= O_NONBLOCK;
      return fcntl(fd, F_SETFL, fd_flags);
  #elif defined(O_NDELAY)
      fd_flags |= O_NDELAY;
      return fcntl(fd, F_SETFL, fd_flags);
  #elif defined(FNDELAY)
      fd_flags |= O_FNDELAY;
      return fcntl(fd, F_SETFL, fd_flags);
  #else
  #error "your unix lacks non-blocking i/o, you lose"
  #endif
  }
  
  /* the timeout code is a separate routine because it requires
      a stack frame... and we don't want to pay that setup cost
      on every call */
  
  /* this macro expands into the four basic i/o methods */
  
  #define method(name, args, syscall, selread, selwrite)        \
      static int unix_##name##_timeout args \
      { \
        fd_data *fd = _fd->iol_data; \
        fd_set fdset; \
        struct timeval tv; \
        int rv; \
   \
        FD_ZERO(&fdset); \
        FD_SET(fd->fd, &fdset); \
        tv.tv_sec = fd->timeout; \
        tv.tv_usec = 0; \
        do { \
            rv = select(fd->fd + 1, selread, selwrite, NULL, fd->timeout < 0 ? 
NULL : &tv); \
        } while (rv == -1 && errno == EINTR); \
        if (!FD_ISSET(fd->fd, &fdset)) { \
            errno = ETIME; \
            return -1; \
        } \
        do { \
            rv = syscall(fd->fd, arg1, arg2); \
        } while (rv == -1 && errno == EINTR); \
        return rv; \
      } \
   \
      static int unix_##name args \
      { \
        fd_data *fd = _fd->iol_data; \
        int rv; \
   \
        if (!(fd->flags & FD_NONBLOCKING_SET)) { \
            if (fd->timeout < 0) { \
                return syscall(fd->fd, arg1, arg2); \
            } \
            /* must shift descriptor to blocking mode now */ \
            if (set_nonblock(fd->fd)) { \
                return -1; \
            } \
            fd->flags |= B_NONBLOCK_SET; \
        } \
   \
        /* try writing, ignoring EINTR, the upper layer has to handle \
            partial read/writes anyhow, so we can return early */ \
        do { \
            rv = syscall(fd->fd, arg1, arg2); \
        } while (rv == -1 && errno == EINTR); \
        if (rv >= 0) { \
            return rv; \
        } \
        if (errno == EWOULDBLOCK && fd->timeout != 0) { \
            return unix_##name##_timeout(_fd, arg1, arg2); \
        } \
        return -1; \
      } \
  
  method(write, (ap_iol *_fd, const char *arg1, int arg2), write, NULL, &fdset)
  method(writev, (ap_iol *_fd, const struct iovec *arg1, int arg2), writev, 
NULL, &fdset)
  method(read, (ap_iol *_fd, char *arg1, int arg2), read, &fdset, NULL)
  method(readv, (ap_iol *_fd, struct iovec *arg1, int arg2), readv, &fdset, 
NULL)
  
  static int unix_close(ap_iol *_fd)
  {
      fd_data *fd = _fd->iol_data;
      int rv;
      int saved_errno;
  
      rv = close(fd->fd);
      saved_errno = errno;
      free(fd);
      errno = saved_errno;
      return rv;
  }
  
  static const ap_iol_methods unix_iol = {
      unix_close,
      unix_write,
      unix_writev,
      unix_read,
      unix_readv,
      unix_setopt,
      unix_getopt
  };
  
  void unix_attach_fd(ap_iol *iol, int _fd)
  {
      fd_data *fd;
  
      fd = malloc(sizeof(fd_data));
      fd->fd = _fd;
      fd->timeout = -1;
      fd->flags = 0;
      iol->iol_data = fd;
      iol->methods = &unix_iol;
  }
  
  
  

Reply via email to