├── Makefile ├── README ├── dummy_headers ├── README ├── io.h ├── windows.h └── ws2tcpip.h └── socketpair.c /Makefile: -------------------------------------------------------------------------------- 1 | # On Windows, add "-DWIN32" 2 | CC=gcc 3 | CFLAGS=-O3 -W -Wall -Wextra 4 | LIB=socketpair 5 | 6 | all: $(LIB).o 7 | 8 | dummy: # test win32 build on unix 9 | $(CC) -DWIN32 $(CFLAGS) -Idummy_headers -c -o $(LIB).dummy $(LIB).c 10 | rm $(LIB).dummy 11 | 12 | clean:; rm $(LIB).o 13 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Windows XP doesn't provide POSIX socketpair(2). Typical workarounds 2 | based on pipes can't be used with win32 select(2). This socketpair is 3 | named a little differently because it offers an extra argument needed 4 | for use in Windows code. The extra argument is ignored on unixy systems. 5 | -------------------------------------------------------------------------------- /dummy_headers/README: -------------------------------------------------------------------------------- 1 | Files in this directory are only used for "make dummy" on *nix. 2 | They are used only to check for gross coding errors when no win32 3 | build environment is immediately available. 4 | -------------------------------------------------------------------------------- /dummy_headers/io.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncm/selectable-socketpair/bd18664090daf125d4e5614b861371a485001a0e/dummy_headers/io.h -------------------------------------------------------------------------------- /dummy_headers/windows.h: -------------------------------------------------------------------------------- 1 | typedef void* SOCKET; 2 | typedef unsigned int DWORD; 3 | #define WSA_FLAG_OVERLAPPED 1 4 | extern void WSASetLastError(int); 5 | extern int WSAGetLastError(); 6 | #define WSAEINVAL 22 7 | #define SOCKET_ERROR -1 8 | #define AF_INET 33 9 | #define SOCK_STREAM 44 10 | #define IPPROTO_TCP 55 11 | #define INVALID_SOCKET 0 12 | extern void* socket(int, int, int); 13 | struct sockaddr_in { 14 | int sin_family; 15 | struct { unsigned s_addr; } sin_addr; 16 | unsigned short sin_port; 17 | }; 18 | struct sockaddr { int dummy; }; 19 | typedef unsigned socklen_t; 20 | #define SOL_SOCKET 66 21 | #define SO_REUSEADDR 77 22 | #define INADDR_LOOPBACK 88 23 | extern int setsockopt(SOCKET, int, int, char*, unsigned); 24 | extern int bind(SOCKET, struct sockaddr*, unsigned); 25 | extern int getsockname(SOCKET, struct sockaddr*, socklen_t*); 26 | extern int listen(SOCKET, int); 27 | extern SOCKET WSASocket(int, int, int, void*, int, int); 28 | extern int connect(SOCKET, struct sockaddr*, unsigned); 29 | extern SOCKET accept(SOCKET, void*, void*); 30 | extern int closesocket(SOCKET); 31 | extern unsigned htonl(unsigned); 32 | -------------------------------------------------------------------------------- /dummy_headers/ws2tcpip.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncm/selectable-socketpair/bd18664090daf125d4e5614b861371a485001a0e/dummy_headers/ws2tcpip.h -------------------------------------------------------------------------------- /socketpair.c: -------------------------------------------------------------------------------- 1 | /* socketpair.c 2 | Copyright 2007, 2010 by Nathan C. Myers 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | The name of the author must not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* Changes: 29 | * 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements 30 | * git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54 31 | * github.com/GerHobbelt/selectable-socketpair 32 | * always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64 33 | * and UNIX/other platforms 34 | * 2013-07-18: Change to BSD 3-clause license 35 | * 2010-03-31: 36 | * set addr to 127.0.0.1 because win32 getsockname does not always set it. 37 | * 2010-02-25: 38 | * set SO_REUSEADDR option to avoid leaking some windows resource. 39 | * Windows System Error 10049, "Event ID 4226 TCP/IP has reached 40 | * the security limit imposed on the number of concurrent TCP connect 41 | * attempts." Bleah. 42 | * 2007-04-25: 43 | * preserve value of WSAGetLastError() on all error returns. 44 | * 2007-04-22: (Thanks to Matthew Gregan ) 45 | * s/EINVAL/WSAEINVAL/ fix trivial compile failure 46 | * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout 47 | * of a child process. 48 | * add argument make_overlapped 49 | */ 50 | 51 | #include 52 | 53 | #ifdef WIN32 54 | # include /* socklen_t, et al (MSVC20xx) */ 55 | # include 56 | # include 57 | #else 58 | # include 59 | # include 60 | # include 61 | #endif 62 | 63 | #ifdef WIN32 64 | 65 | /* dumb_socketpair: 66 | * If make_overlapped is nonzero, both sockets created will be usable for 67 | * "overlapped" operations via WSASend etc. If make_overlapped is zero, 68 | * socks[0] (only) will be usable with regular ReadFile etc., and thus 69 | * suitable for use as stdin or stdout of a child process. Note that the 70 | * sockets must be closed with closesocket() regardless. 71 | */ 72 | 73 | int dumb_socketpair(SOCKET socks[2], int make_overlapped) 74 | { 75 | union { 76 | struct sockaddr_in inaddr; 77 | struct sockaddr addr; 78 | } a; 79 | SOCKET listener; 80 | int e; 81 | socklen_t addrlen = sizeof(a.inaddr); 82 | DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0); 83 | int reuse = 1; 84 | 85 | if (socks == 0) { 86 | WSASetLastError(WSAEINVAL); 87 | return SOCKET_ERROR; 88 | } 89 | socks[0] = socks[1] = -1; 90 | 91 | listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 92 | if (listener == -1) 93 | return SOCKET_ERROR; 94 | 95 | memset(&a, 0, sizeof(a)); 96 | a.inaddr.sin_family = AF_INET; 97 | a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 98 | a.inaddr.sin_port = 0; 99 | 100 | for (;;) { 101 | if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, 102 | (char*) &reuse, (socklen_t) sizeof(reuse)) == -1) 103 | break; 104 | if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) 105 | break; 106 | 107 | memset(&a, 0, sizeof(a)); 108 | if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) 109 | break; 110 | // win32 getsockname may only set the port number, p=0.0005. 111 | // ( http://msdn.microsoft.com/library/ms738543.aspx ): 112 | a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 113 | a.inaddr.sin_family = AF_INET; 114 | 115 | if (listen(listener, 1) == SOCKET_ERROR) 116 | break; 117 | 118 | socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); 119 | if (socks[0] == -1) 120 | break; 121 | if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) 122 | break; 123 | 124 | socks[1] = accept(listener, NULL, NULL); 125 | if (socks[1] == -1) 126 | break; 127 | 128 | closesocket(listener); 129 | return 0; 130 | } 131 | 132 | e = WSAGetLastError(); 133 | closesocket(listener); 134 | closesocket(socks[0]); 135 | closesocket(socks[1]); 136 | WSASetLastError(e); 137 | socks[0] = socks[1] = -1; 138 | return SOCKET_ERROR; 139 | } 140 | #else 141 | int dumb_socketpair(int socks[2], int dummy) 142 | { 143 | if (socks == 0) { 144 | errno = EINVAL; 145 | return -1; 146 | } 147 | dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, socks); 148 | if (dummy) 149 | socks[0] = socks[1] = -1; 150 | return dummy; 151 | } 152 | #endif 153 | --------------------------------------------------------------------------------