--- /dev/null
+/*=============================================================================\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