2022-10-26 13:25:11 +02:00
|
|
|
// Copyright (c) 2021-2021 The Bitcoin Core developers
|
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#include <compat.h>
|
|
|
|
#include <test/util/setup_common.h>
|
|
|
|
#include <util/sock.h>
|
|
|
|
#include <util/system.h>
|
|
|
|
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
|
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(sock_tests, BasicTestingSetup)
|
|
|
|
|
|
|
|
static bool SocketIsClosed(const SOCKET& s)
|
|
|
|
{
|
|
|
|
// Notice that if another thread is running and creates its own socket after `s` has been
|
|
|
|
// closed, it may be assigned the same file descriptor number. In this case, our test will
|
|
|
|
// wrongly pretend that the socket is not closed.
|
|
|
|
int type;
|
|
|
|
socklen_t len = sizeof(type);
|
|
|
|
return getsockopt(s, SOL_SOCKET, SO_TYPE, (sockopt_arg_type)&type, &len) == SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SOCKET CreateSocket()
|
|
|
|
{
|
|
|
|
const SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
BOOST_REQUIRE(s != static_cast<SOCKET>(SOCKET_ERROR));
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(constructor_and_destructor)
|
|
|
|
{
|
|
|
|
const SOCKET s = CreateSocket();
|
|
|
|
Sock* sock = new Sock(s);
|
|
|
|
BOOST_CHECK_EQUAL(sock->Get(), s);
|
|
|
|
BOOST_CHECK(!SocketIsClosed(s));
|
|
|
|
delete sock;
|
|
|
|
BOOST_CHECK(SocketIsClosed(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(move_constructor)
|
|
|
|
{
|
|
|
|
const SOCKET s = CreateSocket();
|
|
|
|
Sock* sock1 = new Sock(s);
|
|
|
|
Sock* sock2 = new Sock(std::move(*sock1));
|
|
|
|
delete sock1;
|
|
|
|
BOOST_CHECK(!SocketIsClosed(s));
|
|
|
|
BOOST_CHECK_EQUAL(sock2->Get(), s);
|
|
|
|
delete sock2;
|
|
|
|
BOOST_CHECK(SocketIsClosed(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(move_assignment)
|
|
|
|
{
|
|
|
|
const SOCKET s = CreateSocket();
|
|
|
|
Sock* sock1 = new Sock(s);
|
|
|
|
Sock* sock2 = new Sock();
|
|
|
|
*sock2 = std::move(*sock1);
|
|
|
|
delete sock1;
|
|
|
|
BOOST_CHECK(!SocketIsClosed(s));
|
|
|
|
BOOST_CHECK_EQUAL(sock2->Get(), s);
|
|
|
|
delete sock2;
|
|
|
|
BOOST_CHECK(SocketIsClosed(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(release)
|
|
|
|
{
|
|
|
|
SOCKET s = CreateSocket();
|
|
|
|
Sock* sock = new Sock(s);
|
|
|
|
BOOST_CHECK_EQUAL(sock->Release(), s);
|
|
|
|
delete sock;
|
|
|
|
BOOST_CHECK(!SocketIsClosed(s));
|
|
|
|
BOOST_REQUIRE(CloseSocket(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(reset)
|
|
|
|
{
|
|
|
|
const SOCKET s = CreateSocket();
|
|
|
|
Sock sock(s);
|
|
|
|
sock.Reset();
|
|
|
|
BOOST_CHECK(SocketIsClosed(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef WIN32 // Windows does not have socketpair(2).
|
|
|
|
|
|
|
|
static void CreateSocketPair(int s[2])
|
|
|
|
{
|
|
|
|
BOOST_REQUIRE_EQUAL(socketpair(AF_UNIX, SOCK_STREAM, 0, s), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SendAndRecvMessage(const Sock& sender, const Sock& receiver)
|
|
|
|
{
|
|
|
|
const char* msg = "abcd";
|
2021-02-17 01:06:47 +01:00
|
|
|
constexpr ssize_t msg_len = 4;
|
2022-10-26 13:25:11 +02:00
|
|
|
char recv_buf[10];
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(sender.Send(msg, msg_len, 0), msg_len);
|
|
|
|
BOOST_CHECK_EQUAL(receiver.Recv(recv_buf, sizeof(recv_buf), 0), msg_len);
|
|
|
|
BOOST_CHECK_EQUAL(strncmp(msg, recv_buf, msg_len), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(send_and_receive)
|
|
|
|
{
|
|
|
|
int s[2];
|
|
|
|
CreateSocketPair(s);
|
|
|
|
|
|
|
|
Sock* sock0 = new Sock(s[0]);
|
|
|
|
Sock* sock1 = new Sock(s[1]);
|
|
|
|
|
|
|
|
SendAndRecvMessage(*sock0, *sock1);
|
|
|
|
|
|
|
|
Sock* sock0moved = new Sock(std::move(*sock0));
|
|
|
|
Sock* sock1moved = new Sock();
|
|
|
|
*sock1moved = std::move(*sock1);
|
|
|
|
|
|
|
|
delete sock0;
|
|
|
|
delete sock1;
|
|
|
|
|
|
|
|
SendAndRecvMessage(*sock1moved, *sock0moved);
|
|
|
|
|
|
|
|
delete sock0moved;
|
|
|
|
delete sock1moved;
|
|
|
|
|
|
|
|
BOOST_CHECK(SocketIsClosed(s[0]));
|
|
|
|
BOOST_CHECK(SocketIsClosed(s[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(wait)
|
|
|
|
{
|
|
|
|
int s[2];
|
|
|
|
CreateSocketPair(s);
|
|
|
|
|
|
|
|
Sock sock0(s[0]);
|
|
|
|
Sock sock1(s[1]);
|
|
|
|
|
|
|
|
std::thread waiter([&sock0]() { sock0.Wait(24h, Sock::RECV); });
|
|
|
|
|
|
|
|
BOOST_REQUIRE_EQUAL(sock1.Send("a", 1, 0), 1);
|
|
|
|
|
|
|
|
waiter.join();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|