httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@hyperreal.org
Subject cvs commit: apache-2.0/src/lib/apr/network_io/unix networkio.h sendrecv.c
Date Sat, 04 Dec 1999 21:48:35 GMT
rbb         99/12/04 13:48:35

  Modified:    src/lib/apr acconfig.h configure.in
               src/lib/apr/include apr.h.in apr_network_io.h
               src/lib/apr/network_io/unix networkio.h sendrecv.c
  Log:
  Add Sendfile to APR.  This is not well tested, and a test case is needed.
  I did some minor cleanup work, mainly to integrate sendfile into the APR
  autoconf stuff.
  Submitted by:	John Zedlewski
  Reviewed by:    Ryan Bloom
  
  Revision  Changes    Path
  1.15      +1 -0      apache-2.0/src/lib/apr/acconfig.h
  
  Index: acconfig.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/acconfig.h,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- acconfig.h	1999/12/01 18:38:55	1.14
  +++ acconfig.h	1999/12/04 21:48:30	1.15
  @@ -46,6 +46,7 @@
   
   #undef SIZEOF_SSIZE_T
   #undef APR_HAS_THREADS
  +#undef APR_HAS_SENDFILE
   
   @BOTTOM@
   
  
  
  
  1.31      +3 -0      apache-2.0/src/lib/apr/configure.in
  
  Index: configure.in
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/configure.in,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- configure.in	1999/12/01 20:35:16	1.30
  +++ configure.in	1999/12/04 21:48:31	1.31
  @@ -215,6 +215,7 @@
   
   AC_CHECK_HEADERS(arpa/inet.h)
   AC_CHECK_HEADERS(netinet/in.h, netinet_inh="1", netinet_inh="0")
  +AC_CHECK_HEADERS(netinet/tcp.h)
   
   AC_CHECK_HEADERS(sys/file.h)
   AC_CHECK_HEADERS(sys/ioctl.h)
  @@ -261,8 +262,10 @@
   AC_CHECK_FUNCS(pthread_sigmask)
   AC_CHECK_FUNCS(strcasecmp stricmp poll setsid)
   AC_CHECK_FUNCS(sigaction writev)
  +AC_CHECK_FUNCS(sendfile, [ sendfile="#define APR_HAS_SENDFILE 1" ], [ sendfile="APR_HAS_SENDFILE
0" ]) 
   AC_CHECK_FUNCS(getpass)
   AC_CHECK_FUNC(_getch)
  +AC_SUBST(sendfile)
   
   AC_CHECK_FUNCS(gmtime_r localtime_r)
   
  
  
  
  1.4       +1 -0      apache-2.0/src/lib/apr/include/apr.h.in
  
  Index: apr.h.in
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr.h.in,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- apr.h.in	1999/12/01 20:35:20	1.3
  +++ apr.h.in	1999/12/04 21:48:33	1.4
  @@ -18,6 +18,7 @@
   
   /*  APR Feature Macros */
   @threads@
  +@sendfile@
   @mmap@
   
   /* Typedefs that APR needs. */
  
  
  
  1.18      +16 -0     apache-2.0/src/lib/apr/include/apr_network_io.h
  
  Index: apr_network_io.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_network_io.h,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- apr_network_io.h	1999/12/01 20:35:37	1.17
  +++ apr_network_io.h	1999/12/04 21:48:33	1.18
  @@ -61,6 +61,7 @@
   #endif
   
   #include "apr_general.h"
  +#include "apr_file_io.h"
   #include "apr_errno.h"
   #if APR_HAVE_NETINET_IN_H
   #include <netinet/in.h>
  @@ -103,7 +104,18 @@
   
   typedef struct socket_t     ap_socket_t;
   typedef struct pollfd_t    ap_pollfd_t;
  +typedef struct hdtr_t		ap_hdtr_t;
   
  +#ifdef APR_HAS_SENDFILE
  +/* A structure to encapsulate headers and trailers for ap_sendfile */
  +struct hdtr_t {
  +    struct iovec* headers;
  +    int numheaders;
  +    struct iovec* trailers;
  +    int numtrailers;
  +};
  +#endif
  +
   /* function definitions */
   
   ap_status_t ap_create_tcp_socket(ap_socket_t **, ap_context_t *);
  @@ -123,6 +135,10 @@
   
   ap_status_t ap_send(ap_socket_t *, const char *, ap_ssize_t *);
   ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, ap_int32_t nvec, ap_int32_t
*nbytes);
  +#ifdef HAVE_SENDFILE
  +ap_status_t ap_sendfile(ap_socket_t *sock, ap_file_t *file, ap_hdtr_t *hdtr, ap_off_t *offset,

  +                         ap_size_t *len, ap_int32_t flags);
  +#endif
   ap_status_t ap_recv(ap_socket_t *, char *, ap_ssize_t *);
   
   ap_status_t ap_setsocketopt(ap_socket_t *, ap_int32_t, ap_int32_t);
  
  
  
  1.11      +6 -0      apache-2.0/src/lib/apr/network_io/unix/networkio.h
  
  Index: networkio.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/network_io/unix/networkio.h,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- networkio.h	1999/12/03 15:18:33	1.10
  +++ networkio.h	1999/12/04 21:48:34	1.11
  @@ -62,6 +62,12 @@
   #include "apr_lib.h"
   
   /* System headers the network I/O library needs */
  +#if HAVE_SYS_TYPES_H
  +#include <sys/types.h>
  +#endif
  +#if HAVE_SYS_UIO_H
  +#include <sys/uio.h>
  +#endif
   #if HAVE_POLL_H
   #include <poll.h>
   #endif
  
  
  
  1.8       +380 -0    apache-2.0/src/lib/apr/network_io/unix/sendrecv.c
  
  Index: sendrecv.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/network_io/unix/sendrecv.c,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- sendrecv.c	1999/12/03 15:18:33	1.7
  +++ sendrecv.c	1999/12/04 21:48:34	1.8
  @@ -57,6 +57,19 @@
   
   #include "networkio.h"
   
  +#ifdef HAVE_SENDFILE
  +/* This file is needed to allow us access to the ap_file_t internals. */
  +#include "../../file_io/unix/fileio.h"
  +
  +/* Glibc2.1.1 fails to define TCP_CORK.  This is a bug that will be 
  + *fixed in the next release.  It should be 3
  + */
  +#if !defined(TCP_CORK) && defined(__linux__)
  +#define TCP_CORK 3
  +#endif
  +
  +#endif /* HAVE_SENDFILE */
  +
   /* ***APRDOC********************************************************
    * ap_status_t ap_send(ap_socket_t *, const char *, ap_ssize_t *, time_t)
    *    Send data over a network.
  @@ -171,4 +184,371 @@
       (*len) = rv;
       return APR_SUCCESS;
   }
  +
  +/* ***APRDOC********************************************************
  + * ap_status_t ap_sendv(ap_socket_t *, const struct iovec *, ap_int32_t, ap_int32_t *)
  + *    Send multiple packets of data over a network.
  + * arg 1) The socket to send the data over.
  + * arg 2) The array of iovec structs containing the data to send 
  + * arg 3) The number of iovec structs in the array
  + * arg 4) Receives the number of bytes actually written
  + * NOTE:  This functions acts like a blocking write by default.  To change 
  + *        this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option.
  + *        The number of bytes actually sent is stored in argument 3.
  + */
  +ap_status_t ap_sendv(struct socket_t * sock, const struct iovec * vec,
  +                     ap_int32_t nvec, ap_int32_t * nbytes)
  +{
  +    ssize_t rv;
  +
  +    do {
  +        rv = writev(sock->socketdes, vec, nvec);
  +    } while (rv == -1 && errno == EINTR);
  +
  +    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
  +        struct timeval *tv;
  +        fd_set fdset;
  +        int srv;
  +
  +        do {
  +            FD_ZERO(&fdset);
  +            FD_SET(sock->socketdes, &fdset);
  +            if (sock->timeout < 0) {
  +        	tv = NULL;
  +            }
  +            else {
  +        	tv = ap_palloc(sock->cntxt, sizeof(struct timeval));
  +        	tv->tv_sec = sock->timeout;
  +        	tv->tv_usec = 0;
  +            }
  +            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
  +        } while (srv == -1 && errno == EINTR);
  +
  +        if (srv == 0) {
  +            (*nbytes) = -1;
  +            return APR_TIMEUP;
  +        }
  +        else if (srv < 0) {
  +            (*nbytes) = -1;
  +            return errno;
  +        }
  +        else {
  +            do {
  +        	rv = writev(sock->socketdes, vec, nvec);
  +            } while (rv == -1 && errno == EINTR);
  +        }
  +    }
  +    (*nbytes) = rv;
  +    return APR_SUCCESS;
  +}
  +
  +#if defined(HAVE_SENDFILE)
  +/* ***APRDOC********************************************************
  + * ap_status_t ap_sendfile(ap_socket_t *, ap_file_t *, ap_hdtr_t *, 
  + *                         ap_off_t *, ap_size_t *, ap_int32_t flags)
  + *    Send a file from an open file descriptor to a socket, along with 
  + *    optional headers and trailers
  + * arg 1) The socket to which we're writing
  + * arg 2) The open file from which to read
  + * arg 3) A structure containing the headers and trailers to send
  + * arg 4) Offset into the file where we should begin writing
  + * arg 5) Number of bytes to send 
  + * arg 6) OS-specific flags to pass to sendfile()
  + * NOTE:  This functions acts like a blocking write by default.  To change 
  + *        this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option.
  + *        The number of bytes actually sent is stored in argument 4.
  + */
  +
  + /* TODO: Verify that all platforms handle the fd the same way 
  +  *     (i.e. not moving current file pointer)
  +  *     - Should flags be an int_32 or what?
  +  */
  +
  +#if defined(__linux__) && defined(HAVE_WRITEV)
  +ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
  +        		ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
  +        		ap_int32_t flags)
  +{
  +    off_t off = *offset;
  +    int corkflag = 1;
  +    int rv, nbytes = 0;
  +
  +    /* TCP_CORK keeps us from sending partial frames when we shouldn't */
  +    rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK,
  +        	    (const void *) &corkflag, sizeof(corkflag));
  +    if (rv == -1) {
  +        return errno;
  +    }
  +
  +    /* Now write the headers */
  +    if (hdtr->numheaders > 0) {
  +        ap_int32_t hdrbytes;
  +        rv = ap_sendv(sock, hdtr->headers, hdtr->numheaders, &hdrbytes);
  +        if (rv != APR_SUCCESS) {
  +            return errno;
  +        }
  +        nbytes += hdrbytes;
  +    }
  +
  +    do {
  +        rv = sendfile(sock->socketdes,	/* socket */
  +        	      file->filedes,	/* open file descriptor of the file to be sent */
  +        	      &off,	/* where in the file to start */
  +        	      *len	/* number of bytes to send */
  +            );
  +    } while (rv == -1 && errno == EINTR);
  +
  +    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
  +        struct timeval *tv;
  +        fd_set fdset;
  +        int srv;
  +        do {
  +            FD_ZERO(&fdset);
  +            FD_SET(sock->socketdes, &fdset);
  +            if (sock->timeout < 0) {
  +        	tv = NULL;
  +            }
  +            else {
  +        	tv = ap_palloc(sock->cntxt, sizeof(struct timeval));
  +        	tv->tv_sec = sock->timeout;
  +        	tv->tv_usec = 0;
  +            }
  +            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
  +        } while (srv == -1 && errno == EINTR);
  +
  +        if (srv == 0) {
  +            (*len) = -1;
  +            return APR_TIMEUP;
  +        }
  +        else if (srv < 0) {
  +            (*len) = -1;
  +            return errno;
  +        }
  +        else {
  +            do {
  +        	rv = sendfile(sock->socketdes,	/* socket */
  +        		      file->filedes,	/* open file descriptor of the file to be sent */
  +        		      &off,	/* where in the file to start */
  +        		      *len);	/* number of bytes to send */
  +            } while (rv == -1 && errno == EINTR);
  +        }
  +    }
  +
  +    if (rv == -1) {
  +        return errno;
  +    }
  +
  +    nbytes += rv;
  +
  +    /* Now write the footers */
  +    if (hdtr->numtrailers > 0) {
  +        ap_int32_t trbytes;
  +        rv = ap_sendv(sock, hdtr->trailers, hdtr->numtrailers, &trbytes);
  +        if (rv == -1) {
  +            return errno;
  +        }
  +        nbytes += trbytes;
  +    }
  +
  +    /* Uncork to send queued frames */
  +    corkflag = 0;
  +    rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK,
  +                    (const void *) &corkflag, sizeof(corkflag));
  +
  +    (*len) = nbytes;
  +    return APR_SUCCESS;
  +}
  +
  +/* These are just demos of how the code for the other OSes.
  + * I haven't tested these, but they're right in terms of interface.
  + * I just wanted to see what types of vars would be required from other OSes. 
  + */
  +
  +#elif defined(__FreeBSD__)
  +/* Release 3.1 or greater */
  +ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
  +        		ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
  +        		ap_int32_t flags)
  +{
  +    off_t nbytes;
  +    int rv;
  +    struct sf_hdtr headerstruct;
  +
  +    headerstruct.headers = hdtr->headers;
  +    headerstruct.hdr_cnt = hdtr->numheaders;
  +    headerstruct.trailers = hdtr->trailers;
  +    headerstruct.trl_cnt = hdtr->numtrailers;
  +
  +
  +    /* FreeBSD can send the headers/footers as part of the system call */
  +    do {
  +        rv = sendfile(file->filedes,	/* open file descriptor of the file to be sent
*/
  +        	      sock->socketdes,	/* socket */
  +        	      *offset,	/* where in the file to start */
  +        	      (size_t) * len,	/* number of bytes to send */
  +        	      &headerstruct,	/* Headers/footers */
  +        	      &nbytes,	/* number of bytes written */
  +        	      flags	/* undefined, set to 0 */
  +            );
  +    } while (rv == -1 && errno == EINTR);
  +
  +    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
  +        struct timeval *tv;
  +        fd_set fdset;
  +        int srv;
  +
  +        do {
  +            FD_ZERO(&fdset);
  +            FD_SET(sock->socketdes, &fdset);
  +            if (sock->timeout < 0) {
  +        	tv = NULL;
  +            }
  +            else {
  +        	tv = ap_palloc(sock->cntxt, sizeof(struct timeval));
  +        	tv->tv_sec = sock->timeout;
  +        	tv->tv_usec = 0;
  +            }
  +            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
  +        } while (srv == -1 && errno == EINTR);
  +
  +        if (srv == 0) {
  +            (*len) = -1;
  +            return APR_TIMEUP;
  +        }
  +        else if (srv < 0) {
  +            (*len) = -1;
  +            return errno;
  +        }
  +        else {
  +            do {
  +        	rv = sendfile(file->filedes,	/* open file descriptor of the file to be sent
*/
  +        		      sock->socketdes,	/* socket */
  +        		      *offset,	/* where in the file to start */
  +        		      (size_t) * len,	/* number of bytes to send */
  +        		      &headerstruct,	/* Headers/footers */
  +        		      &nbytes,	/* number of bytes written */
  +        		      flags	/* undefined, set to 0 */
  +        	    );
  +            } while (rv == -1 && errno == EINTR);
  +        }
  +    }
  +
  +
  +    if (rv == -1) {
  +        return errno;
  +    }
  +
  +    (*len) = nbytes;
  +    return APR_SUCCESS;
  +}
  +
  +#elif defined(__HPUX__)
  +
  +/* HP-UX Version 10.30 or greater */
  +ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
  +        		ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
  +        		ap_int32_t flags)
  +{
  +    int i, ptr = 0;
  +    size_t nbytes = 0, headerlen = 0, trailerlen = 0;
  +    struct sf_hdtr headerstruct;
  +    struct iovec hdtrarray[2];
  +    void *headerbuf, *trailerbuf;
  +
  +
  +    /* HP-UX can only send one header iovec and one footer iovec */
  +
  +    for (i = 0; i < hdtr->numheaders; i++) {
  +        headerlen += hdtr->headers[i].iov_len;
  +    }
  +
  +    headerbuf = ap_palloc(sock->cntxt, headerlen);
  +
  +    for (i = 0; i < hdtr->numheaders; i++) {
  +        memcpy(headerbuf, hdtr->headers[i].iov_base + ptr,
  +               hdtr->headers[i].iov_len);
  +        ptr += hdtr->headers[i].iov_len;
  +    }
  +
  +    for (i = 0; i < hdtr->numtrailers; i++) {
  +        trailerlen += hdtr->headers[i].iov_len;
  +    }
  +
  +    trailerbuf = ap_palloc(sock->cntxt, trailerlen);
  +
  +    for (i = 0; i < hdtr->numtrailers; i++) {
  +        memcpy(trailerbuf, hdtr->trailers[i].iov_base + ptr,
  +               hdtr->trailers[i].iov_len);
  +        ptr += hdtr->trailers[i].iov_len;
  +    }
  +
  +    hdtrarray[0].iov_base = headerbuf;
  +    hdtrarray[0].iov_len = headerlen;
  +    hdtrarray[1].iov_base = trailerbuf;
  +    hdtrarray[1].iov_len = trailerlen;
  +
  +    do {
  +        rv = sendfile(sock->socketdes,	/* socket  */
  +        	      file->filedes,	/* file descriptor to send */
  +        	      *offset,	/* where in the file to start */
  +        	      nbytes,	/* number of bytes to send */
  +        	      hdtrarray,	/* Headers/footers */
  +        	      flags	/* undefined, set to 0 */
  +            );
  +    } while (rv == -1 && errno == EINTR);
  +
  +    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
  +        struct timeval *tv;
  +        fd_set fdset;
  +        int srv;
  +
  +        do {
  +            FD_ZERO(&fdset);
  +            FD_SET(sock->socketdes, &fdset);
  +            if (sock->timeout < 0) {
  +        	tv = NULL;
  +            }
  +            else {
  +        	tv = ap_palloc(sock->cntxt, sizeof(struct timeval));
  +        	tv->tv_sec = sock->timeout;
  +        	tv->tv_usec = 0;
  +            }
  +            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
  +        } while (srv == -1 && errno == EINTR);
  +
  +        if (srv == 0) {
  +            (*len) = -1;
  +            return APR_TIMEUP;
  +        }
  +        else if (srv < 0) {
  +            (*len) = -1;
  +            return errno;
  +        }
  +        else {
  +            do {
  +        	rv = sendfile(sock->socketdes,	/* socket  */
  +        		      file->filedes,	/* file descriptor to send */
  +        		      *offset,	/* where in the file to start */
  +        		      nbytes,	/* number of bytes to send */
  +        		      hdtrarray,	/* Headers/footers */
  +        		      flags	/* undefined, set to 0 */
  +        	    );
  +            } while (rv == -1 && errno == EINTR);
  +        }
  +    }
  +
  +
  +    if (rv == -1) {
  +        return errno;
  +    }
  +
  +
  +    /* Set len to the number of bytes written */
  +    (*len) = rv;
  +    return APR_SUCCESS;
  +}
  +#else
  +/* TODO: Add AIX support */
  +#endif /* __linux__, __FreeBSD__, __HPUX__ */
  +#endif /* HAVE_SENDFILE */
   
  
  
  

Mime
View raw message