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
/// 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();
/// Destroys the ServerSocket.

View File

@ -85,6 +85,10 @@ public:
#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();
/// Destroys the Socket and releases the
/// SocketImpl.

View File

@ -142,6 +142,13 @@ public:
/// If the library has not been built with IPv6 support,
/// 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);
/// 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()
{
}

View File

@ -54,6 +54,15 @@ Socket::Socket(const Socket& socket):
_pImpl->duplicate();
}
Socket Socket::fromFileDescriptor(poco_socket_t fd)
{
Socket s;
s.impl()->useFileDescriptor(fd);
return s;
}
#if POCO_NEW_STATE_ON_MOVE
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)
{
if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();

View File

@ -9,6 +9,7 @@
#include "EchoServer.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketAddress.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()
{
_stop = true;

View File

@ -31,6 +31,9 @@ public:
EchoServer(const Poco::Net::SocketAddress& address);
/// Creates the EchoServer using the given address.
EchoServer(const Poco::Net::ServerSocket& sock);
/// Creates the EchoServer using the already created socket
~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)
{
@ -650,6 +695,7 @@ CppUnit::Test* SocketTest::suite()
CppUnit_addTest(pSuite, SocketTest, testSelect3);
CppUnit_addTest(pSuite, SocketTest, testEchoUnixLocal);
CppUnit_addTest(pSuite, SocketTest, testUnixLocalAbstract);
CppUnit_addTest(pSuite, SocketTest, testUseFd);
return pSuite;
}

View File

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