You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by st...@hyperreal.org on 1999/08/17 23:25:34 UTC

cvs commit: apache-2.0/mpm/src/os/win32 iol_socket.c

stoddard    99/08/17 14:25:32

  Added:       mpm/src/os/win32 iol_socket.c
  Log:
  WIN32 iol_socket.c.
  
  Revision  Changes    Path
  1.1                  apache-2.0/mpm/src/os/win32/iol_socket.c
  
  Index: iol_socket.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
   *    apache@apache.org.
   *
   * 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 "ap_iol.h"
  
  #define FD_NONBLOCKING_SET	(1)
  //#define IOL_SOCK_POSIX    // This works except for writev
  #define IOL_SOCK_WIN32      // ANd this seems to be working as well, except for writev...
  //#define IOL_SOCK_ASYNC
  
  typedef struct {
      ap_iol iol;
      int fd;
      int flags;
      int timeout;
  } iol_socket;
  
  static int win32_setopt(ap_iol *viol, ap_iol_option opt, const void *value)
  {
      iol_socket *iol = (iol_socket *)viol;
  
      switch (opt) {
      case AP_IOL_TIMEOUT:
  	iol->timeout = *(const int *)value;
  	break;
      default:
          WSASetLastError(WSAEINVAL);
  	return -1;
      }
      return 0;
  }
  
  static int win32_getopt(ap_iol *viol, ap_iol_option opt, void *value)
  {
      iol_socket *iol = (iol_socket *)viol;
  
      switch (opt) {
      case AP_IOL_TIMEOUT:
  	*(int *)value = iol->timeout;
  	break;
      default:
          WSASetLastError(WSAEINVAL);
  	return -1;
      }
      return 0;
  }
  
  static int set_nonblock(int fd)
  {
      int iostate = 1;
      ioctlsocket(fd, FIONBIO, &iostate);
      return 0;
  }
  
  static int win32_close(ap_iol *viol)
  {
      iol_socket *iol = (iol_socket *)viol;
      int rv;
  
      rv = close(iol->fd);
  
      free(iol);
  
      return rv;
  }
  #ifdef IOL_SOCK_POSIX
  /* 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 win32_##name##_timeout args \
      { \
  	iol_socket *iol = (iol_socket *)viol; \
  	fd_set fdset; \
  	struct timeval tv; \
  	int rv; \
          int lasterror; \
   \
  	FD_ZERO(&fdset); \
  	FD_SET(iol->fd, &fdset); \
  	tv.tv_sec = iol->timeout; \
  	tv.tv_usec = 0; \
  	do { \
  	    rv = select(iol->fd + 1, selread, selwrite, NULL, iol->timeout < 0 ? NULL : &tv); \
              if (rv == SOCKET_ERROR) { \
                  lasterror = WSAGetLastError(); \
              } \
          } while (rv == SOCKET_ERROR && lasterror == WSAEINTR); \
  	if (!FD_ISSET(iol->fd, &fdset)) { \
  	    WSASetLastError(WSAETIMEDOUT); \
  	    return -1; \
  	} \
  	do { \
  	    rv = syscall(iol->fd, arg1, arg2, 0); \
              if (rv == SOCKET_ERROR) { \
                  lasterror = WSAGetLastError(); \
              } \
  	} while (rv == SOCKET_ERROR && lasterror == WSAEINTR); \
  	return rv; \
      } \
   \
      static int win32_##name args \
      { \
  	iol_socket *iol = (iol_socket *)viol; \
  	int rv; \
          int lasterror; \
   \
  	if (!(iol->flags & FD_NONBLOCKING_SET)) { \
  	    if (iol->timeout < 0) { \
  		return syscall(iol->fd, arg1, arg2, 0); \
  	    } \
  	    /* must shift descriptor to blocking mode now */ \
  	    if (set_nonblock(iol->fd)) { \
  		return -1; \
  	    } \
  	    iol->flags |= FD_NONBLOCKING_SET; \
  	} \
   \
  	/* try writing, ignoring EINTR, the upper layer has to handle \
  	    partial read/writes anyhow, so we can return early */ \
  	do { \
              rv = syscall(iol->fd, arg1, arg2, 0); \
              if (rv == SOCKET_ERROR) { \
                  lasterror = WSAGetLastError(); \
              } \
          } while (rv == SOCKET_ERROR && lasterror == WSAEINTR); \
  	if (rv >= 0) { \
  	    return rv; \
  	} \
  	if (lasterror == WSAEWOULDBLOCK && iol->timeout != 0) { \
  	    return win32_##name##_timeout(viol, arg1, arg2); \
  	} \
  	return -1; \
      } \
  
  method(send, (ap_iol *viol, const char *arg1, int arg2), send, NULL, &fdset)
  //method(writev, (ap_iol *viol, const struct iovec *arg1, int arg2), writev, NULL, &fdset)
  method(recv, (ap_iol *viol, char *arg1, int arg2), recv, &fdset, NULL)
  
  
  #elif defined(IOL_SOCK_WIN32)
  
  static int win32_send(ap_iol *viol, const char *buf, int len)
  {
      int rv;
      int lasterror;    
      iol_socket *iol = (iol_socket *)viol;
      WSABUF wsaData;
  
      wsaData.len = len;
      wsaData.buf = buf;
  
      if (set_nonblock(iol->fd)) { 
          return -1;
      }
  
      do {
          rv = WSASend(iol->fd, &wsaData, 1, &len, 0, NULL, NULL);
          if (rv == SOCKET_ERROR) {
              lasterror = WSAGetLastError();
          } 
      } while (rv == SOCKET_ERROR && lasterror == WSAEINTR);
  
      if (rv == SOCKET_ERROR && lasterror == WSAEWOULDBLOCK && iol->timeout > 0) {
          struct timeval tv;
          fd_set fdset;
          int srv;
  
          do {
              FD_ZERO(&fdset);
              FD_SET(iol->fd, &fdset);
              tv.tv_sec  = iol->timeout;
              tv.tv_usec = 0;
  
              srv = select(FD_SETSIZE, NULL, &fdset, NULL, &tv);
              if (srv == SOCKET_ERROR) {
                  lasterror = WSAGetLastError();
              }
          } while (srv == SOCKET_ERROR && errno == WSAEINTR);
  
          if (srv == 0) {
              return -1;
          }
          if (srv < 0) {
              return -1;
          }
          else {
              do {
                  rv = WSASend(iol->fd, &wsaData, 1, &len, 0, NULL, NULL);
                  if (rv == SOCKET_ERROR) {
                      lasterror = WSAGetLastError();
                  } 
              } while (rv == SOCKET_ERROR && lasterror == WSAEINTR);
          }
      }
      else if (rv == SOCKET_ERROR) {
          len = -1;
      }
  
      return len;
  }
  
  static int win32_recv( ap_iol *viol, const char *buf, int len)
  {
      int rv;
      int lasterror;
      iol_socket *iol = (iol_socket *)viol;
      WSABUF wsaData;
      DWORD dwBytesRecv;
      DWORD flags = 0;
  
      wsaData.len = len;
      wsaData.buf = buf;
  
      if (set_nonblock(iol->fd)) { 
          return -1;
      }
  
      do {
          rv = WSARecv(iol->fd, &wsaData, 1, &dwBytesRecv, &flags, NULL, NULL);
          if (rv == SOCKET_ERROR) {
              lasterror = WSAGetLastError();
          } 
          else
              len = dwBytesRecv;
      } while (rv == SOCKET_ERROR && lasterror == WSAEINTR);
  
      if (rv == SOCKET_ERROR && lasterror == WSAEWOULDBLOCK && iol->timeout > 0) {
          struct timeval tv;
          fd_set fdset;
          int srv;
  
          do {
              FD_ZERO(&fdset);
              FD_SET(iol->fd, &fdset);
              tv.tv_sec  = iol->timeout;
              tv.tv_usec = 0;
  
              srv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
              if (srv == SOCKET_ERROR) {
                  lasterror = WSAGetLastError();
              } 
          } while (srv == SOCKET_ERROR && errno == WSAEINTR);
  
          if (srv == 0) {
              return -1;
          }
          else if (srv < 0) {
              return -1;
          }
          else {
              do {
                  rv = WSARecv(iol->fd, &wsaData, 1, &dwBytesRecv, &flags, NULL, NULL);
                  if (rv == SOCKET_ERROR) {
                      lasterror = WSAGetLastError();
                  } 
                  else
                      len = dwBytesRecv;
              } while (rv == SOCKET_ERROR && lasterror == WSAEINTR);
          }
      }
      else if (rv == SOCKET_ERROR) {
          len = -1;
      }
  
      return len;
  }
  #elif defined(IOL_SOCK_ASYNC)
  
  static int win32_read(ap_iol *viol, const char *buf, int bufSize) 
  {
      int rc;
      iol_socket *iol = (iol_socket *) viol;
  
      DWORD BytesRecvd;
      DWORD flags;
      WSAOVERLAPPED Overlapped;
      WSABUF wsaBuf;
  
      wsaBuf.u_longlen = bufSize;
      wsaBuf.buf = buf;
      
      Overlapped.Internal = ;
      Overlapped.InternalHigh = ;
      Overlapped.Offset = ;
      Overlapped.OffsetHigh = ;
      Overlapped.hEvent = CreateEvent(...);
  
      rc = WSARecv(iol->fd,
                   &wsaBuf,
                   (DWORD) 1,
                   &BytesRecvd,
                   &flags,
                   &Overlapped,
                   NULL); 
      if (rc == SOCKET_ERROR) {
          if (WSAGetLastError() == WSA_IO_PENDING) {
              rc = WSAWaitForMultipleEvents(1,                  // wait for 1 event
                                            &Overlapped.hEvent, 
                                            TRUE,               // wait for all events to be satisfied
                                            (DWORD) iol->timeout, // timeout in milliseconds
                                            FALSE);
              if (rc == WSA_WAIT_FAILED)
          }
          else {
          }
          if (timeout
      }
                               
  }
  #endif
  
  static const ap_iol_methods socket_methods = {
      win32_close,
      win32_send,
      NULL, //win32_writev,
      win32_recv,
      win32_setopt,
      win32_getopt
  };
  
  ap_iol *win32_attach_socket(int fd)
  {
      iol_socket *iol;
  
      iol = malloc(sizeof(iol_socket));
      if (!iol)
          return (ap_iol*) NULL;
      iol->iol.methods = &socket_methods;
      iol->fd = fd;
      iol->timeout = -1;
      iol->flags = 0;
      return (ap_iol *)iol;
  }