Skip to content

Commit

Permalink
fix(NetSSL): Non-blocking sockets support #4773
Browse files Browse the repository at this point in the history
  • Loading branch information
obiltschnig committed Nov 16, 2024
1 parent cedd086 commit bf09be3
Show file tree
Hide file tree
Showing 12 changed files with 447 additions and 34 deletions.
27 changes: 18 additions & 9 deletions NetSSL_OpenSSL/include/Poco/Net/SecureSocketImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,6 @@ class NetSSL_API SecureSocketImpl
/// underlying TCP connection. No orderly SSL shutdown
/// is performed.

void setBlocking(bool flag);
/// Sets the socket in blocking mode if flag is true,
/// disables blocking mode if flag is false.

bool getBlocking() const;
/// Returns the blocking mode of the socket.
/// This method will only work if the blocking modes of
/// the socket are changed via the setBlocking method!

int sendBytes(const void* buffer, int length, int flags = 0);
/// Sends the contents of the given buffer through
/// the socket. Any specified flags are ignored.
Expand Down Expand Up @@ -239,6 +230,12 @@ class NetSSL_API SecureSocketImpl
/// Returns true iff a reused session was negotiated during
/// the handshake.

SocketImpl* socket();
/// Returns the underlying SocketImpl.

const SocketImpl* socket() const;
/// Returns the underlying SocketImpl.

protected:
void acceptSSL();
/// Performs a server-side SSL handshake and certificate verification.
Expand Down Expand Up @@ -308,6 +305,18 @@ class NetSSL_API SecureSocketImpl
//
// inlines
//
inline SocketImpl* SecureSocketImpl::socket()
{
return _pSocket.get();
}


inline const SocketImpl* SecureSocketImpl::socket() const
{
return _pSocket.get();
}


inline poco_socket_t SecureSocketImpl::sockfd()
{
return _pSocket->sockfd();
Expand Down
6 changes: 6 additions & 0 deletions NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocketImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ class NetSSL_API SecureStreamSocketImpl: public StreamSocketImpl
/// Returns true iff a reused session was negotiated during
/// the handshake.

// SocketImpl
virtual void setBlocking(bool flag) override;
virtual bool getBlocking() const override;
virtual void setRawOption(int level, int option, const void* value, poco_socklen_t length) override;
virtual void getRawOption(int level, int option, void* value, poco_socklen_t& length) override;

protected:
void acceptSSL();
/// Performs a SSL server-side handshake.
Expand Down
25 changes: 8 additions & 17 deletions NetSSL_OpenSSL/src/SecureSocketImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,22 +332,6 @@ void SecureSocketImpl::close()
}


void SecureSocketImpl::setBlocking(bool flag)
{
poco_check_ptr (_pSocket);

_pSocket->setBlocking(flag);
}


bool SecureSocketImpl::getBlocking() const
{
poco_check_ptr (_pSocket);

return _pSocket->getBlocking();
}


int SecureSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
poco_assert (_pSocket->initialized());
Expand Down Expand Up @@ -409,7 +393,14 @@ int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags)
Poco::Timestamp tsStart;
while (true)
{
rc = ::SSL_read(_pSSL, buffer, length);
if (flags & MSG_PEEK)
{
rc = SSL_peek(_pSSL, buffer, length);
}
else
{
rc = SSL_read(_pSSL, buffer, length);
}
if (!mustRetry(rc))
break;

Expand Down
24 changes: 24 additions & 0 deletions NetSSL_OpenSSL/src/SecureStreamSocketImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,28 @@ int SecureStreamSocketImpl::completeHandshake()
}


void SecureStreamSocketImpl::setBlocking(bool flag)
{
_impl.socket()->setBlocking(flag);
}


bool SecureStreamSocketImpl::getBlocking() const
{
return _impl.socket()->getBlocking();
}


void SecureStreamSocketImpl::setRawOption(int level, int option, const void* value, poco_socklen_t length)
{
_impl.socket()->setRawOption(level, option, value, length);
}


void SecureStreamSocketImpl::getRawOption(int level, int option, void* value, poco_socklen_t& length)
{
_impl.socket()->getRawOption(level, option, value, length);
}


} } // namespace Poco::Net
2 changes: 1 addition & 1 deletion NetSSL_OpenSSL/testsuite/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ objects = NetSSLTestSuite Driver \
HTTPSClientSessionTest HTTPSClientTestSuite HTTPSServerTest HTTPSServerTestSuite \
HTTPSStreamFactoryTest HTTPSTestServer TCPServerTest TCPServerTestSuite \
WebSocketTest WebSocketTestSuite FTPSClientSessionTest FTPSClientTestSuite \
DialogServer
DialogServer SecureStreamSocketTest SecureStreamSocketTestSuite

target = testrunner
target_version = 1
Expand Down
3 changes: 2 additions & 1 deletion NetSSL_OpenSSL/testsuite/src/NetSSLTestSuite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


#include "NetSSLTestSuite.h"

#include "SecureStreamSocketTestSuite.h"
#include "HTTPSClientTestSuite.h"
#include "TCPServerTestSuite.h"
#include "HTTPSServerTestSuite.h"
Expand All @@ -21,6 +21,7 @@ CppUnit::Test* NetSSLTestSuite::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OpenSSLTestSuite");

pSuite->addTest(SecureStreamSocketTestSuite::suite());
pSuite->addTest(HTTPSClientTestSuite::suite());
pSuite->addTest(TCPServerTestSuite::suite());
pSuite->addTest(HTTPSServerTestSuite::suite());
Expand Down
222 changes: 222 additions & 0 deletions NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
//
// SecureStreamSocketTest.cpp
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//


#include "SecureStreamSocketTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/Net/SecureServerSocket.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/RejectCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/Session.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/AbstractConfiguration.h"
#include "Poco/Thread.h"
#include <iostream>


using Poco::Net::TCPServer;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::TCPServerConnectionFactoryImpl;
using Poco::Net::TCPServerParams;
using Poco::Net::StreamSocket;
using Poco::Net::SecureStreamSocket;
using Poco::Net::SecureServerSocket;
using Poco::Net::SocketAddress;
using Poco::Net::Context;
using Poco::Net::Session;
using Poco::Net::SSLManager;
using Poco::Thread;
using Poco::Util::Application;


namespace
{
class EchoConnection: public TCPServerConnection
{
public:
EchoConnection(const StreamSocket& s): TCPServerConnection(s)
{
}

void run()
{
StreamSocket& ss = socket();
try
{
char buffer[256];
int n = ss.receiveBytes(buffer, sizeof(buffer));
while (n > 0)
{
ss.sendBytes(buffer, n);
n = ss.receiveBytes(buffer, sizeof(buffer));
}
}
catch (Poco::Exception& exc)
{
std::cerr << "EchoConnection: " << exc.displayText() << std::endl;
}
}
};
}


SecureStreamSocketTest::SecureStreamSocketTest(const std::string& name): CppUnit::TestCase(name)
{
}


SecureStreamSocketTest::~SecureStreamSocketTest()
{
}


void SecureStreamSocketTest::testSendReceive()
{
SecureServerSocket svs(0);
TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs);
srv.start();

SocketAddress sa("127.0.0.1", svs.address().port());
SecureStreamSocket ss1(sa);
std::string data("hello, world");
ss1.sendBytes(data.data(), static_cast<int>(data.size()));
char buffer[8192];
int n = ss1.receiveBytes(buffer, sizeof(buffer));
assertTrue (n > 0);
assertTrue (std::string(buffer, n) == data);

const std::vector<std::size_t> sizes = {67, 467, 7883, 19937};
for (const auto n: sizes)
{
data.assign(n, 'X');
ss1.sendBytes(data.data(), static_cast<int>(data.size()));
std::string received;
while (received.size() < n)
{
int rc = ss1.receiveBytes(buffer, sizeof(buffer));
if (rc > 0)
{
received.append(buffer, rc);
}
else if (n == 0)
{
break;
}
}
assertTrue (received == data);
}

ss1.close();
}


void SecureStreamSocketTest::testPeek()
{
SecureServerSocket svs(0);
TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs);
srv.start();

SocketAddress sa("127.0.0.1", svs.address().port());
SecureStreamSocket ss(sa);

int n = ss.sendBytes("hello, world!", 13);
assertTrue (n == 13);
char buffer[256];
n = ss.receiveBytes(buffer, 5, MSG_PEEK);
assertTrue (n == 5);
assertTrue (std::string(buffer, n) == "hello");
n = ss.receiveBytes(buffer, sizeof(buffer), MSG_PEEK);
assertTrue (n == 13);
assertTrue (std::string(buffer, n) == "hello, world!");
n = ss.receiveBytes(buffer, 7);
assertTrue (n == 7);
assertTrue (std::string(buffer, n) == "hello, ");
n = ss.receiveBytes(buffer, 6);
assertTrue (n == 6);
assertTrue (std::string(buffer, n) == "world!");
ss.close();
}


void SecureStreamSocketTest::testNB()
{
SecureServerSocket svs(0);
TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs);
srv.start();

SocketAddress sa("127.0.0.1", svs.address().port());
SecureStreamSocket ss1(sa);
ss1.setBlocking(false);
ss1.setSendBufferSize(32000);

char buffer[8192];
const std::vector<std::size_t> sizes = {67, 467, 7883, 19937};
for (const auto n: sizes)
{
std::string data(n, 'X');
int rc = ss1.sendBytes(data.data(), static_cast<int>(data.size()));
assertTrue (rc == n);

rc = -1;
while (rc < 0)
{
rc = ss1.receiveBytes(buffer, sizeof(buffer), MSG_PEEK);
}
assertTrue (rc > 0 && rc <= n);
assertTrue (data.compare(0, rc, buffer, rc) == 0);

std::string received;
while (received.size() < n)
{
int rc = ss1.receiveBytes(buffer, sizeof(buffer));
if (rc > 0)
{
received.append(buffer, rc);
}
else if (n == 0)
{
break;
}
}
assertTrue (received == data);
}

ss1.close();
}


void SecureStreamSocketTest::setUp()
{
}


void SecureStreamSocketTest::tearDown()
{
}


CppUnit::Test* SecureStreamSocketTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SecureStreamSocketTest");

CppUnit_addTest(pSuite, SecureStreamSocketTest, testSendReceive);
CppUnit_addTest(pSuite, SecureStreamSocketTest, testPeek);
CppUnit_addTest(pSuite, SecureStreamSocketTest, testNB);

return pSuite;
}
Loading

0 comments on commit bf09be3

Please sign in to comment.