initial load of upstream version 1.06.32
[xmlrpc-c] / lib / abyss / src / socket_win.c
diff --git a/lib/abyss/src/socket_win.c b/lib/abyss/src/socket_win.c
new file mode 100644 (file)
index 0000000..058c322
--- /dev/null
@@ -0,0 +1,456 @@
+/*=============================================================================\r
+                                 socket_win.c\r
+===============================================================================\r
+  This is the implementation of TSocket for a Windows Winsock socket.\r
+=============================================================================*/\r
+\r
+#include "xmlrpc_config.h"\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <assert.h>\r
+#include <winsock.h>\r
+\r
+#include "xmlrpc-c/util_int.h"\r
+#include "mallocvar.h"\r
+#include "trace.h"\r
+\r
+#include "socket.h"\r
+\r
+\r
+struct socketWin {\r
+/*----------------------------------------------------------------------------\r
+   The properties/state of a TSocket unique to a Unix TSocket.\r
+-----------------------------------------------------------------------------*/\r
+    SOCKET fd;\r
+    abyss_bool userSuppliedWinsock;\r
+        /* 'socket' was supplied by the user; it belongs to him */\r
+};\r
+\r
+\r
+\r
+void\r
+SocketWinInit(abyss_bool * const succeededP) {\r
+\r
+    WORD wVersionRequested;\r
+    WSADATA wsaData;\r
+    int err;\r
+\r
+    wVersionRequested = MAKEWORD(2, 0);\r
+\r
+    err = WSAStartup(wVersionRequested, &wsaData);\r
+    *succeededP = (err == 0);\r
+}\r
+\r
+\r
+\r
+void\r
+SocketWinTerm(void) {\r
+\r
+    WSACleanup();\r
+}\r
+\r
+\r
+\r
+static SocketDestroyImpl            socketDestroy;\r
+static SocketWriteImpl              socketWrite;\r
+static SocketReadImpl               socketRead;\r
+static SocketConnectImpl            socketConnect;\r
+static SocketBindImpl               socketBind;\r
+static SocketListenImpl             socketListen;\r
+static SocketAcceptImpl             socketAccept;\r
+static SocketErrorImpl              socketError;\r
+static SocketWaitImpl               socketWait;\r
+static SocketAvailableReadBytesImpl socketAvailableReadBytes;\r
+static SocketGetPeerNameImpl        socketGetPeerName;\r
+\r
+\r
+static struct TSocketVtbl const vtbl = {\r
+    &socketDestroy,\r
+    &socketWrite,\r
+    &socketRead,\r
+    &socketConnect,\r
+    &socketBind,\r
+    &socketListen,\r
+    &socketAccept,\r
+    &socketError,\r
+    &socketWait,\r
+    &socketAvailableReadBytes,\r
+    &socketGetPeerName\r
+};\r
+\r
+\r
+\r
+void\r
+SocketWinCreate(TSocket ** const socketPP) {\r
+\r
+    struct socketWin * socketWinP;\r
+\r
+    MALLOCVAR(socketWinP);\r
+\r
+    if (socketWinP) {\r
+        SOCKET rc;\r
+        rc = socket(AF_INET, SOCK_STREAM, 0);\r
+        if (rc < 0)\r
+            *socketPP = NULL;\r
+        else {\r
+            socketWinP->fd = rc;\r
+            socketWinP->userSuppliedWinsock = FALSE;\r
+\r
+            {\r
+                int32_t n = 1;\r
+                int rc;\r
+                rc = setsockopt(socketWinP->fd, SOL_SOCKET, SO_REUSEADDR,\r
+                                (char*)&n, sizeof(n));\r
+                if (rc < 0)\r
+                    *socketPP = NULL;\r
+                else\r
+                    SocketCreate(&vtbl, socketWinP, socketPP);\r
+            }\r
+            if (!*socketPP)\r
+                closesocket(socketWinP->fd);\r
+        }\r
+        if (!*socketPP)\r
+            free(socketWinP);\r
+    } else\r
+        *socketPP = NULL;\r
+}\r
+\r
+\r
+\r
+void\r
+SocketWinCreateWinsock(SOCKET     const winsock,\r
+                       TSocket ** const socketPP) {\r
+\r
+    struct socketWin * socketWinP;\r
+\r
+    MALLOCVAR(socketWinP);\r
+\r
+    if (socketWinP) {\r
+        socketWinP->fd = winsock;\r
+        socketWinP->userSuppliedWinsock = TRUE;\r
+\r
+        SocketCreate(&vtbl, socketWinP, socketPP);\r
+\r
+        if (!*socketPP)\r
+            free(socketWinP);\r
+    } else\r
+        *socketPP = NULL;\r
+}\r
+\r
+\r
+\r
+void\r
+socketDestroy(TSocket * const socketP) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    if (!socketWinP->userSuppliedWinsock)\r
+        closesocket(socketWinP->fd);\r
+\r
+    free(socketWinP);\r
+}\r
+\r
+\r
+\r
+void\r
+socketWrite(TSocket *             const socketP,\r
+            const unsigned char * const buffer,\r
+            uint32_t              const len,\r
+            abyss_bool *          const failedP) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    size_t bytesLeft;\r
+    abyss_bool error;\r
+\r
+    assert(sizeof(size_t) >= sizeof(len));\r
+\r
+    for (bytesLeft = len, error = FALSE;\r
+         bytesLeft > 0 && !error;\r
+        ) {\r
+        size_t const maxSend = (size_t)(-1) >> 1;\r
+\r
+        int rc;\r
+\r
+        rc = send(socketWinP->fd, &buffer[len-bytesLeft],\r
+                  MIN(maxSend, bytesLeft), 0);\r
+\r
+        if (rc <= 0)\r
+            /* 0 means connection closed; < 0 means severe error */\r
+            error = TRUE;\r
+        else\r
+            bytesLeft -= rc;\r
+    }\r
+    *failedP = error;\r
+}\r
+\r
+\r
+\r
+uint32_t\r
+socketRead(TSocket * const socketP,\r
+           char *    const buffer,\r
+           uint32_t  const len) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    int rc;\r
+    rc = recv(socketWinP->fd, buffer, len, 0);\r
+    return rc;\r
+}\r
+\r
+\r
+\r
+abyss_bool\r
+socketConnect(TSocket * const socketP,\r
+              TIPAddr * const addrP,\r
+              uint16_t  const portNumber) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    struct sockaddr_in name;\r
+    int rc;\r
+\r
+    name.sin_family = AF_INET;\r
+    name.sin_port = htons(portNumber);\r
+    name.sin_addr = *addrP;\r
+\r
+    rc = connect(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));\r
+\r
+    return rc != -1;\r
+}\r
+\r
+\r
+\r
+abyss_bool\r
+socketBind(TSocket * const socketP,\r
+           TIPAddr * const addrP,\r
+           uint16_t  const portNumber) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    struct sockaddr_in name;\r
+    int rc;\r
+\r
+    name.sin_family = AF_INET;\r
+    name.sin_port   = htons(portNumber);\r
+    if (addrP)\r
+        name.sin_addr = *addrP;\r
+    else\r
+        name.sin_addr.s_addr = INADDR_ANY;\r
+\r
+    rc = bind(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));\r
+\r
+    return (rc != -1);\r
+}\r
+\r
+\r
+\r
+abyss_bool\r
+socketListen(TSocket * const socketP,\r
+             uint32_t  const backlog) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    int32_t const minus1 = -1;\r
+\r
+    int rc;\r
+\r
+    /* Disable the Nagle algorithm to make persistant connections faster */\r
+\r
+    setsockopt(socketWinP->fd, IPPROTO_TCP,TCP_NODELAY,\r
+               (const char *)&minus1, sizeof(minus1));\r
+\r
+    rc = listen(socketWinP->fd, backlog);\r
+\r
+    return (rc != -1);\r
+}\r
+\r
+\r
+\r
+static void\r
+socketAccept(TSocket *    const listenSocketP,\r
+             abyss_bool * const connectedP,\r
+             abyss_bool * const failedP,\r
+             TSocket **   const acceptedSocketPP,\r
+             TIPAddr *    const ipAddrP) {\r
+/*----------------------------------------------------------------------------\r
+   Accept a connection on the listening socket 'listenSocketP'.  Return as\r
+   *acceptedSocketPP the socket for the accepted connection.\r
+\r
+   If no connection is waiting on 'listenSocketP', wait until one is.\r
+\r
+   If we receive a signal while waiting, return immediately.\r
+\r
+   Return *connectedP true iff we accepted a connection.  Return\r
+   *failedP true iff we were unable to accept a connection for some\r
+   reason other than that we were interrupted.  Return both false if\r
+   our wait for a connection was interrupted by a signal.\r
+-----------------------------------------------------------------------------*/\r
+    struct socketWin * const listenSocketWinP = listenSocketP->implP;\r
+\r
+    abyss_bool connected, failed, interrupted;\r
+\r
+    connected   = FALSE;\r
+    failed      = FALSE;\r
+    interrupted = FALSE;\r
+\r
+    while (!connected && !failed && !interrupted) {\r
+        struct sockaddr_in sa;\r
+        socklen_t size = sizeof(sa);\r
+        int rc;\r
+        rc = accept(listenSocketWinP->fd, (struct sockaddr *)&sa, &size);\r
+        if (rc >= 0) {\r
+            SOCKET const acceptedWinsock = rc;\r
+            struct socketWin * acceptedSocketWinP;\r
+\r
+            MALLOCVAR(acceptedSocketWinP);\r
+\r
+            if (acceptedSocketWinP) {\r
+                acceptedSocketWinP->fd = acceptedWinsock;\r
+                acceptedSocketWinP->userSuppliedWinsock = FALSE;\r
+\r
+                SocketCreate(&vtbl, acceptedSocketWinP, acceptedSocketPP);\r
+                if (!*acceptedSocketPP)\r
+                    failed = TRUE;\r
+                else {\r
+                    connected = TRUE;\r
+                    *ipAddrP = sa.sin_addr;\r
+                }\r
+                if (failed)\r
+                    free(acceptedSocketWinP);\r
+            } else\r
+                failed = TRUE;\r
+            if (failed)\r
+                closesocket(acceptedWinsock);\r
+        } else if (socketError(NULL) == WSAEINTR)\r
+            interrupted = TRUE;\r
+        else\r
+            failed = TRUE;\r
+    }\r
+    *failedP    = failed;\r
+    *connectedP = connected;\r
+}\r
+\r
+\r
+\r
+static uint32_t\r
+socketWait(TSocket *  const socketP,\r
+           abyss_bool const rd,\r
+           abyss_bool const wr,\r
+           uint32_t   const timems) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    fd_set rfds, wfds;\r
+    TIMEVAL tv;\r
+\r
+    FD_ZERO(&rfds);\r
+    FD_ZERO(&wfds);\r
+\r
+    if (rd)\r
+        FD_SET(socketWinP->fd, &rfds);\r
+\r
+    if (wr)\r
+        FD_SET(socketWinP->fd, &wfds);\r
+\r
+    tv.tv_sec  = timems / 1000;\r
+    tv.tv_usec = timems % 1000;\r
+\r
+    for (;;) {\r
+        int rc;\r
+\r
+        rc = select(socketWinP->fd + 1, &rfds, &wfds, NULL,\r
+                    (timems == TIME_INFINITE ? NULL : &tv));\r
+\r
+        switch(rc) {\r
+        case 0: /* time out */\r
+            return 0;\r
+\r
+        case -1:  /* socket error */\r
+            if (socketError(NULL) == WSAEINTR)\r
+                break;\r
+\r
+            return 0;\r
+\r
+        default:\r
+            if (FD_ISSET(socketWinP->fd, &rfds))\r
+                return 1;\r
+            if (FD_ISSET(socketWinP->fd, &wfds))\r
+                return 2;\r
+            return 0;\r
+        }\r
+    }\r
+}\r
+\r
+\r
+\r
+static uint32_t\r
+socketAvailableReadBytes(TSocket * const socketP) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    uint32_t x;\r
+    int rc;\r
+\r
+    rc = ioctlsocket(socketWinP->fd, FIONREAD, &x);\r
+\r
+    return rc == 0 ? x : 0;\r
+}\r
+\r
+\r
+\r
+static void\r
+socketGetPeerName(TSocket *    const socketP,\r
+                  TIPAddr *    const ipAddrP,\r
+                  uint16_t *   const portNumberP,\r
+                  abyss_bool * const successP) {\r
+\r
+    struct socketWin * const socketWinP = socketP->implP;\r
+\r
+    socklen_t addrlen;\r
+    int rc;\r
+    struct sockaddr sockAddr;\r
+\r
+    addrlen = sizeof(sockAddr);\r
+\r
+    rc = getpeername(socketWinP->fd, &sockAddr, &addrlen);\r
+\r
+    if (rc < 0) {\r
+        TraceMsg("getpeername() failed.  errno=%d (%s)",\r
+                 errno, strerror(errno));\r
+        *successP = FALSE;\r
+    } else {\r
+        if (addrlen != sizeof(sockAddr)) {\r
+            TraceMsg("getpeername() returned a socket address of the wrong "\r
+                     "size: %u.  Expected %u", addrlen, sizeof(sockAddr));\r
+            *successP = FALSE;\r
+        } else {\r
+            if (sockAddr.sa_family != AF_INET) {\r
+                TraceMsg("Socket does not use the Inet (IP) address "\r
+                         "family.  Instead it uses family %d",\r
+                         sockAddr.sa_family);\r
+                *successP = FALSE;\r
+            } else {\r
+                struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)\r
+                    &sockAddr;\r
+\r
+                *ipAddrP     = sockAddrInP->sin_addr;\r
+                *portNumberP = sockAddrInP->sin_port;\r
+\r
+                *successP = TRUE;\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+\r
+\r
+static uint32_t\r
+socketError(TSocket * const socketP) {\r
+    return (uint32_t)WSAGetLastError();\r
+}\r
+\r
+\r
+\r