Skip to content

Commit e361578

Browse files
committed
feat: windows socketpair handling in golang
1 parent cf30891 commit e361578

File tree

5 files changed

+305
-79
lines changed

5 files changed

+305
-79
lines changed

socketpair.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/* socketpair.c
2+
Copyright 2007, 2010 by Nathan C. Myers <[email protected]>
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 <[email protected]>)
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 <string.h>
52+
53+
#ifdef WIN32
54+
# include <ws2tcpip.h> /* socklen_t, et al (MSVC20xx) */
55+
# include <windows.h>
56+
# include <io.h>
57+
#else
58+
# include <sys/types.h>
59+
# include <sys/socket.h>
60+
# include <errno.h>
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

socketpair_handler.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifdef _WIN32
2+
#include "socketpair.c"
3+
#include <winsock2.h>
4+
#include <windows.h>
5+
#include <ws2tcpip.h>
6+
#include <stdio.h>
7+
#endif
8+
9+
int *get_socket_pair() {
10+
#ifdef _WIN32
11+
SOCKET spair[2];
12+
spair[0] = 0;
13+
spair[1] = 0;
14+
if(dumb_socketpair(spair, 1) == SOCKET_ERROR)
15+
fprintf(stderr, "Init failed, creating socketpair: %s\n", strerror(errno));
16+
return spair;
17+
#endif
18+
return -1;
19+
}

socketpair_handler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef SOCKET_H
2+
#define SOCKET_H
3+
4+
int *get_socket_pair();
5+
6+
#endif

0 commit comments

Comments
 (0)