aboutsummaryrefslogtreecommitdiffstats
path: root/util/network/pair.cpp
blob: 2e410b842e337d39b2336732b065192212f55b06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "pair.h" 
 
int SocketPair(SOCKET socks[2], bool overlapped, bool cloexec) {
#if defined(_win_) 
    struct sockaddr_in addr; 
    SOCKET listener; 
    int e; 
    int addrlen = sizeof(addr); 
    DWORD flags = (overlapped ? WSA_FLAG_OVERLAPPED : 0) | (cloexec ? WSA_FLAG_NO_HANDLE_INHERIT : 0);
 
    if (socks == 0) { 
        WSASetLastError(WSAEINVAL); 
 
        return SOCKET_ERROR; 
    } 
 
    socks[0] = INVALID_SOCKET; 
    socks[1] = INVALID_SOCKET; 
 
    if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { 
        return SOCKET_ERROR; 
    } 
 
    memset(&addr, 0, sizeof(addr)); 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = htonl(0x7f000001); 
    addr.sin_port = 0; 
 
    e = bind(listener, (const struct sockaddr*)&addr, sizeof(addr)); 
 
    if (e == SOCKET_ERROR) { 
        e = WSAGetLastError(); 
        closesocket(listener); 
        WSASetLastError(e); 
 
        return SOCKET_ERROR; 
    } 
 
    e = getsockname(listener, (struct sockaddr*)&addr, &addrlen); 
 
    if (e == SOCKET_ERROR) { 
        e = WSAGetLastError(); 
        closesocket(listener); 
        WSASetLastError(e); 
 
        return SOCKET_ERROR; 
    } 
 
    do { 
        if (listen(listener, 1) == SOCKET_ERROR) 
            break; 
 
        if ((socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, nullptr, 0, flags)) == INVALID_SOCKET)
            break; 
 
        if (connect(socks[0], (const struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) 
            break; 
 
        if ((socks[1] = accept(listener, nullptr, nullptr)) == INVALID_SOCKET)
            break; 
 
        closesocket(listener); 
 
        return 0; 
    } while (0); 
 
    e = WSAGetLastError(); 
    closesocket(listener); 
    closesocket(socks[0]); 
    closesocket(socks[1]); 
    WSASetLastError(e); 
 
    return SOCKET_ERROR; 
#else 
    (void)overlapped; 
 
    #if defined(_linux_) 
    return socketpair(AF_LOCAL, SOCK_STREAM | (cloexec ? SOCK_CLOEXEC : 0), 0, socks);
    #else 
    int r = socketpair(AF_LOCAL, SOCK_STREAM, 0, socks);
    // Non-atomic wrt exec
    if (r == 0 && cloexec) {
        for (int i = 0; i < 2; ++i) {
            int flags = fcntl(socks[i], F_GETFD, 0);
            if (flags < 0) {
                return flags;
            }
            r = fcntl(socks[i], F_SETFD, flags | FD_CLOEXEC);
            if (r < 0) {
                return r;
            }
        }
    }
    return r;
    #endif 
#endif 
}