--- /dev/null
+/*\r
+ * This file contains all winsock-related stuff.\r
+ * Socketpair() for winsock is implemented here.\r
+ * There are also functions to create a non-overlapped socket (which windows normally doesn't do)\r
+ * and to create a socketpair that has one synchronous and one async socket.\r
+ * Synchronous sockets are required because async sockets can't be used by child processes.\r
+ */\r
+\r
+\r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include <mswsock.h>\r
+#include <ws2tcpip.h>\r
+#include <ws2spi.h>\r
+#include <platform_win32_winsock.h>\r
+\r
+\r
+namespace node {\r
+\r
+\r
+/*\r
+ * Winsock version data goes here\r
+ */\r
+static WSAData winsock_info;\r
+\r
+\r
+/*\r
+ * Cache for WSAPROTOCOL_INFOW structures for protocols used in node\r
+ * [0] TCP/IP\r
+ * [1] UDP/IP\r
+ * [2] TCP/IPv6\r
+ * [3] UDP/IPv6\r
+ */\r
+static WSAPROTOCOL_INFOW proto_info_cache[4];\r
+\r
+\r
+/*\r
+ * Does the about the same as perror(), but for winsock errors\r
+ */\r
+void wsa_perror(const char *prefix) {\r
+ DWORD errorno = WSAGetLastError();\r
+ char *errmsg;\r
+\r
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\r
+ NULL, errorno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errmsg, 0, NULL);\r
+\r
+ // FormatMessage messages include a newline character\r
+\r
+ if (prefix) {\r
+ fprintf(stderr, "%s: %s", prefix, errmsg);\r
+ } else {\r
+ fputs(errmsg, stderr);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * Retrieves a pointer to a WSAPROTOCOL_INFOW structure\r
+ * related to a certain winsock protocol from the cache\r
+ */\r
+inline static WSAPROTOCOL_INFOW *wsa_get_cached_proto_info(int af, int type, int proto) {\r
+ assert(proto == IPPROTO_IP\r
+ || proto == IPPROTO_TCP\r
+ || proto == IPPROTO_UDP);\r
+\r
+ switch (af) {\r
+ case AF_INET:\r
+ switch (type) {\r
+ case SOCK_STREAM:\r
+ return &proto_info_cache[0];\r
+ case SOCK_DGRAM:\r
+ return &proto_info_cache[1];\r
+ }\r
+ break;\r
+\r
+ case AF_INET6:\r
+ switch (type) {\r
+ case SOCK_STREAM:\r
+ return &proto_info_cache[2];\r
+ case SOCK_DGRAM:\r
+ return &proto_info_cache[3];\r
+ }\r
+ break;\r
+ }\r
+\r
+ WSASetLastError(WSAEPROTONOSUPPORT);\r
+ return NULL;\r
+}\r
+\r
+\r
+/*\r
+ * Creates a synchronous, non-overlapped socket.\r
+ * (The sockets that are created with socket() or accept() are always in overlapped mode.)\r
+ * Doubles the winsock api, e.g. returns a SOCKET handle, not an FD\r
+ */\r
+SOCKET wsa_sync_socket(int af, int type, int proto) {\r
+ WSAPROTOCOL_INFOW *protoInfo = wsa_get_cached_proto_info(af, type, proto);\r
+ if (protoInfo == NULL)\r
+ return INVALID_SOCKET;\r
+\r
+ return WSASocketW(af, type, proto, protoInfo, 0, 0);\r
+}\r
+\r
+\r
+/*\r
+ * Create a socketpair using the protocol specified\r
+ * This function uses winsock semantics, it returns SOCKET handles, not FDs\r
+ * Currently supports TCP/IPv4 socket pairs only\r
+ */\r
+int wsa_socketpair(int af, int type, int proto, SOCKET sock[2]) {\r
+ assert(af == AF_INET\r
+ && type == SOCK_STREAM\r
+ && (proto == IPPROTO_IP || proto == IPPROTO_TCP));\r
+\r
+ SOCKET listen_sock;\r
+ SOCKADDR_IN addr1;\r
+ SOCKADDR_IN addr2;\r
+ int addr1_len = sizeof (addr1);\r
+ int addr2_len = sizeof (addr2);\r
+ sock[1] = INVALID_SOCKET;\r
+ sock[2] = INVALID_SOCKET;\r
+\r
+ if ((listen_sock = socket(af, type, proto)) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ memset((void*)&addr1, 0, sizeof(addr1));\r
+ addr1.sin_family = af;\r
+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);\r
+ addr1.sin_port = 0;\r
+\r
+ if (bind(listen_sock, (SOCKADDR*)&addr1, addr1_len) == SOCKET_ERROR)\r
+ goto error;\r
+\r
+ if (getsockname(listen_sock, (SOCKADDR*)&addr1, &addr1_len) == SOCKET_ERROR)\r
+ goto error;\r
+\r
+ if (listen(listen_sock, 1))\r
+ goto error;\r
+\r
+ if ((sock[0] = socket(af, type, proto)) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (connect(sock[0], (SOCKADDR*)&addr1, addr1_len))\r
+ goto error;\r
+\r
+ if ((sock[1] = accept(listen_sock, 0, 0)) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (getpeername(sock[0], (SOCKADDR*)&addr1, &addr1_len) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (getsockname(sock[1], (SOCKADDR*)&addr2, &addr2_len) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (addr1_len != addr2_len\r
+ || addr1.sin_addr.s_addr != addr2.sin_addr.s_addr\r
+ || addr1.sin_port != addr2.sin_port)\r
+ goto error;\r
+\r
+ closesocket(listen_sock);\r
+\r
+ return 0;\r
+\r
+error:\r
+ int error = WSAGetLastError();\r
+\r
+ if (listen_sock != INVALID_SOCKET)\r
+ closesocket(listen_sock);\r
+\r
+ if (sock[0] != INVALID_SOCKET)\r
+ closesocket(sock[0]);\r
+\r
+ if (sock[1] != INVALID_SOCKET)\r
+ closesocket(sock[1]);\r
+\r
+ WSASetLastError(error);\r
+\r
+ return SOCKET_ERROR;\r
+}\r
+\r
+\r
+/*\r
+ * Create a sync-async socketpair using the protocol specified,\r
+ * returning a synchronous socket and an asynchronous socket.\r
+ * Upon completion asyncSocket is opened with the WSA_FLAG_OVERLAPPED flag set,\r
+ * syncSocket won't have it set.\r
+ * Currently supports TCP/IPv4 socket pairs only\r
+ */\r
+int wsa_sync_async_socketpair(int af, int type, int proto, SOCKET *syncSocket, SOCKET *asyncSocket) {\r
+ assert(af == AF_INET\r
+ && type == SOCK_STREAM\r
+ && (proto == IPPROTO_IP || proto == IPPROTO_TCP));\r
+\r
+ SOCKET listen_sock;\r
+ SOCKET sock1 = INVALID_SOCKET;\r
+ SOCKET sock2 = INVALID_SOCKET;\r
+ SOCKADDR_IN addr1;\r
+ SOCKADDR_IN addr2;\r
+ int addr1_len = sizeof (addr1);\r
+ int addr2_len = sizeof (addr2);\r
+\r
+ if ((listen_sock = socket(af, type, proto)) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ memset((void*)&addr1, 0, sizeof(addr1));\r
+ addr1.sin_family = af;\r
+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);\r
+ addr1.sin_port = 0;\r
+\r
+ if (bind(listen_sock, (SOCKADDR*)&addr1, addr1_len) == SOCKET_ERROR)\r
+ goto error;\r
+\r
+ if (getsockname(listen_sock, (SOCKADDR*)&addr1, &addr1_len) == SOCKET_ERROR)\r
+ goto error;\r
+\r
+ if (listen(listen_sock, 1))\r
+ goto error;\r
+\r
+ if ((sock1 = wsa_sync_socket(af, type, proto)) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (connect(sock1, (SOCKADDR*)&addr1, addr1_len))\r
+ goto error;\r
+\r
+ if ((sock2 = accept(listen_sock, 0, 0)) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (getpeername(sock1, (SOCKADDR*)&addr1, &addr1_len) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (getsockname(sock2, (SOCKADDR*)&addr2, &addr2_len) == INVALID_SOCKET)\r
+ goto error;\r
+\r
+ if (addr1_len != addr2_len\r
+ || addr1.sin_addr.s_addr != addr2.sin_addr.s_addr\r
+ || addr1.sin_port != addr2.sin_port)\r
+ goto error;\r
+\r
+ closesocket(listen_sock);\r
+\r
+ *syncSocket = sock1;\r
+ *asyncSocket = sock2;\r
+\r
+ return 0;\r
+\r
+error:\r
+ int error = WSAGetLastError();\r
+\r
+ if (listen_sock != INVALID_SOCKET)\r
+ closesocket(listen_sock);\r
+\r
+ if (sock1 != INVALID_SOCKET)\r
+ closesocket(sock1);\r
+\r
+ if (sock2 != INVALID_SOCKET)\r
+ closesocket(sock2);\r
+\r
+ WSASetLastError(error);\r
+\r
+ return SOCKET_ERROR;\r
+}\r
+\r
+\r
+/*\r
+ * Retrieves a WSAPROTOCOL_INFOW structure for a certain protocol\r
+ */\r
+static void wsa_get_proto_info(int af, int type, int proto, WSAPROTOCOL_INFOW *target) {\r
+ WSAPROTOCOL_INFOW *info_buffer = NULL;\r
+ unsigned long info_buffer_length = 0;\r
+ int protocol_count, i, error;\r
+\r
+ if (WSCEnumProtocols(NULL, NULL, &info_buffer_length, &error) != SOCKET_ERROR) {\r
+ error = WSAEOPNOTSUPP;\r
+ goto error;\r
+ }\r
+\r
+ info_buffer = (WSAPROTOCOL_INFOW *)malloc(info_buffer_length);\r
+\r
+ if ((protocol_count = WSCEnumProtocols(NULL, info_buffer, &info_buffer_length, &error)) == SOCKET_ERROR)\r
+ goto error;\r
+\r
+ for (i = 0; i < protocol_count; i++) {\r
+ if (af == info_buffer[i].iAddressFamily\r
+ && type == info_buffer[i].iSocketType\r
+ && proto == info_buffer[i].iProtocol\r
+ && info_buffer[i].dwServiceFlags1 & XP1_IFS_HANDLES) {\r
+ memcpy(target, (WSAPROTOCOL_INFOW*)&info_buffer[i], sizeof(WSAPROTOCOL_INFOW));\r
+ free(info_buffer);\r
+ return;\r
+ }\r
+ }\r
+\r
+ error = WSAEPROTONOSUPPORT;\r
+\r
+error:\r
+ WSASetLastError(error);\r
+ wsa_perror("Error obtaining winsock protocol information");\r
+\r
+ if (info_buffer != NULL) {\r
+ free(info_buffer);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * Initializes (fills) the WSAPROTOCOL_INFOW structure cache\r
+ */\r
+static void wsa_init_proto_info_cache() {\r
+ WSAPROTOCOL_INFOW *cache = (WSAPROTOCOL_INFOW*)&proto_info_cache;\r
+\r
+ wsa_get_proto_info(AF_INET, SOCK_STREAM, IPPROTO_TCP, &proto_info_cache[0]);\r
+ wsa_get_proto_info(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &proto_info_cache[1]);\r
+ wsa_get_proto_info(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &proto_info_cache[2]);\r
+ wsa_get_proto_info(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &proto_info_cache[3]);\r
+}\r
+\r
+\r
+/*\r
+ * Initializes winsock and winsock-related stuff\r
+ */\r
+void wsa_init() {\r
+ WORD version = MAKEWORD(2, 2);\r
+ if (WSAStartup(version, &winsock_info)) {\r
+ wsa_perror("WSAStartup");\r
+ }\r
+\r
+ wsa_init_proto_info_cache();\r
+}\r
+\r
+\r
+} // namespace node\r