Purpose: Establish an SSL TCP connection to a server
| Return Type | Function name | Arguments |
|---|---|---|
| hzEcode | hzTcpClient::ConnectSSL | (const char*,uint32_t,uint32_t,uint32_t,) |
Declared in file: hzTcpClient.h
Defined in file : hzTcpClient.cpp
Function Logic:
Function body:
hzEcode hzTcpClient::ConnectSSL (const char* hostname)uint32_t nPort, uint32_t nTimeoutR, uint32_t nTimeoutS,
{
// Purpose: Establish an SSL TCP connection to a server
//
// Arguments: 1) hostname The server name or IP address
// 2) nPort The port number
// 3) nTimeoutR Timeout (Recv)
// 4) nTimeoutS Timeout (Send)
//
// Returns: E_DNS_NOHOST If the domain does not exist
// E_DNS_FAILED If the domain settings were invalid
// E_DNS_NODATA If the domain exists but no server found
// E_DNS_RETRY If the DNS was busy
// E_INITFAIL If the SSL client side settings fail
// E_NOSOCKET If a socket could not be obtained
// E_HOSTFAIL If no connection could be established or if socket options were not set.
// E_OK If a connection to the host was established
_hzfunc("hzTcpClient::ConnectSSL") ;
static bool bBeenHere = false ; // OPENSSL init state
const SSL_METHOD* sslMethod = 0; // SSL client method
SSL_CTX* sslCtx = 0; // SSL client CTX structure
int32_t sys_rc ; // Return from connect call
hzEcode rc = E_OK ; // Return code
// Ensure SSL/TLS is initialized
if (!bBeenHere)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
#else
OPENSSL_init_ssl(0,NULL);
#endif
bBeenHere = true ;
}
// Check we are not already connected
if (m_nSock)
{
if (m_Hostname == hostname && m_nPort == nPort)
return E_OK ;
m_Hostname.Clear() ;
m_pHost = 0;
Close() ;
}
if (m_Hostname && m_Hostname != hostname)
{
// At the point of call there was no socket but this hzTcpClient instance has a hostname from a previous connection. If this differs from the host now
// being sought then the m_pHost value will be invalid and a fresh call to gethostbyname is required.
m_Hostname = hostname ;
m_pHost = 0;
}
// Get the host IP
m_pHost = gethostbyname(hostname) ;
if (!m_pHost)
{
threadLog("No Host found\n") ;
if (h_errno == TRY_AGAIN) return E_DNS_RETRY ;
if (h_errno == HOST_NOT_FOUND) return E_DNS_NOHOST ;
if (h_errno == NO_RECOVERY) return E_DNS_FAILED ;
if (h_errno == NO_DATA || h_errno == NO_ADDRESS)
return E_DNS_NODATA ;
m_Hostname.Clear() ;
return hzerr(E_DNS_NOHOST, "Unknown Host [%s]\n", hostname) ;
}
m_Hostname = hostname ;
m_nPort = nPort ;
// Create the socket
memset(&m_SvrAddr, 0,sizeof(m_SvrAddr)) ;
m_SvrAddr.sin_family = AF_INET ;
memcpy(&m_SvrAddr.sin_addr, m_pHost->h_addr, m_pHost->h_length) ;
m_SvrAddr.sin_port = htons(nPort) ;
if ((m_nSock = socket(AF_INET, SOCK_STREAM, 0))< 0)
return hzerr(E_INITFAIL, "Could not create socket (returns %d, errno=%d)", m_nSock, errno) ;
threadLog("Using socket %d\n", m_nSock) ;
// Establish a standard, non-SSL TCP/IP connection
sys_rc = connect(m_nSock, (SOCKADDR*) &m_SvrAddr, sizeof(m_SvrAddr)) ;
if (sys_rc < 0)
{
threadLog("Could not connect to host (returns %d)", sys_rc) ;
return hzerr(E_HOSTFAIL, "Could not connect to host [%s] on port %d (errno=%d)", *m_Hostname, m_nPort, errno) ;
}
threadLog("Connected\n") ;
// Apply timeouts
if (!nTimeoutR) nTimeoutR = 90;
if (!nTimeoutS) nTimeoutS = 90;
if (rc == E_OK) rc = SetRecvTimeout(nTimeoutR) ;
if (rc == E_OK) rc = SetSendTimeout(nTimeoutS) ;
if (rc != E_OK)
return hzerr(rc, "Could not set connection timeouts") ;
threadLog("Socket options set\n") ;
/*
** ** SSL/TLS part
** */
sslMethod = TLS_client_method() ;
if (!sslMethod)
{
Close() ;
return hzerr(E_INITFAIL, "No SSL Client Method issued") ;
}
threadLog("Method set\n") ;
sslCtx = SSL_CTX_new(sslMethod) ;
if (!sslCtx)
{
Close() ;
hzerr(E_INITFAIL, "No SSL Structure issued") ;
}
threadLog("CTX Created\n") ;
m_pSSL = SSL_new(sslCtx) ;
if (!m_pSSL)
{
threadLog("Could not allocate SSL structure\n") ;
return E_HOSTFAIL ;
}
threadLog("SSL allocated\n") ;
/*
** if (SSL_CTX_set_cipher_list(sslCtx, "ECDHE-RSA-AES128-GCM-SHA256") <= 0)
** {
** threadLog("Error setting the cipher list.\n");
** return E_HOSTFAIL ;
** }
** threadLog("Cipers Listed\n") ;
** */
sys_rc = SSL_set_fd(m_pSSL, m_nSock);
if (sys_rc != 1)
{
threadLog("Could not set SSL file descriptor\n") ;
return E_HOSTFAIL ;
}
threadLog("SSL fd set\n") ;
SSL_set_tlsext_host_name(m_pSSL, *m_Hostname) ;
SSL_set_connect_state(m_pSSL) ;
threadLog("SSL set as client\n") ;
sys_rc = SSL_connect(m_pSSL);
// sys_rc = SSL_do_handshake(m_pSSL);
threadLog("Handshake done\n") ;
if (sys_rc != 1)
{
threadLog("Could not connect: %s\n", ShowErrorSSL(SSL_get_error(m_pSSL, sys_rc))) ;
return E_HOSTFAIL ;
}
threadLog("Connected Secure\n") ;
/*
** Move to separate function or scrap
** if (bCheckCert)
** {
** if (SSL_get_peer_certificate(m_pSSL) != NULL)
** {
** if (SSL_get_verify_result(m_pSSL) == X509_V_OK)
** threadLog("Client verification with SSL_get_verify_result() succeeded.\n") ;
** else
** threadLog("Client verification with SSL_get_verify_result() failed.\n") ;
** }
** }
** */
return E_OK ;
}