1 /* socketpair.c
2  * Copyright 2007 by Nathan C. Myers <ncm@cantrip.org>; some rights reserved.
3  * This code is Free Software.  It may be copied freely, in original or
4  * modified form, subject only to the restrictions that (1) the author is
5  * relieved from all responsibilities for any use for any purpose, and (2)
6  * this copyright notice must be retained, unchanged, in its entirety.  If
7  * for any reason the author might be held responsible for any consequences
8  * of copying or use, license is withheld.
9  */
10 
11 /*
12  * Licensed to the Apache Software Foundation (ASF) under one
13  * or more contributor license agreements. See the NOTICE file
14  * distributed with this work for additional information
15  * regarding copyright ownership. The ASF licenses this file
16  * to you under the Apache License, Version 2.0 (the
17  * "License"); you may not use this file except in compliance
18  * with the License. You may obtain a copy of the License at
19  *
20  *   http://www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing,
23  * software distributed under the License is distributed on an
24  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
25  * KIND, either express or implied. See the License for the
26  * specific language governing permissions and limitations
27  * under the License.
28  */
29 
30 #include <thrift/windows/SocketPair.h>
31 #include <thrift/Thrift.h>
32 
33 // stl
34 #include <string.h>
35 
36 // Win32
37 #include <WS2tcpip.h>
38 
thrift_socketpair(int d,int type,int protocol,THRIFT_SOCKET sv[2])39 int thrift_socketpair(int d, int type, int protocol, THRIFT_SOCKET sv[2]) {
40   THRIFT_UNUSED_VARIABLE(protocol);
41   THRIFT_UNUSED_VARIABLE(type);
42   THRIFT_UNUSED_VARIABLE(d);
43 
44   union {
45     struct sockaddr_in inaddr;
46     struct sockaddr addr;
47   } a;
48   THRIFT_SOCKET listener;
49   int e;
50   socklen_t addrlen = sizeof(a.inaddr);
51   DWORD flags = 0;
52   int reuse = 1;
53 
54   if (sv == 0) {
55     WSASetLastError(WSAEINVAL);
56     return SOCKET_ERROR;
57   }
58 
59   listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
60   if (listener == INVALID_SOCKET)
61     return SOCKET_ERROR;
62 
63   memset(&a, 0, sizeof(a));
64   a.inaddr.sin_family = AF_INET;
65   a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
66   a.inaddr.sin_port = 0;
67 
68   sv[0] = sv[1] = INVALID_SOCKET;
69   do {
70     // ignore errors coming out of this setsockopt.  This is because
71     // SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
72     // want to force socket pairs to be an admin.
73     setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&reuse, (socklen_t)sizeof(reuse));
74     if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
75       break;
76     if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
77       break;
78     if (listen(listener, 1) == SOCKET_ERROR)
79       break;
80     sv[0] = WSASocket(AF_INET, SOCK_STREAM, 0, nullptr, 0, flags);
81     if (sv[0] == INVALID_SOCKET)
82       break;
83     if (connect(sv[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
84       break;
85     sv[1] = accept(listener, nullptr, nullptr);
86     if (sv[1] == INVALID_SOCKET)
87       break;
88 
89     closesocket(listener);
90     return 0;
91 
92   } while (0);
93 
94   e = WSAGetLastError();
95   closesocket(listener);
96   closesocket(sv[0]);
97   closesocket(sv[1]);
98   WSASetLastError(e);
99   return SOCKET_ERROR;
100 }
101