Ver Fonte

merge FTPSClientSession from develop-experimental

Günter Obiltschnig há 6 anos atrás
pai
commit
5d481ff493

+ 38 - 13
Net/include/Poco/Net/FTPClientSession.h

@@ -63,7 +63,7 @@ public:
 		///
 		/// Passive mode will be used for data transfers.
 
-	explicit FTPClientSession(const StreamSocket& socket);
+	explicit FTPClientSession(const StreamSocket& socket, bool readWelcomeMessage = true);
 		/// Creates an FTPClientSession using the given
 		/// connected socket for the control connection.
 		///
@@ -99,14 +99,14 @@ public:
 	bool getPassive() const;
 		/// Returns true iff passive mode is enabled for this connection.
 		
-	void open(const std::string& host,
+	virtual void open(const std::string& host,
 		Poco::UInt16 port,
 		const std::string& username = "",
 		const std::string& password = "");
 		/// Opens the FTP connection to the given host and port.
 		/// If username is supplied, login is attempted.
 
-	void login(const std::string& username, const std::string& password);
+	virtual void login(const std::string& username, const std::string& password);
 		/// Authenticates the user against the FTP server. Must be
 		/// called before any other commands (except QUIT) can be sent.
 		///
@@ -302,7 +302,16 @@ public:
 	bool isLoggedIn() const;
 		/// Returns true if the session is logged in.
 
+	bool isSecure() const;
+		/// Returns true if the session is FTPS.
+		
+	const std::string& welcomeMessage();
+	/// Returns welcome message.
+	
 protected:
+	virtual void receiveServerReadyReply();
+		/// Function that read server welcome message after connetion
+
 	enum StatusClass
 	{
 		FTP_POSITIVE_PRELIMINARY  = 1,
@@ -335,20 +344,23 @@ protected:
 	void parseExtAddress(const std::string& str, SocketAddress& addr);
 	void endTransfer();
 	
+	DialogSocket*  _pControlSocket = nullptr;
+	SocketStream*  _pDataStream = nullptr;
+
 private:
 	FTPClientSession(const FTPClientSession&);
 	FTPClientSession& operator = (const FTPClientSession&);
 		
-	std::string    _host;
-	Poco::UInt16   _port;
-	DialogSocket*  _pControlSocket;
-	SocketStream*  _pDataStream;
-	bool	   _passiveMode;
-	FileType       _fileType;
-	bool	   _supports1738;
-	bool	   _serverReady;
-	bool	   _isLoggedIn;
-	Poco::Timespan _timeout;
+	std::string _host;
+	Poco::UInt16 _port = 0;
+	bool _passiveMode = true;
+	FileType _fileType = TYPE_BINARY;
+	bool _supports1738 = true;
+	bool _serverReady = false;
+	bool _isLoggedIn = false;
+	Poco::Timespan _timeout = DEFAULT_TIMEOUT;
+	std::string _welcomeMessage;
+	Poco::FastMutex _wmMutex;	
 };
 
 
@@ -397,6 +409,19 @@ inline bool FTPClientSession::isLoggedIn() const
 }
 
 
+inline bool FTPClientSession::isSecure() const
+{
+	return false;
+}
+
+
+inline const std::string& FTPClientSession::welcomeMessage()
+{
+	Poco::FastMutex::ScopedLock lock(_wmMutex);
+	return _welcomeMessage;
+}
+
+
 } } // namespace Poco::Net
 
 

+ 45 - 21
Net/src/FTPClientSession.cpp

@@ -29,9 +29,9 @@ namespace Net {
 
 
 FTPClientSession::FTPClientSession():
-	_port(0),
 	_pControlSocket(0),
 	_pDataStream(0),
+	_port(0),		
 	_passiveMode(true),
 	_fileType(TYPE_BINARY),
 	_supports1738(true),
@@ -42,11 +42,11 @@ FTPClientSession::FTPClientSession():
 }
 
 	
-FTPClientSession::FTPClientSession(const StreamSocket& socket):
-	_host(socket.address().host().toString()),
-	_port(socket.address().port()),
+FTPClientSession::FTPClientSession(const StreamSocket& socket, bool readWelcomeMessage):
 	_pControlSocket(new DialogSocket(socket)),
 	_pDataStream(0),
+	_host(socket.address().host().toString()),
+	_port(socket.address().port()),
 	_passiveMode(true),
 	_fileType(TYPE_BINARY),
 	_supports1738(true),
@@ -55,6 +55,14 @@ FTPClientSession::FTPClientSession(const StreamSocket& socket):
 	_timeout(DEFAULT_TIMEOUT)
 {
 	_pControlSocket->setReceiveTimeout(_timeout);
+	if (readWelcomeMessage) 
+	{
+		receiveServerReadyReply();
+	}
+	else 
+	{
+		_serverReady = true;
+	}	
 }
 
 
@@ -62,10 +70,10 @@ FTPClientSession::FTPClientSession(const std::string& host,
 	Poco::UInt16 port,
 	const std::string& username,
 	const std::string& password):
-	_host(host),
-	_port(port),
 	_pControlSocket(new DialogSocket(SocketAddress(host, port))),
 	_pDataStream(0),
+	_host(host),
+	_port(port),
 	_passiveMode(true),
 	_fileType(TYPE_BINARY),
 	_supports1738(true),
@@ -73,10 +81,9 @@ FTPClientSession::FTPClientSession(const std::string& host,
 	_isLoggedIn(false),
 	_timeout(DEFAULT_TIMEOUT)
 {
+	_pControlSocket->setReceiveTimeout(_timeout);
 	if (!username.empty())
 		login(username, password);
-	else
-		_pControlSocket->setReceiveTimeout(_timeout);
 }
 
 
@@ -134,12 +141,32 @@ void FTPClientSession::open(const std::string& host,
 	}
 	else
 	{
-		_pControlSocket = new DialogSocket(SocketAddress(_host, _port));
-		_pControlSocket->setReceiveTimeout(_timeout);
+		if (!_pControlSocket)
+		{
+			_pControlSocket = new DialogSocket(SocketAddress(_host, _port));
+			_pControlSocket->setReceiveTimeout(_timeout);
+		}
+		receiveServerReadyReply();
 	}
 }
 
 
+void  FTPClientSession::receiveServerReadyReply()
+{
+	if (_serverReady) return;
+	std::string response;
+	int status = _pControlSocket->receiveStatusMessage(response);
+	if (!isPositiveCompletion(status))
+		throw FTPException("Cannot receive status message", response, status);
+
+	{
+		Poco::FastMutex::ScopedLock lock(_wmMutex);
+		_welcomeMessage = response;
+	}
+	_serverReady = true;
+}
+
+
 void FTPClientSession::login(const std::string& username, const std::string& password)
 {
 	if (_isLoggedIn) logout();
@@ -151,15 +178,7 @@ void FTPClientSession::login(const std::string& username, const std::string& pas
 		_pControlSocket = new DialogSocket(SocketAddress(_host, _port));
 		_pControlSocket->setReceiveTimeout(_timeout);
 	}
-
-	if (!_serverReady)
-	{
-		status = _pControlSocket->receiveStatusMessage(response);
-		if (!isPositiveCompletion(status))
-			throw FTPException("Cannot login to server", response, status);
-
-		_serverReady = true;
-	}
+	receiveServerReadyReply();
 
 	status = sendCommand("USER", username, response);
 	if (isPositiveIntermediate(status))
@@ -190,8 +209,13 @@ void FTPClientSession::logout()
 
 void FTPClientSession::close()
 {
-	try { logout(); }
-	catch (...) {}
+	try 
+	{ 
+		logout(); 
+	}
+	catch (...) 
+	{
+	}
 	_serverReady = false;
 	if (_pControlSocket)
 	{

+ 3 - 2
NetSSL_OpenSSL/Makefile

@@ -16,10 +16,11 @@ objects = AcceptCertificateHandler RejectCertificateHandler ConsoleCertificateHa
 	PrivateKeyPassphraseHandler SecureServerSocket SecureServerSocketImpl \
 	SecureSocketImpl SecureStreamSocket SecureStreamSocketImpl \
 	SSLException SSLManager Utility VerificationErrorArgs \
-	X509Certificate Session SecureSMTPClientSession
+	X509Certificate Session SecureSMTPClientSession \
+	FTPSClientSession
 
 target         = PocoNetSSL
 target_version = $(LIBVERSION)
-target_libs    = PocoNet PocoCrypto PocoUtil PocoFoundation 
+target_libs    = PocoNet PocoCrypto PocoUtil PocoFoundation
 
 include $(POCO_BASE)/build/rules/lib

+ 91 - 0
NetSSL_OpenSSL/include/Poco/Net/FTPSClientSession.h

@@ -0,0 +1,91 @@
+//
+// FTPSClientSession.h
+//
+// Library: Net
+// Package: FTP
+// Module:  FTPSClientSession
+//
+// Definition of the FTPSClientSession class.
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#ifndef NetSSL_FTPSClientSession_INCLUDED
+#define NetSSL_FTPSClientSession_INCLUDED
+
+
+#include "Poco/Net/NetSSL.h"
+#include "Poco/Net/FTPClientSession.h"
+
+
+namespace Poco {
+namespace Net {
+
+
+class NetSSL_API FTPSClientSession: public Poco::Net::FTPClientSession
+{
+public:
+	FTPSClientSession();
+		/// Creates an FTPSClientSession.
+		///
+		/// Passive mode will be used for data transfers.
+
+	explicit FTPSClientSession(const StreamSocket& socket, bool readWelcomeMessage = true, bool tryUseFTPS = true);
+		/// Creates an FTPSClientSession using the given
+		/// connected socket for the control connection.
+		///
+		/// Passive mode will be used for data transfers.
+
+	FTPSClientSession(const std::string& host, Poco::UInt16 port = FTP_PORT, const std::string& username = "", const std::string& password = "");
+		/// Creates an FTPSClientSession using a socket connected
+		/// to the given host and port. If username is supplied,
+		/// login is attempted.
+		///
+		/// Passive mode will be used for data transfers.
+
+	virtual ~FTPSClientSession();
+
+	void tryFTPSmode(bool tryFTPS);
+		/// avoid or require TLS mode
+
+	bool isSecure() const;
+		/// Returns true if the session is FTPS.
+
+protected:
+	virtual StreamSocket establishDataConnection(const std::string& command, const std::string& arg);
+		/// Create secure data connection
+
+	virtual void receiveServerReadyReply();
+		/// Function that read server welcome message after connetion and set and make secure socket
+
+private:
+	void beforeCreateDataSocket();
+	///Send commands to check if we can encrypt data socket
+
+	void afterCreateControlSocket();
+	///Send commands to make SSL negotiating of control channel
+
+	bool _tryFTPS = true;
+	bool _secureDataConnection = false;
+};
+
+
+//
+// inlines
+//
+inline bool FTPSClientSession::isSecure() const
+{
+	if (_pControlSocket != nullptr)
+		return _pControlSocket->secure();
+	return false;
+}
+
+
+} } // namespace Poco::Net
+
+
+#endif // #define NetSSL_FTPSClientSession_INCLUDED

+ 130 - 0
NetSSL_OpenSSL/src/FTPSClientSession.cpp

@@ -0,0 +1,130 @@
+//
+// FTPSClientSession.cpp
+//
+// Library: Net
+// Package: FTP
+// Module:  FTPSClientSession
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#include "Poco/Net/FTPSClientSession.h"
+#include "Poco/Net/SecureStreamSocket.h"
+#include "Poco/Net/SecureStreamSocketImpl.h"
+#include "Poco/Net/SSLManager.h"
+#include "Poco/Net/NetException.h"
+
+namespace Poco {
+namespace Net {
+
+FTPSClientSession::FTPSClientSession() :
+	FTPClientSession()
+{
+}
+
+
+FTPSClientSession::~FTPSClientSession()
+{
+}
+
+FTPSClientSession::FTPSClientSession(const StreamSocket& socket, bool readWelcomeMessage, bool tryUseFTPS) :
+	FTPClientSession(socket, readWelcomeMessage), _tryFTPS(tryUseFTPS)
+{
+}
+
+
+FTPSClientSession::FTPSClientSession(const std::string& host,
+	Poco::UInt16 port,
+	const std::string& username,
+	const std::string& password) :
+	FTPClientSession(host, port, username, password)
+{
+}
+
+void FTPSClientSession::tryFTPSmode(bool bTryFTPS)
+{
+	_tryFTPS = bTryFTPS;
+}
+
+void FTPSClientSession::beforeCreateDataSocket()
+{
+	if (_secureDataConnection)
+		return;
+	_secureDataConnection = false;
+	if (!_pControlSocket->secure())
+		return;
+	std::string sResponse;
+	int status = sendCommand("PBSZ 0", sResponse);
+	if (isPositiveCompletion(status))
+	{
+		status = sendCommand("PROT P", sResponse);
+		if (isPositiveCompletion(status))
+			_secureDataConnection = true;
+	}
+}
+
+void FTPSClientSession::afterCreateControlSocket()
+{
+	if (!_tryFTPS)
+		return;
+	_pControlSocket->setNoDelay(true);
+	if (_pControlSocket->secure())
+		return;
+
+	std::string sResponse;
+	int status = sendCommand("AUTH TLS", sResponse);
+	if (!isPositiveCompletion(status))
+		status = sendCommand("AUTH SSL", sResponse);
+
+	if (isPositiveCompletion(status))
+	{
+		//Server support FTPS
+		try
+		{
+			Poco::Net::SecureStreamSocket sss(Poco::Net::SecureStreamSocket::attach(*_pControlSocket, Poco::Net::SSLManager::instance().defaultClientContext()));
+			*_pControlSocket = sss;
+		}
+		catch (Poco::Exception&)
+		{
+			throw;
+		}
+	}
+	else
+	{
+		_tryFTPS = false;
+	}
+}
+
+StreamSocket FTPSClientSession::establishDataConnection(const std::string& command, const std::string& arg)
+{
+	beforeCreateDataSocket();
+
+	StreamSocket ss = FTPClientSession::establishDataConnection(command, arg);
+	ss.setNoDelay(true);
+
+	//SSL nogotiating of data socket
+	if ((_secureDataConnection) && (_pControlSocket->secure()))
+	{
+		//We need to reuse the control socket SSL session so the server can ensure that client that opened control socket is the same using data socket
+		Poco::Net::SecureStreamSocketImpl* pSecure = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(_pControlSocket->impl());
+		if (pSecure != nullptr)
+		{
+			Poco::Net::SecureStreamSocket sss(Poco::Net::SecureStreamSocket::attach(ss, pSecure->context(), pSecure->currentSession()));
+			ss = sss;
+		}
+	}
+	return ss;
+}
+
+void FTPSClientSession::receiveServerReadyReply()
+{
+	FTPClientSession::receiveServerReadyReply();
+	afterCreateControlSocket();
+}
+
+}
+} // namespace Poco::Net

+ 2 - 1
NetSSL_OpenSSL/testsuite/Makefile

@@ -20,7 +20,8 @@ endif
 objects = NetSSLTestSuite Driver \
 	HTTPSClientSessionTest HTTPSClientTestSuite HTTPSServerTest HTTPSServerTestSuite \
 	HTTPSStreamFactoryTest HTTPSTestServer TCPServerTest TCPServerTestSuite \
-	WebSocketTest WebSocketTestSuite
+	WebSocketTest WebSocketTestSuite FTPSClientSessionTest FTPSClientTestSuite \
+	DialogServer
 
 target         = testrunner
 target_version = 1

+ 260 - 0
NetSSL_OpenSSL/testsuite/src/DialogServer.cpp

@@ -0,0 +1,260 @@
+//
+// DialogServer.cpp
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#include "DialogServer.h"
+#include "Poco/Net/DialogSocket.h"
+#include "Poco/Net/SocketAddress.h"
+#include "Poco/Timespan.h"
+#include <iostream>
+#include "Poco/Net/SecureStreamSocket.h"
+#include "Poco/Net/SSLManager.h"
+#include "Poco/Net/Context.h"
+#include "Poco/Net/SecureStreamSocketImpl.h"
+
+
+using Poco::Net::Socket;
+using Poco::Net::DialogSocket;
+using Poco::Net::SocketAddress;
+using Poco::FastMutex;
+using Poco::Thread;
+using Poco::Net::SecureStreamSocket;
+using Poco::Net::SSLManager;
+using Poco::Exception;
+using Poco::Net::Context;
+using Poco::Net::Session;
+using Poco::Net::SecureStreamSocketImpl;
+
+
+DialogServer::DialogServer(bool acceptCommands, bool ssl):
+	_socket(SocketAddress()),
+	_thread("DialogServer"),
+	_stop(false),
+	_acceptCommands(acceptCommands),
+	_log(false),
+	_ssl(ssl)
+{
+	_thread.start(*this);
+	_ready.wait();
+}
+
+
+DialogServer::~DialogServer()
+{
+	_stop = true;
+	_thread.join();
+}
+
+
+Poco::UInt16 DialogServer::port() const
+{
+	return _socket.address().port();
+}
+
+
+void handleDataSSLrequest(DialogSocket& ds, bool ssl, Session::Ptr& sslSession)
+{
+	if (ssl)
+	{
+		try
+		{
+			Context::Ptr cDefaultServerContext = SSLManager::instance().defaultServerContext();
+			SecureStreamSocket sss(SecureStreamSocket::attach(ds, cDefaultServerContext, sslSession));
+			sss.setLazyHandshake(true);
+			if (sss.completeHandshake() == 1)
+			{
+				ds = sss;
+			}
+		}
+		catch (Exception&) {
+		}
+	}
+}
+
+
+void handleSSLrequest(DialogSocket& ds, bool ssl, Session::Ptr& sslSession)
+{
+	if (ssl)
+	{
+		try
+		{
+			Context::Ptr cDefaultServerContext = SSLManager::instance().defaultServerContext();
+			ds.sendMessage("200 OK");
+			SecureStreamSocket sss(SecureStreamSocket::attach(ds, cDefaultServerContext));
+			sss.setLazyHandshake(true);
+			if (sss.completeHandshake() == 1)
+			{
+				ds = sss;
+
+				SecureStreamSocketImpl* pSecure = dynamic_cast<SecureStreamSocketImpl*>(sss.impl());
+				if (pSecure != nullptr)
+					sslSession = pSecure->currentSession();
+			}
+			else
+			{
+				ds.sendMessage("501 Explicit TLS authentication not available");
+			}
+		}
+		catch (Exception&) {
+			ds.sendMessage("501 Explicit TLS authentication not available");
+		}
+	}
+	else
+	{
+		ds.sendMessage("501 Explicit TLS authentication not available");
+	}
+}
+
+
+void DialogServer::run()
+{
+	_ready.set();
+	Poco::Timespan span(250000);
+	while (!_stop)
+	{
+		if (_socket.poll(span, Socket::SELECT_READ))
+		{
+			DialogSocket ds = _socket.acceptConnection();
+			if (!_SSLsession.isNull()) {
+				handleDataSSLrequest(ds, _ssl, _SSLsession);
+			}
+			{
+				FastMutex::ScopedLock lock(_mutex);
+				if (!_nextResponses.empty())
+				{
+					ds.sendMessage(_nextResponses.front());
+					_nextResponses.erase(_nextResponses.begin());
+				}
+			}
+			if (_acceptCommands)
+			{
+				try
+				{
+
+					std::string command;
+					while (ds.receiveMessage(command))
+					{
+						if ((command == "AUTH TLS") || (command == "AUTH SSL"))
+						{
+							handleSSLrequest(ds, _ssl, _SSLsession);
+							continue;
+						}
+						else if ((command == "PBSZ 0") || (command == "PROT P"))
+						{
+							ds.sendMessage("200 OK");
+							continue;
+						}
+
+						if (_log) std::cout << ">> " << command << std::endl;
+						{
+							FastMutex::ScopedLock lock(_mutex);
+							_lastCommands.push_back(command);
+							if (!_nextResponses.empty())
+							{
+								if (_log) std::cout << "<< " << _nextResponses.front() << std::endl;
+								ds.sendMessage(_nextResponses.front());
+								_nextResponses.erase(_nextResponses.begin());
+							}
+						}
+					}
+				}
+				catch (Poco::Exception& exc)
+				{
+					std::cerr << "DialogServer: " << exc.displayText() << std::endl;
+				}
+			}
+		}
+	}
+}
+
+
+const std::string& DialogServer::lastCommand() const
+{
+	FastMutex::ScopedLock lock(_mutex);
+
+	static const std::string EMPTY;
+	if (_lastCommands.empty())
+		return EMPTY;
+	else
+		return _lastCommands.back();
+}
+
+
+const std::vector<std::string>& DialogServer::lastCommands() const
+{
+	return _lastCommands;
+}
+
+
+std::string DialogServer::popCommand()
+{
+	FastMutex::ScopedLock lock(_mutex);
+
+	std::string command;
+	if (!_lastCommands.empty())
+	{
+		command = _lastCommands.front();
+		_lastCommands.erase(_lastCommands.begin());
+	}
+	return command;
+}
+
+
+std::string DialogServer::popCommandWait()
+{
+	std::string result(popCommand());
+	while (result.empty())
+	{
+		Thread::sleep(100);
+		result = popCommand();
+	}
+	return result;
+}
+
+
+void DialogServer::addResponse(const std::string& response)
+{
+	FastMutex::ScopedLock lock(_mutex);
+
+	_nextResponses.push_back(response);
+}
+
+
+void DialogServer::clearCommands()
+{
+	FastMutex::ScopedLock lock(_mutex);
+
+	_lastCommands.clear();
+}
+
+
+void DialogServer::clearResponses()
+{
+	FastMutex::ScopedLock lock(_mutex);
+
+	_nextResponses.clear();
+}
+
+
+void DialogServer::log(bool flag)
+{
+	_log = flag;
+}
+
+
+void DialogServer::setSslSession(Session::Ptr cSession)
+{
+	_SSLsession = cSession;
+}
+
+
+Session::Ptr DialogServer::getSslSession()
+{
+	return _SSLsession;
+}

+ 87 - 0
NetSSL_OpenSSL/testsuite/src/DialogServer.h

@@ -0,0 +1,87 @@
+//
+// DialogServer.h
+//
+// Definition of the DialogServer class.
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#ifndef DialogServer_INCLUDED
+#define DialogServer_INCLUDED
+
+
+#include "Poco/Net/Net.h"
+#include "Poco/Net/ServerSocket.h"
+#include "Poco/Net/StreamSocket.h"
+#include "Poco/Thread.h"
+#include "Poco/Event.h"
+#include "Poco/Mutex.h"
+#include <vector>
+#include "Poco/Net/Session.h"
+
+
+class DialogServer: public Poco::Runnable
+	/// A server for testing FTPClientSession and friends.
+{
+public:
+	DialogServer(bool acceptCommands = true, bool ssl = false);
+		/// Creates the DialogServer.
+
+	~DialogServer();
+		/// Destroys the DialogServer.
+
+	Poco::UInt16 port() const;
+		/// Returns the port the echo server is
+		/// listening on.
+		
+	void run();
+		/// Does the work.
+		
+	const std::string& lastCommand() const;
+		/// Returns the last command received by the server.
+
+	std::string popCommand();
+		/// Pops the next command from the list of received commands.
+
+	std::string popCommandWait();
+		/// Pops the next command from the list of received commands.
+		/// Waits until a command is available.
+
+	const std::vector<std::string>& lastCommands() const;
+		/// Returns the last command received by the server.
+		
+	void addResponse(const std::string& response);
+		/// Sets the next response returned by the server.
+	
+	void clearCommands();
+		/// Clears all commands.
+		
+	void clearResponses();
+		/// Clears all responses.
+		
+	void log(bool flag);
+		/// Enables or disables logging to stdout.
+
+	Poco::Net::Session::Ptr getSslSession();
+	void setSslSession(Poco::Net::Session::Ptr cSession);
+	
+private:
+	Poco::Net::ServerSocket _socket;
+	Poco::Thread             _thread;
+	Poco::Event              _ready;
+	mutable Poco::FastMutex  _mutex;
+	bool                     _stop;
+	std::vector<std::string> _nextResponses;
+	std::vector<std::string> _lastCommands;
+	bool                     _acceptCommands;
+	bool                     _log;
+	bool					 _ssl;
+	Poco::Net::Session::Ptr	 _SSLsession = nullptr;
+};
+
+
+#endif // DialogServer_INCLUDED

+ 647 - 0
NetSSL_OpenSSL/testsuite/src/FTPSClientSessionTest.cpp

@@ -0,0 +1,647 @@
+//
+// FTPSClientSessionTest.cpp
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#include "FTPSClientSessionTest.h"
+#include "Poco/CppUnit/TestCaller.h"
+#include "Poco/CppUnit/TestSuite.h"
+#include "Poco/Net/FTPSClientSession.h"
+#include "Poco/Net/DialogSocket.h"
+#include "Poco/Net/SocketAddress.h"
+#include "Poco/Net/NetException.h"
+#include "Poco/Thread.h"
+#include "Poco/ActiveMethod.h"
+#include "Poco/StreamCopier.h"
+#include "Poco/Net/Session.h"
+#include "DialogServer.h"
+#include <sstream>
+
+
+using Poco::Net::FTPSClientSession;
+using Poco::Net::DialogSocket;
+using Poco::Net::SocketAddress;
+using Poco::Net::FTPException;
+using Poco::ActiveMethod;
+using Poco::ActiveResult;
+using Poco::StreamCopier;
+using Poco::Thread;
+using Poco::Net::Session;
+
+
+namespace
+{
+	class ActiveDownloader
+	{
+	public:
+		ActiveDownloader(FTPSClientSession& session):
+			download(this, &ActiveDownloader::downloadImp),
+			_session(session)
+		{
+		}
+
+		ActiveMethod<std::string, std::string, ActiveDownloader> download;
+
+	protected:
+		std::string downloadImp(const std::string& path)
+		{
+			std::istream& istr = _session.beginDownload(path);
+			std::ostringstream ostr;
+			StreamCopier::copyStream(istr, ostr);
+			_session.endDownload();
+			return ostr.str();
+		}
+
+	private:
+		FTPSClientSession& _session;
+	};
+};
+
+
+FTPSClientSessionTest::FTPSClientSessionTest(const std::string& name): CppUnit::TestCase(name)
+{
+}
+
+
+FTPSClientSessionTest::~FTPSClientSessionTest()
+{
+}
+
+
+void FTPSClientSessionTest::login(DialogServer& server, FTPSClientSession& session)
+{
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	session.login("user", "password");
+	std::string cmd = server.popCommand();
+	assertTrue (cmd == "USER user");
+	cmd = server.popCommand();
+	assertTrue (cmd == "PASS password");
+	cmd = server.popCommand();
+	assertTrue (cmd == "TYPE I");
+
+	assertTrue (session.getFileType() == FTPSClientSession::TYPE_BINARY);
+}
+
+
+void FTPSClientSessionTest::testLogin1()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	FTPSClientSession session("127.0.0.1", server.port());
+	assertTrue (session.isOpen());
+	assertTrue (!session.isLoggedIn());
+	login(server, session);
+	assertTrue (session.isOpen());
+	assertTrue (session.isLoggedIn());
+	server.addResponse("221 Good Bye");
+	session.logout();
+	assertTrue (session.isOpen());
+	assertTrue (!session.isLoggedIn());
+
+	server.clearCommands();
+	server.clearResponses();
+
+	session.tryFTPSmode(true);
+	login(server, session);
+	assertTrue (session.isOpen());
+	assertTrue (session.isLoggedIn());
+	server.addResponse("221 Good Bye");
+	session.close();
+	assertTrue (!session.isOpen());
+	assertTrue (!session.isLoggedIn());
+}
+
+
+void FTPSClientSessionTest::testLogin2()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	Poco::UInt16 serverPort = server.port();
+	FTPSClientSession session("127.0.0.1", serverPort, "user", "password");
+	assertTrue (session.isOpen());
+	assertTrue (session.isLoggedIn());
+	server.addResponse("221 Good Bye");
+	session.close();
+	assertTrue (!session.isOpen());
+	assertTrue (!session.isLoggedIn());
+
+	server.clearCommands();
+	server.clearResponses();
+	server.addResponse("220 localhost FTP ready");
+
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	session.tryFTPSmode(true);
+	session.open("127.0.0.1", serverPort, "user", "password");
+	assertTrue (session.isOpen());
+	assertTrue (session.isLoggedIn());
+	server.addResponse("221 Good Bye");
+	session.close();
+	assertTrue (!session.isOpen());
+	assertTrue (!session.isLoggedIn());
+}
+
+
+void FTPSClientSessionTest::testLogin3()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session;
+	assertTrue (!session.isOpen());
+	assertTrue (!session.isLoggedIn());
+	session.open("127.0.0.1", server.port(), "user", "password");
+	server.addResponse("221 Good Bye");
+	session.close();
+	assertTrue (!session.isOpen());
+	assertTrue (!session.isLoggedIn());
+}
+
+
+
+void FTPSClientSessionTest::testLoginFailed1()
+{
+	DialogServer server;
+	server.addResponse("421 localhost FTP not ready");
+	FTPSClientSession session("127.0.0.1", server.port());
+	try
+	{
+		session.login("user", "password");
+		fail("server not ready - must throw");
+	}
+	catch (FTPException&)
+	{
+	}
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testLoginFailed2()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("530 Login incorrect");
+	FTPSClientSession session("127.0.0.1", server.port());
+	try
+	{
+		session.login("user", "password");
+		fail("login incorrect - must throw");
+	}
+	catch (FTPException&)
+	{
+	}
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testCommands()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.login("user", "password");
+	std::string cmd = server.popCommand();
+	assertTrue (cmd == "USER user");
+	cmd = server.popCommand();
+	assertTrue (cmd == "PASS password");
+	cmd = server.popCommand();
+	assertTrue (cmd == "TYPE I");
+
+	// systemType
+	server.clearCommands();
+	server.addResponse("215 UNIX Type: L8 Version: dummyFTP 1.0");
+	std::string type = session.systemType();
+	cmd = server.popCommand();
+	assertTrue (cmd == "SYST");
+	assertTrue (type == "UNIX Type: L8 Version: dummyFTP 1.0");
+
+	// getWorkingDirectory
+	server.addResponse("257 \"/usr/test\" is current directory");
+	std::string cwd = session.getWorkingDirectory();
+	cmd = server.popCommand();
+	assertTrue (cmd == "PWD");
+	assertTrue (cwd == "/usr/test");
+
+	// getWorkingDirectory (quotes in filename)
+	server.addResponse("257 \"\"\"quote\"\"\" is current directory");
+	cwd = session.getWorkingDirectory();
+	cmd = server.popCommand();
+	assertTrue (cmd == "PWD");
+	assertTrue (cwd == "\"quote\"");
+
+	// setWorkingDirectory
+	server.addResponse("250 CWD OK");
+	session.setWorkingDirectory("test");
+	cmd = server.popCommand();
+	assertTrue (cmd == "CWD test");
+
+	server.addResponse("250 CDUP OK");
+	session.cdup();
+	cmd = server.popCommand();
+	assertTrue (cmd == "CDUP");
+
+	// rename
+	server.addResponse("350 File exists, send destination name");
+	server.addResponse("250 Rename OK");
+	session.rename("old.txt", "new.txt");
+	cmd = server.popCommand();
+	assertTrue (cmd == "RNFR old.txt");
+	cmd = server.popCommand();
+	assertTrue (cmd == "RNTO new.txt");
+
+	// rename (failing)
+	server.addResponse("550 not found");
+	try
+	{
+		session.rename("old.txt", "new.txt");
+		fail("not found - must throw");
+	}
+	catch (FTPException&)
+	{
+	}
+	server.clearCommands();
+
+	// remove
+	server.addResponse("250 delete ok");
+	session.remove("test.txt");
+	cmd = server.popCommand();
+	assertTrue (cmd == "DELE test.txt");
+
+	// remove (failing)
+	server.addResponse("550 not found");
+	try
+	{
+		session.remove("test.txt");
+		fail("not found - must throw");
+	}
+	catch (FTPException&)
+	{
+	}
+	server.clearCommands();
+
+	// createDirectory
+	server.addResponse("257 dir created");
+	session.createDirectory("foo");
+	cmd = server.popCommand();
+	assertTrue (cmd == "MKD foo");
+
+	// createDirectory (failing)
+	server.addResponse("550 exists");
+	try
+	{
+		session.createDirectory("foo");
+		fail("not found - must throw");
+	}
+	catch (FTPException&)
+	{
+	}
+	server.clearCommands();
+
+	// removeDirectory
+	server.addResponse("250 RMD OK");
+	session.removeDirectory("foo");
+	cmd = server.popCommand();
+	assertTrue (cmd == "RMD foo");
+
+	// removeDirectory (failing)
+	server.addResponse("550 not found");
+	try
+	{
+		session.removeDirectory("foo");
+		fail("not found - must throw");
+	}
+	catch (FTPException&)
+	{
+	}
+	server.clearCommands();
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testDownloadPORT()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.setPassive(false);
+	session.login("user", "password");
+	server.clearCommands();
+
+	server.addResponse("500 EPRT not understood");
+	server.addResponse("200 PORT OK");
+	server.addResponse("150 Sending data\r\n226 Transfer complete");
+
+	ActiveDownloader dl(session);
+	ActiveResult<std::string> result = dl.download("test.txt");
+
+	std::string cmd = server.popCommandWait();
+	assertTrue (cmd.substr(0, 4) == "EPRT");
+
+	cmd = server.popCommandWait();
+	assertTrue (cmd.substr(0, 4) == "PORT");
+
+	std::string dummy;
+	int x, lo, hi;
+	for (std::string::iterator it = cmd.begin(); it != cmd.end(); ++it)
+	{
+		if (*it == ',') *it = ' ';
+	}
+	std::istringstream istr(cmd);
+	istr >> dummy >> x >> x >> x >> x >> hi >> lo;
+	int port = hi*256 + lo;
+
+	cmd = server.popCommandWait();
+	assertTrue (cmd == "RETR test.txt");
+
+	SocketAddress sa("127.0.0.1", (Poco::UInt16) port);
+	DialogSocket dataSock;
+	dataSock.connect(sa);
+
+	std::string data("This is some data");
+	dataSock.sendString(data);
+	dataSock.close();
+
+	result.wait();
+	std::string received = result.data();
+	assertTrue (received == data);
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testDownloadEPRT()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.setPassive(false);
+	session.login("user", "password");
+	server.clearCommands();
+
+	server.addResponse("200 EPRT OK");
+	server.addResponse("150 Sending data\r\n226 Transfer complete");
+
+	ActiveDownloader dl(session);
+	ActiveResult<std::string> result = dl.download("test.txt");
+
+	std::string cmd = server.popCommandWait();
+	assertTrue (cmd.substr(0, 4) == "EPRT");
+
+	std::string dummy;
+	char c;
+	int d;
+	int port;
+	std::istringstream istr(cmd);
+	istr >> dummy >> c >> d >> c >> d >> c >> d >> c >> d >> c >> d >> c >> port >> c;
+
+	cmd = server.popCommandWait();
+	assertTrue (cmd == "RETR test.txt");
+
+	SocketAddress sa("127.0.0.1", (Poco::UInt16) port);
+	DialogSocket dataSock;
+	dataSock.connect(sa);
+
+	std::string data("This is some data");
+	dataSock.sendString(data);
+	dataSock.close();
+
+	result.wait();
+	std::string received = result.data();
+	assertTrue (received == data);
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testDownloadPASV()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.login("user", "password");
+	server.clearCommands();
+
+	server.addResponse("500 EPSV not understood");
+
+	DialogServer dataServer(false);
+	Poco::UInt16 dataServerPort = dataServer.port();
+	dataServer.addResponse("This is some data");
+	std::ostringstream pasv;
+	pasv << "227 Entering Passive Mode (127,0,0,1," << (dataServerPort/256) << "," << (dataServerPort % 256) << ")";
+	server.addResponse(pasv.str());
+	server.addResponse("150 sending data\r\n226 Transfer complete");
+
+	std::istream& istr = session.beginDownload("test.txt");
+	std::ostringstream dataStr;
+	StreamCopier::copyStream(istr, dataStr);
+	session.endDownload();
+	std::string s(dataStr.str());
+	assertTrue (s == "This is some data\r\n");
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testDownloadEPSV()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.login("user", "password");
+	server.clearCommands();
+
+	DialogServer dataServer(false);
+	dataServer.addResponse("This is some data");
+	std::ostringstream epsv;
+	epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
+	server.addResponse(epsv.str());
+	server.addResponse("150 sending data\r\n226 Transfer complete");
+
+	std::istream& istr = session.beginDownload("test.txt");
+	std::ostringstream dataStr;
+	StreamCopier::copyStream(istr, dataStr);
+	session.endDownload();
+	std::string s(dataStr.str());
+	assertTrue (s == "This is some data\r\n");
+
+	std::string cmd = server.popCommand();
+	assertTrue (cmd.substr(0, 4) == "EPSV");
+	cmd = server.popCommand();
+	assertTrue (cmd == "RETR test.txt");
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testUpload()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.login("user", "password");
+	server.clearCommands();
+
+	DialogServer dataServer;
+	std::ostringstream epsv;
+	epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
+	server.addResponse(epsv.str());
+	server.addResponse("150 send data\r\n226 Transfer complete");
+
+	std::ostream& ostr = session.beginUpload("test.txt");
+	ostr << "This is some data\r\n";
+	session.endUpload();
+	std::string s(dataServer.popCommandWait());
+	assertTrue (s == "This is some data");
+
+	std::string cmd = server.popCommand();
+	assertTrue (cmd.substr(0, 4) == "EPSV");
+	cmd = server.popCommand();
+	assertTrue (cmd == "STOR test.txt");
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testUploadSSL()
+{
+	DialogServer server(true, true);
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.login("user", "password");
+	server.clearCommands();
+
+	DialogServer dataServer(true, true);
+	Session::Ptr cSessionSSL = server.getSslSession();
+	dataServer.setSslSession(cSessionSSL);
+
+	std::ostringstream epsv;
+	epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
+	server.addResponse(epsv.str());
+	server.addResponse("150 send data\r\n226 Transfer complete");
+
+	std::ostream& ostr = session.beginUpload("test.txt");
+	ostr << "This is some data\r\n";
+	session.endUpload();
+	std::string s(dataServer.popCommandWait());
+	assertTrue (s == "This is some data");
+
+	std::string cmd = server.popCommand();
+	assertTrue (cmd.substr(0, 4) == "EPSV");
+	cmd = server.popCommand();
+	assertTrue (cmd == "STOR test.txt");
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::testList()
+{
+	DialogServer server;
+	server.addResponse("220 localhost FTP ready");
+	server.addResponse("331 Password required");
+	server.addResponse("230 Welcome");
+	server.addResponse("200 Type set to I");
+	FTPSClientSession session("127.0.0.1", server.port());
+	session.login("user", "password");
+	server.clearCommands();
+
+	DialogServer dataServer(false);
+	dataServer.addResponse("file1\r\nfile2");
+	std::ostringstream epsv;
+	epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
+	server.addResponse(epsv.str());
+	server.addResponse("150 sending data\r\n226 Transfer complete");
+
+	std::istream& istr = session.beginList();
+	std::ostringstream dataStr;
+	StreamCopier::copyStream(istr, dataStr);
+	session.endList();
+	std::string s(dataStr.str());
+	assertTrue (s == "file1\r\nfile2\r\n");
+
+	std::string cmd = server.popCommand();
+	assertTrue (cmd.substr(0, 4) == "EPSV");
+	cmd = server.popCommand();
+	assertTrue (cmd == "NLST");
+
+	server.addResponse("221 Good Bye");
+	session.close();
+}
+
+
+void FTPSClientSessionTest::setUp()
+{
+}
+
+
+void FTPSClientSessionTest::tearDown()
+{
+}
+
+
+CppUnit::Test* FTPSClientSessionTest::suite()
+{
+	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FTPSClientSessionTest");
+
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testLogin1);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testLogin2);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testLogin3);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testLoginFailed1);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testLoginFailed2);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testCommands);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadPORT);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadEPRT);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadPASV);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadEPSV);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testUpload);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testList);
+	CppUnit_addTest(pSuite, FTPSClientSessionTest, testUploadSSL);
+
+	return pSuite;
+}

+ 62 - 0
NetSSL_OpenSSL/testsuite/src/FTPSClientSessionTest.h

@@ -0,0 +1,62 @@
+//
+// FTPClientSessionTest.h
+//
+// Definition of the FTPClientSessionTest class.
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#ifndef FTPClientSessionTest_INCLUDED
+#define FTPClientSessionTest_INCLUDED
+
+
+#include "Poco/Net/Net.h"
+#include "Poco/CppUnit/TestCase.h"
+
+
+namespace Poco {
+namespace Net {
+
+class FTPSClientSession;
+
+} }
+
+
+class DialogServer;
+
+
+class FTPSClientSessionTest: public CppUnit::TestCase
+{
+public:
+	FTPSClientSessionTest(const std::string& name);
+	~FTPSClientSessionTest();
+
+	void testLogin1();
+	void testLogin2();
+	void testLogin3();
+	void testLoginFailed1();
+	void testLoginFailed2();
+	void testCommands();
+	void testDownloadPORT();
+	void testDownloadEPRT();
+	void testDownloadPASV();
+	void testDownloadEPSV();
+	void testUpload();
+	void testList();
+	void testUploadSSL();
+
+	void setUp();
+	void tearDown();
+
+	static CppUnit::Test* suite();
+
+private:
+	void login(DialogServer& server, Poco::Net::FTPSClientSession& session);
+};
+
+
+#endif // FTPClientSessionTest_INCLUDED

+ 22 - 0
NetSSL_OpenSSL/testsuite/src/FTPSClientTestSuite.cpp

@@ -0,0 +1,22 @@
+//
+// FTPClientTestSuite.cpp
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#include "FTPSClientTestSuite.h"
+#include "FTPSClientSessionTest.h"
+
+
+CppUnit::Test* FTPSClientTestSuite::suite()
+{
+	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FTPSClientTestSuite");
+
+	pSuite->addTest(FTPSClientSessionTest::suite());
+
+	return pSuite;
+}

+ 27 - 0
NetSSL_OpenSSL/testsuite/src/FTPSClientTestSuite.h

@@ -0,0 +1,27 @@
+//
+// FTPClientTestSuite.h
+//
+// Definition of the FTPClientTestSuite class.
+//
+// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
+// and Contributors.
+//
+// SPDX-License-Identifier:	BSL-1.0
+//
+
+
+#ifndef FTPClientTestSuite_INCLUDED
+#define FTPClientTestSuite_INCLUDED
+
+
+#include "Poco/CppUnit/TestSuite.h"
+
+
+class FTPSClientTestSuite
+{
+public:
+	static CppUnit::Test* suite();
+};
+
+
+#endif // FTPClientTestSuite_INCLUDED

+ 2 - 0
NetSSL_OpenSSL/testsuite/src/NetSSLTestSuite.cpp

@@ -14,6 +14,7 @@
 #include "TCPServerTestSuite.h"
 #include "HTTPSServerTestSuite.h"
 #include "WebSocketTestSuite.h"
+#include "FTPSClientTestSuite.h"
 
 
 CppUnit::Test* NetSSLTestSuite::suite()
@@ -24,6 +25,7 @@ CppUnit::Test* NetSSLTestSuite::suite()
 	pSuite->addTest(TCPServerTestSuite::suite());
 	pSuite->addTest(HTTPSServerTestSuite::suite());
 	pSuite->addTest(WebSocketTestSuite::suite());
+	pSuite->addTest(FTPSClientTestSuite::suite());
 
 	return pSuite;
 }