Commit ab129b5e authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

copy socketpair for win32 from libevent and tor

Summary: Rather than conditionally depending on libevent in a way which is causing downstream conflicts.

Reviewed By: Orvid

Differential Revision: D27121200

fbshipit-source-id: 4c4816e7cb2061718f81cd8a75ce4999b5b32042
parent 163f3c3a
......@@ -22,15 +22,11 @@
#include <cstddef>
#include <stdexcept>
#include <folly/Portability.h>
#include <folly/ScopeGuard.h>
#include <folly/net/detail/SocketFileDescriptorMap.h>
#ifdef _WIN32
#include <event2/util.h> // @manual
#include <MSWSock.h> // @manual
#include <folly/ScopeGuard.h>
#endif
#if !FOLLY_HAVE_RECVMMSG
......@@ -545,13 +541,126 @@ NetworkSocket socket(int af, int type, int protocol) {
#endif
}
#ifdef _WIN32
// adapted from like code in libevent, itself adapted from like code in tor
//
// from: https://github.com/libevent/libevent/tree/release-2.1.12-stable
// license: 3-Clause BSD
static int socketpair_win32(
int family, int type, int protocol, intptr_t fd[2]) {
intptr_t listener = -1;
intptr_t connector = -1;
intptr_t acceptor = -1;
struct sockaddr_in listen_addr;
struct sockaddr_in connect_addr;
int size;
int saved_errno = -1;
int family_test;
family_test = family != AF_INET && (family != AF_UNIX);
if (protocol || family_test) {
WSASetLastError(WSAEAFNOSUPPORT);
return -1;
}
if (!fd) {
WSASetLastError(WSAEINVAL);
return -1;
}
listener = ::socket(AF_INET, type, 0);
if (listener < 0) {
return -1;
}
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
listen_addr.sin_port = 0; /* kernel chooses port. */
if (::bind(listener, (struct sockaddr*)&listen_addr, sizeof(listen_addr)) ==
-1) {
goto tidy_up_and_fail;
}
if (::listen(listener, 1) == -1) {
goto tidy_up_and_fail;
}
connector = ::socket(AF_INET, type, 0);
if (connector < 0) {
goto tidy_up_and_fail;
}
memset(&connect_addr, 0, sizeof(connect_addr));
/* We want to find out the port number to connect to. */
size = sizeof(connect_addr);
if (::getsockname(listener, (struct sockaddr*)&connect_addr, &size) == -1) {
goto tidy_up_and_fail;
}
if (size != sizeof(connect_addr)) {
goto abort_tidy_up_and_fail;
}
if (::connect(
connector, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) ==
-1) {
goto tidy_up_and_fail;
}
size = sizeof(listen_addr);
acceptor = ::accept(listener, (struct sockaddr*)&listen_addr, &size);
if (acceptor < 0) {
goto tidy_up_and_fail;
}
if (size != sizeof(listen_addr)) {
goto abort_tidy_up_and_fail;
}
/* Now check we are talking to ourself by matching port and host on the
two sockets. */
if (::getsockname(connector, (struct sockaddr*)&connect_addr, &size) == -1) {
goto tidy_up_and_fail;
}
if (size != sizeof(connect_addr) ||
listen_addr.sin_family != connect_addr.sin_family ||
listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr ||
listen_addr.sin_port != connect_addr.sin_port) {
goto abort_tidy_up_and_fail;
}
::closesocket(listener);
fd[0] = connector;
fd[1] = acceptor;
return 0;
abort_tidy_up_and_fail:
saved_errno = WSAECONNABORTED;
tidy_up_and_fail:
if (saved_errno < 0) {
saved_errno = WSAGetLastError();
}
if (listener != -1) {
::closesocket(listener);
}
if (connector != -1) {
::closesocket(connector);
}
if (acceptor != -1) {
::closesocket(acceptor);
}
WSASetLastError(saved_errno);
return -1;
}
#endif
int socketpair(int domain, int type, int protocol, NetworkSocket sv[2]) {
#ifdef _WIN32
if (domain != PF_UNIX || type != SOCK_STREAM || protocol != 0) {
return -1;
}
intptr_t pair[2];
auto r = evutil_socketpair(AF_INET, type, protocol, pair);
auto r = socketpair_win32(AF_INET, type, protocol, pair);
if (r == -1) {
return r;
}
......
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/net/NetOps.h>
#include <glog/logging.h>
#include <folly/net/NetworkSocket.h>
#include <folly/portability/GTest.h>
class NetOpsTest : public testing::Test {};
TEST_F(NetOpsTest, socketpair) {
folly::NetworkSocket pair[2];
PCHECK(0 == folly::netops::socketpair(AF_UNIX, SOCK_STREAM, 0, pair));
std::string const textw = "hello world";
PCHECK(
long(textw.size()) ==
folly::netops::send(pair[0], textw.data(), textw.size(), 0));
std::string textr(100, '\0');
PCHECK(
long(textw.size()) ==
folly::netops::recv(pair[1], &textr[0], textr.size(), 0));
textr.resize(textw.size());
EXPECT_EQ(textw, textr);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment