Add C4NetIOTCP::Bind() for binding without connect

master
Lukas Werling 2018-03-07 17:30:58 +01:00
parent 82a43b7cd9
commit ee34ac1b06
3 changed files with 97 additions and 5 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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();
}