enh(Net): Allow passing raw fd's into ServerSocket (#4156)

* Allow creating ServerSocket's from fd's
* more sensible approach
* fix whitespace issue
* add test
* build fixes for windows
This commit is contained in:
Russell Greene 2023-12-04 08:53:40 -07:00 committed by GitHub
parent 94418e5bc8
commit 3ae282db2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 102 additions and 0 deletions

View File

@ -60,6 +60,10 @@ public:
/// After successful construction, the server socket /// After successful construction, the server socket
/// is ready to accept connections. /// is ready to accept connections.
static ServerSocket fromFileDescriptor(poco_socket_t fd);
// Creates a socket from an existing file descriptor.
// Ownership is taken by poco
virtual ~ServerSocket(); virtual ~ServerSocket();
/// Destroys the ServerSocket. /// Destroys the ServerSocket.

View File

@ -85,6 +85,10 @@ public:
#endif // POCO_NEW_STATE_ON_MOVE #endif // POCO_NEW_STATE_ON_MOVE
static Socket fromFileDescriptor(poco_socket_t fd);
// Creates a socket from an existing file descriptor.
// Ownership is taken by poco
virtual ~Socket(); virtual ~Socket();
/// Destroys the Socket and releases the /// Destroys the Socket and releases the
/// SocketImpl. /// SocketImpl.

View File

@ -142,6 +142,13 @@ public:
/// If the library has not been built with IPv6 support, /// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown. /// a Poco::NotImplementedException will be thrown.
void useFileDescriptor(poco_socket_t fd);
/// Use a external file descriptor for the socket. Required to be careful
/// about what kind of file descriptor you're passing to make sure it's compatable
/// with how you plan on using it. These specifics are platform-specific.
/// Not valid to call this if the internal socket is already initialized.
/// Poco takes ownership of the file descriptor, closing it when this socket is closed.
virtual void listen(int backlog = 64); virtual void listen(int backlog = 64);
/// Puts the socket into listening state. /// Puts the socket into listening state.
/// ///

View File

@ -57,6 +57,14 @@ ServerSocket::ServerSocket(SocketImpl* pImpl, bool ignore): Socket(pImpl)
} }
ServerSocket ServerSocket::fromFileDescriptor(poco_socket_t fd)
{
ServerSocket s;
s.impl()->useFileDescriptor(fd);
return s;
}
ServerSocket::~ServerSocket() ServerSocket::~ServerSocket()
{ {
} }

View File

@ -54,6 +54,15 @@ Socket::Socket(const Socket& socket):
_pImpl->duplicate(); _pImpl->duplicate();
} }
Socket Socket::fromFileDescriptor(poco_socket_t fd)
{
Socket s;
s.impl()->useFileDescriptor(fd);
return s;
}
#if POCO_NEW_STATE_ON_MOVE #if POCO_NEW_STATE_ON_MOVE
Socket::Socket(Socket&& socket): Socket::Socket(Socket&& socket):

View File

@ -276,6 +276,14 @@ void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reu
} }
void SocketImpl::useFileDescriptor(poco_socket_t fd)
{
poco_assert (_sockfd == POCO_INVALID_SOCKET);
_sockfd = fd;
}
void SocketImpl::listen(int backlog) void SocketImpl::listen(int backlog)
{ {
if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException(); if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();

View File

@ -9,6 +9,7 @@
#include "EchoServer.h" #include "EchoServer.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/StreamSocket.h" #include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketAddress.h" #include "Poco/Net/SocketAddress.h"
#include "Poco/Timespan.h" #include "Poco/Timespan.h"
@ -42,6 +43,17 @@ EchoServer::EchoServer(const Poco::Net::SocketAddress& address):
} }
EchoServer::EchoServer(const Poco::Net::ServerSocket& sock):
_socket(sock),
_thread("EchoServer"),
_stop(false),
_done(false)
{
_thread.start(*this);
_ready.wait();
}
EchoServer::~EchoServer() EchoServer::~EchoServer()
{ {
_stop = true; _stop = true;

View File

@ -31,6 +31,9 @@ public:
EchoServer(const Poco::Net::SocketAddress& address); EchoServer(const Poco::Net::SocketAddress& address);
/// Creates the EchoServer using the given address. /// Creates the EchoServer using the given address.
EchoServer(const Poco::Net::ServerSocket& sock);
/// Creates the EchoServer using the already created socket
~EchoServer(); ~EchoServer();
/// Destroys the EchoServer. /// Destroys the EchoServer.

View File

@ -598,6 +598,51 @@ void SocketTest::testUnixLocalAbstract()
} }
void SocketTest::testUseFd()
{
#ifdef POCO_OS_FAMILY_WINDOWS
struct addrinfo addr_hint = {};
addr_hint.ai_family = AF_INET;
addr_hint.ai_socktype = SOCK_STREAM;
addr_hint.ai_protocol = IPPROTO_TCP;
addr_hint.ai_flags = AI_PASSIVE;
struct addrinfo* addr_result;
getaddrinfo(nullptr, "0", &addr_hint, &addr_result);
poco_socket_t listenfd = socket(addr_result->ai_family, addr_result->ai_socktype, addr_result->ai_protocol);
bind(listenfd, addr_result->ai_addr, (int)addr_result->ai_addrlen);
freeaddrinfo(addr_result);
listen(listenfd, SOMAXCONN);
SOCKADDR_IN serv_addr;
int addr_len = sizeof(serv_addr);
getsockname(listenfd, (SOCKADDR*)&serv_addr, &addr_len);
auto server_port = ntohs(serv_addr.sin_port);
#elif defined(POCO_OS_FAMILY_UNIX)
poco_socket_t listenfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr = {};
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(0);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 1);
socklen_t len = sizeof(serv_addr);
getsockname(listenfd, (struct sockaddr*)&serv_addr, &len);
auto server_port = ntohs(serv_addr.sin_port);
#else
std::cout << "[USE FD TEST DISABLED]";
return;
#endif
EchoServer server(ServerSocket::fromFileDescriptor(listenfd));
StreamSocket ss;
ss.connect(SocketAddress("127.0.0.1", server_port));
int n = ss.sendBytes("hello", 5);
assertTrue (n == 5);
char buffer[256];
n = ss.receiveBytes(buffer, sizeof(buffer));
assertTrue (n == 5);
assertTrue (std::string(buffer, n) == "hello");
ss.close();
}
void SocketTest::onReadable(bool& b) void SocketTest::onReadable(bool& b)
{ {
@ -650,6 +695,7 @@ CppUnit::Test* SocketTest::suite()
CppUnit_addTest(pSuite, SocketTest, testSelect3); CppUnit_addTest(pSuite, SocketTest, testSelect3);
CppUnit_addTest(pSuite, SocketTest, testEchoUnixLocal); CppUnit_addTest(pSuite, SocketTest, testEchoUnixLocal);
CppUnit_addTest(pSuite, SocketTest, testUnixLocalAbstract); CppUnit_addTest(pSuite, SocketTest, testUnixLocalAbstract);
CppUnit_addTest(pSuite, SocketTest, testUseFd);
return pSuite; return pSuite;
} }

View File

@ -43,6 +43,7 @@ public:
void testSelect3(); void testSelect3();
void testEchoUnixLocal(); void testEchoUnixLocal();
void testUnixLocalAbstract(); void testUnixLocalAbstract();
void testUseFd();
void setUp(); void setUp();
void tearDown(); void tearDown();