forked from Mirrors/openclonk
Add C4NetIOTCP::Bind() for binding without connect
parent
82a43b7cd9
commit
ee34ac1b06
|
@ -1151,20 +1151,77 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd *fds) // (mt-safe)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool C4NetIOTCP::Connect(const C4NetIO::addr_t &addr) // (mt-safe)
|
||||
C4NetIOTCP::Socket::~Socket()
|
||||
{
|
||||
if (sock != INVALID_SOCKET)
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
C4NetIO::addr_t C4NetIOTCP::Socket::GetAddress()
|
||||
{
|
||||
sockaddr_in6 addr;
|
||||
socklen_t address_len = sizeof addr;
|
||||
C4NetIO::addr_t result;
|
||||
if (::getsockname(sock, (sockaddr*) &addr, &address_len) != SOCKET_ERROR)
|
||||
{
|
||||
result.SetAddress((sockaddr*) &addr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SOCKET C4NetIOTCP::CreateSocket(addr_t::AddressFamily family)
|
||||
{
|
||||
// create new socket
|
||||
SOCKET nsock = ::socket(addr.GetFamily() == HostAddress::IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
||||
SOCKET nsock = ::socket(family == HostAddress::IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
||||
if (nsock == INVALID_SOCKET)
|
||||
{
|
||||
SetError("socket creation failed", true);
|
||||
return false;
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (addr.GetFamily() == HostAddress::IPv6)
|
||||
if (family == HostAddress::IPv6)
|
||||
if (!InitIPv6Socket(nsock))
|
||||
return false;
|
||||
{
|
||||
closesocket(nsock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return nsock;
|
||||
}
|
||||
|
||||
std::unique_ptr<C4NetIOTCP::Socket> C4NetIOTCP::Bind(const C4NetIO::addr_t &addr) // (mt-safe)
|
||||
{
|
||||
SOCKET nsock = CreateSocket(addr.GetFamily());
|
||||
if (nsock == INVALID_SOCKET) return nullptr;
|
||||
|
||||
// bind the socket to the given address
|
||||
if (::bind(nsock, &addr, addr.GetAddrLen()) == SOCKET_ERROR)
|
||||
{
|
||||
SetError("binding the socket failed", true);
|
||||
closesocket(nsock);
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<Socket>(new Socket(nsock));
|
||||
}
|
||||
|
||||
bool C4NetIOTCP::Connect(const addr_t &addr, std::unique_ptr<Socket> socket) // (mt-safe)
|
||||
{
|
||||
SOCKET nsock = socket->sock;
|
||||
socket->sock = INVALID_SOCKET;
|
||||
return Connect(addr, nsock);
|
||||
}
|
||||
|
||||
bool C4NetIOTCP::Connect(const C4NetIO::addr_t &addr) // (mt-safe)
|
||||
{
|
||||
// create new socket
|
||||
SOCKET nsock = CreateSocket(addr.GetFamily());
|
||||
if (nsock == INVALID_SOCKET) return false;
|
||||
|
||||
return Connect(addr, nsock);
|
||||
}
|
||||
|
||||
bool C4NetIOTCP::Connect(const C4NetIO::addr_t &addr, SOCKET nsock) // (mt-safe)
|
||||
{
|
||||
#ifdef STDSCHEDULER_USE_EVENTS
|
||||
// set event
|
||||
if (::WSAEventSelect(nsock, Event, FD_CONNECT) == SOCKET_ERROR)
|
||||
|
|
|
@ -338,6 +338,18 @@ public:
|
|||
C4NetIOTCP();
|
||||
~C4NetIOTCP() override;
|
||||
|
||||
// Socket is an unconnected, but bound socket.
|
||||
class Socket
|
||||
{
|
||||
SOCKET sock;
|
||||
Socket(SOCKET s) : sock(s) { }
|
||||
friend class C4NetIOTCP;
|
||||
public:
|
||||
~Socket();
|
||||
// GetAddress returns the address the socket is bound to.
|
||||
C4NetIO::addr_t GetAddress();
|
||||
};
|
||||
|
||||
// *** interface
|
||||
|
||||
// * not multithreading safe
|
||||
|
@ -349,6 +361,8 @@ public:
|
|||
bool Execute(int iMaxTime = TO_INF, pollfd * readyfds = nullptr) override;
|
||||
|
||||
// * multithreading safe
|
||||
std::unique_ptr<Socket> Bind(const addr_t &addr);
|
||||
bool Connect(const addr_t &addr, std::unique_ptr<Socket> socket);
|
||||
bool Connect(const addr_t &addr) override;
|
||||
bool Close(const addr_t &addr) override;
|
||||
|
||||
|
@ -474,6 +488,9 @@ protected:
|
|||
|
||||
bool Listen(uint16_t inListenPort);
|
||||
|
||||
SOCKET CreateSocket(addr_t::AddressFamily family);
|
||||
bool Connect(const addr_t &addr, SOCKET nsock);
|
||||
|
||||
Peer *Accept(SOCKET nsock = INVALID_SOCKET, const addr_t &ConnectAddr = addr_t());
|
||||
Peer *GetPeer(const addr_t &addr);
|
||||
void OnShareFree(CStdCSecEx *pCSec) override;
|
||||
|
|
|
@ -83,3 +83,21 @@ TEST_F(C4NetIOTest, HostAddressCategories)
|
|||
EXPECT_TRUE(check(addr.IsPrivate(), t->priv));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tests C4NetIOTCP::Bind
|
||||
TEST_F(C4NetIOTest, TCPBind)
|
||||
{
|
||||
C4NetIOTCP NetIO;
|
||||
ASSERT_TRUE(NetIO.Init());
|
||||
|
||||
C4NetIO::addr_t addr(StdStrBuf("[::1]:0"));
|
||||
auto socket = NetIO.Bind(addr);
|
||||
ASSERT_NE(socket, nullptr);
|
||||
auto bound_addr = socket->GetAddress();
|
||||
EXPECT_TRUE(bound_addr.IsLoopback());
|
||||
EXPECT_EQ(bound_addr.GetFamily(), C4NetIO::addr_t::IPv6);
|
||||
EXPECT_NE(bound_addr.GetPort(), 0);
|
||||
|
||||
NetIO.Close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue