The client error is because when TIdServerIOHandlerSSLOpenSSL
accepts a new client connection, the PassThrough
property of the client's IOHandler is set to true by default, thus SSL/TLS is not active yet. This allows the server to decide dynamically, on a per-connection basis, whether to activate SSL/TLS or not. Such as if your server is listening on multiple ports and only uses SSL on certain ports. Or if your protocol implements a STARTTLS
style command. So you need to set the PassThrough
property to false when you are ready to accept the SSL/TLS handshake, eg:
void __fastcall ServerOnConnect(TIdContext* context)
{
std::cout << "Client connected" << std::endl;
static_cast<TIdSSLIOHandlerSocketOpenSSL*>(context->Connection->IOHandler)->PassThrough = false;
}
On the client side, set PassThrough
to false when you are ready to initiate a SSL/TLS handshake:
ioHandler->PassThrough = false;
If PassThrough
is false when Connect()
is called, the handshake will be performed immediately once the socket successfully connects to the server.
With that said, Indy relies on exceptions, so you should not use a try/catch
block in the OnExecute
event handler. You can use the OnException
event to log uncaught exceptions, eg:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
conn->Disconnect();
}
void __fastcall ServerOnException(TIdContext* ctx, Exception *excpt)
{
std::cout << AnsiString(excpt->Message).c_str() << std::endl;
}
But, if you must use a try/catch
then be sure to re-throw any EIdException
based exceptions you catch. Let TIdTCPServer
handle them, eg:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
try
{
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
}
catch(const Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
if (dynamic_cast<const EIdException*>(&e))
throw;
}
conn->Disconnect();
}
Or:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
try
{
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
}
catch(const EIdException&)
{
throw;
}
catch(const Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
}
conn->Disconnect();
}
Also, these lines are also wrong:
ioHandler->SSLOptions->SSLVersions << sslvSSLv23;
ioHandler->SSLOptions->VerifyMode.Clear();
You cannot use the <<
operator on a property, and calling Clear()
is a no-op. The reason is because both lines are invoking the property getters and then manipulating temp objects that are not assigned back to the properties afterwards. You have to do that manually:
ioHandler->SSLOptions->SSLVersions = TIdSSLVersions() << sslvSSLv23;
ioHandler->SSLOptions->VerifyMode = TIdSSLVerifyModeSet();
And lastly:
#pragma link "IndyCore140.lib"
#pragma link "IndyProtocols140.lib"
#pragma link "IndySystem140.lib"
You should not be linking to Indy's .lib files directly. Your project's .bpr/.cproj file, not your code, should contain references to Indy's runtime packages instead.