Skip to content

Commit

Permalink
enh(Net): Allow passing raw fd's into ServerSocket (#4156)
Browse files Browse the repository at this point in the history
* Allow creating ServerSocket's from fd's
* more sensible approach
* fix whitespace issue
* add test
* build fixes for windows
  • Loading branch information
russelltg authored Dec 4, 2023
1 parent 94418e5 commit 3ae282d
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Net/include/Poco/Net/ServerSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class Net_API ServerSocket: public Socket
/// 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.

Expand Down
4 changes: 4 additions & 0 deletions Net/include/Poco/Net/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ class Net_API Socket

#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.
Expand Down
7 changes: 7 additions & 0 deletions Net/include/Poco/Net/SocketImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ class Net_API SocketImpl: public Poco::RefCountedObject
/// 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.
///
Expand Down
8 changes: 8 additions & 0 deletions Net/src/ServerSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
}
Expand Down
9 changes: 9 additions & 0 deletions Net/src/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
8 changes: 8 additions & 0 deletions Net/src/SocketImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions Net/testsuite/src/EchoServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions Net/testsuite/src/EchoServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class EchoServer: public Poco::Runnable
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.

Expand Down
46 changes: 46 additions & 0 deletions Net/testsuite/src/SocketTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions Net/testsuite/src/SocketTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class SocketTest: public CppUnit::TestCase
void testSelect3();
void testEchoUnixLocal();
void testUnixLocalAbstract();
void testUseFd();

void setUp();
void tearDown();
Expand Down

0 comments on commit 3ae282d

Please sign in to comment.