void CSSLClientAsync::OnConnect(BOOL bConnected)
{
    //无论是否连接成功,都认为已经判断结束
    SetCheckConnect(FALSE);
    //连接完毕,则删除写/错误事件的注册,改成读事件
    m_pio->Remove_WriteEvent(this);
    if (TRUE == bConnected)
    {
        SOCKET_IO_INFO("socket connect successed, remote ip: %s, port: %d.", GetRemoteIP(),
                       GetRemotePort());
        DoConnect(GetSocketID());
        SSL_set_mode(GetSSL(), SSL_MODE_AUTO_RETRY);
        if (SSL_set_fd(GetSSL(), GetSocket()) != 1)
        {
            SOCKET_IO_ERROR("ssl set fd failed");
            DoException(GetSocketID(), SOCKET_IO_SSL_CONNECT_FAILED);
            return;
        }
        SSLConnect();
    }
    else
    {
        SOCKET_IO_ERROR("socket connect failed, remote ip: %s, port: %d.", GetRemoteIP(), GetRemotePort());
        DoException(GetSocketID(), SOCKET_IO_TCP_CONNECT_FAILED);
    }
}
void CSSLClientAsync::OnRecv()
{
    if (GetSSLConnectStatus() == TRUE)
    {
        char szBuf[TCP_RECV_SIZE] = {0};
        int32_t nRet = SSL_read(GetSSL(), szBuf, TCP_RECV_SIZE);
        if (nRet > 0)
        {
            int32_t nBufSize = nRet;
            char szIP[32] = {0};
            int32_t nPort = 0;
            S_GetPeerName(GetSocket(), szIP, &nPort);
            DoRecv(GetSocketID(), szBuf, nBufSize, szIP, nPort);
        }
        else if (nRet == 0)
        {
            int32_t nErrorCode = SSL_get_error(GetSSL(), nRet);
            if (SSL_ERROR_ZERO_RETURN == nErrorCode)
            {
                //对方关闭socket
                SOCKET_IO_WARN("recv ssl data error, peer closed.");
                DoException(GetSocketID(), SOCKET_IO_SSL_RECV_FAILED);
            }
            else
            {
                SOCKET_IO_ERROR("recv ssl data error.");
                DoException(GetSocketID(), SOCKET_IO_SSL_RECV_FAILED);
            }
        }
        else
        {
            int32_t nErrorCode = SSL_get_error(GetSSL(), nRet);
            if (SSL_ERROR_WANT_READ == nErrorCode || SSL_ERROR_WANT_WRITE == nErrorCode)
            {
                //用select/epoll/iocp的方式应该很少会有这个情况出现
                SOCKET_IO_DEBUG("recv ssl data error, buffer is blocking.");
            }
            else
            {
                SOCKET_IO_ERROR("recv ssl data error, errno: %d.", nErrorCode);
                DoException(GetSocketID(), SOCKET_IO_SSL_RECV_FAILED);
            }
        }
    }
    else
    {
        SSLConnect();
    }
}
/**
 * @ingroup TcpStack
 * @brief TCP 연결 Thread
 * @param lpParameter CTcpClientArg 객체
 * @returns 0 을 리턴한다.
 */
THREAD_API TcpClientThread( LPVOID lpParameter )
{
	CTcpClientArg * pclsArg = (CTcpClientArg *)lpParameter;

	CLog::Print( LOG_INFO, "TcpClientThread started (%s:%d)", pclsArg->m_strIp.c_str(), pclsArg->m_iPort );

	Socket hConn = TcpConnect( pclsArg->m_strIp.c_str(), pclsArg->m_iPort, pclsArg->m_pclsStack->m_clsSetup.m_iTcpConnectTimeout );
	if( hConn == INVALID_SOCKET )
	{
		CLog::Print( LOG_ERROR, "%s TcpConnect(%s:%d) error(%d)", __FUNCTION__, pclsArg->m_strIp.c_str(), pclsArg->m_iPort, GetError() );

		pclsArg->m_pclsStack->m_clsClientMap.Delete( pclsArg->m_strIp.c_str(), pclsArg->m_iPort );
	}
	else
	{
		CTcpComm clsTcpComm;
		bool bAccept = true;

#ifdef USE_TLS
		if( pclsArg->m_pclsStack->m_clsSetup.m_bUseTls )
		{
			if( SSLConnect( hConn, &clsTcpComm.m_psttSsl ) == false )
			{
				CLog::Print( LOG_ERROR, "%s SSLConnect(%s:%d) error", __FUNCTION__, pclsArg->m_strIp.c_str(), pclsArg->m_iPort );
				closesocket( hConn );

				pclsArg->m_pclsStack->m_clsClientMap.Delete( pclsArg->m_strIp.c_str(), pclsArg->m_iPort );
				bAccept = false;
			}
		}
#endif

		if( bAccept )
		{
			if( pclsArg->m_pclsStack->m_clsSetup.m_bUseThreadPipe )
			{
				clsTcpComm.m_hSocket = hConn;
				snprintf( clsTcpComm.m_szIp, sizeof(clsTcpComm.m_szIp), "%s", pclsArg->m_strIp.c_str() );
				clsTcpComm.m_iPort = pclsArg->m_iPort;
				clsTcpComm.m_bClient = true;

				if( pclsArg->m_pclsStack->m_clsThreadList.SendCommand( (char *)&clsTcpComm, sizeof(clsTcpComm) ) == false )
				{
					CLog::Print( LOG_ERROR, "%s m_clsThreadList.SendCommand error", __FUNCTION__ );
					pclsArg->m_pclsStack->m_clsClientMap.Delete( pclsArg->m_strIp.c_str(), pclsArg->m_iPort );
					closesocket( hConn );
				}
			}
			else
			{
				CTcpNoPipeThreadArg * pclsNewArg = new CTcpNoPipeThreadArg();
				if( pclsNewArg == NULL )
				{
					CLog::Print( LOG_ERROR, "%s new error", __FUNCTION__ );
					closesocket( hConn );
				}
				else
				{
					pclsNewArg->m_hSocket = hConn;
					pclsNewArg->m_strIp = pclsArg->m_strIp;
					pclsNewArg->m_iPort = pclsArg->m_iPort;
					pclsNewArg->m_pclsStack = pclsArg->m_pclsStack;
					pclsNewArg->m_bClient = true;

					if( StartThread( "TcpNoPipeThread", TcpNoPipeThread, pclsNewArg ) == false )
					{
						CLog::Print( LOG_ERROR, "%s StartThread error", __FUNCTION__ );
						closesocket( hConn );
					}
				}

				pclsArg->m_pclsStack->m_clsClientMap.Delete( pclsArg->m_strIp.c_str(), pclsArg->m_iPort );
			}
		}
	}

	CLog::Print( LOG_INFO, "TcpClientThread terminated (%s:%d)", pclsArg->m_strIp.c_str(), pclsArg->m_iPort );

	delete pclsArg;

#ifdef USE_TLS
	if( pclsArg->m_pclsStack->m_clsSetup.m_bUseTls )
	{
		ERR_remove_thread_state( NULL );
	}
#endif
	
	return 0;
}