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 * [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 "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; }