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();
    }
}
int32_t CSSLClientAsync::SSLConnect()
{
    int32_t nErrorCode = SOCKET_IO_SSL_CONNECT_FAILED;
    
    //阻塞的ssl_connect可能会有一个问题,服务端如果不对此处理,可能会一直卡在SSL_connect这个接口
    //此处采用非阻塞的ssl_connect
    int32_t nRet = SSL_connect(GetSSL());
    if (nRet == 1)
    {
        nErrorCode = SOCKET_IO_RESULT_OK;
        SOCKET_IO_INFO("ssl connect successed, remote ip: %s, port: %d.", GetRemoteIP(), GetRemotePort());
        SetSSLConnectStatus(TRUE);
        DoSSLConnect(GetSocket());
    }
    else if (nRet == 0)
    {
        int32_t ssl_error_code = SSL_get_error(GetSSL(), nRet);
        SOCKET_IO_ERROR("ssl connect was shut down, remote ip: %s, port: %d, error code: %d.",
                        GetRemoteIP(), GetRemotePort(), ssl_error_code);
        DoException(GetSocketID(), SOCKET_IO_SSL_CONNECT_FAILED);
    }
    else
    {
        int32_t ssl_error_code = SSL_get_error(GetSSL(), nRet);
        if (SSL_ERROR_WANT_READ == ssl_error_code || SSL_ERROR_WANT_WRITE == ssl_error_code)
        {
            SOCKET_IO_WARN("ssl connect is blocking, remote ip: %s, port: %d, error code: %d.",
                           GetRemoteIP(), GetRemotePort(), ssl_error_code);
        }
        else
        {
            SOCKET_IO_ERROR("ssl connect failed, remote ip: %s, port: %d, error code: %d.",
                            GetRemoteIP(), GetRemotePort(), ssl_error_code);
            DoException(GetSocketID(), SOCKET_IO_SSL_CONNECT_FAILED);
        }
    }
    return nErrorCode;
}
Example #4
0
/**	@fn	int32_t CTCPClientAsync::ConnectAsync(const char* szIP, HPR_INT32 nPort)
*	@brief 
*	@param[in] szIP 
*	@param[in] nPort 
*	@return	返回值为0
*/
int32_t CTCPClientAsync::ConnectAsync( const char* szIP, int nPort )
{
	SetRemoteIP(szIP);
	SetRemotePort(nPort);
    //windows:这种做法对select没有用
    //linux:这个做法也没有效果
    //S_SetSendTimeOut(GetSocket(), 10);
    
    SOCKET_IO_INFO("connect remote ip: %s, port: %d.", szIP, nPort);
	if (S_Connect(GetSocket(), szIP, nPort) != 0)
	{
#if (defined(_WIN32) || defined(_WIN64))
		int32_t nError = ::GetLastError();
		if (nError != WSAEWOULDBLOCK)
#else
		int32_t nError = errno;
		if (nError != EINPROGRESS)
#endif
		{
			//连接出错
			SOCKET_IO_ERROR("connect error, errno: %d.", nError);
			DoException(GetSocketID(), SOCKET_IO_TCP_CONNECT_FAILED);
		}
		else
		{
			//连接建立已启动,但是还未成功
		}
        //对于tcp client来说,在此处在加入io中
        m_pio->Add_Handler(this);
        //对于windows/linux 的select来说,connect需要激活可写事件
        //对于epoll来说,激活的是EPOLLERR?
        m_pio->Add_WriteEvent(this);
	}
	else
	{
        //对于tcp client来说,在此处在加入io中
        m_pio->Add_Handler(this);
        //对于windows/linux 的select来说,connect需要激活可写事件
        //对于epoll来说,激活的是EPOLLERR?
        m_pio->Add_WriteEvent(this);
        
		//连接成功,一般连接的是本地端口可能会立即成功
		OnConnect(TRUE);
	}
	return 0;
}
Example #5
0
/**	@fn	int32_t CTCPClientAsync::SendBufferAsync()
*	@brief 将待发送队列中的数据发送出去
*	@return	
*/
int32_t CTCPClientAsync::SendBufferAsync()
{
	int32_t nErrorCode = 0;
	m_sendqueuemutex.Lock();
	if (m_sendqueue.size() == 0)
	{
        //待发送队列中为空,则删除写事件的注册,改成读事件
        m_pio->Remove_WriteEvent(this);
        m_sendqueuemutex.Unlock();
        if (_GetWaitForCloseStatus() == TRUE)
        {
            //待发送内容发送完毕,则关闭链接
            _Close();
        }
        return nErrorCode;
	}
	CSimpleBuffer* pBufferLoop = m_sendqueue.front();
	m_sendqueuemutex.Unlock();
	int32_t nRet = S_Send(GetSocket(), (void*)pBufferLoop->GetBuffer(), pBufferLoop->GetWriteOffset());
	if ( nRet < 0)
	{
#if (defined(_WIN32) || defined(_WIN64))
		int32_t nError = ::GetLastError();
		if (WSAEWOULDBLOCK == nError)
#else
		int32_t nError = errno;
		if (EAGAIN == nError)
#endif
		{
			SOCKET_IO_DEBUG("send tcp data, buffer is blocking.")
		}
		else
		{
            _ClearSendBuffer();
			SOCKET_IO_ERROR("send tcp data error, errno: %d.", nError);
			DoException(GetSocketID(), SOCKET_IO_TCP_SEND_FAILED);
		}
	}
int32_t CSSLClientAsync::SendBufferAsync()
{
    int32_t nErrorCode = SOCKET_IO_RESULT_OK;
    m_sendqueuemutex.Lock();
    if (m_sendqueue.size() == 0)
    {
        SOCKET_IO_DEBUG("ssl send queue is empty.");
        //待发送队列中为空,则删除写事件的注册,改成读事件
        m_pio->Remove_WriteEvent(this);
        m_sendqueuemutex.Unlock();
        if (_GetWaitForCloseStatus() == TRUE)
        {
            //待发送内容发送完毕,则关闭链接
            _Close();
        }
        return nErrorCode;
    }
    CSimpleBuffer* pBufferLoop = m_sendqueue.front();
    m_sendqueuemutex.Unlock();
    int32_t nRet = SSL_write(GetSSL(), (void*)pBufferLoop->GetBuffer(), pBufferLoop->GetWriteOffset());
    if ( nRet < 0)
    {
        int32_t nError = SSL_get_error(GetSSL(), nRet);
        if (SSL_ERROR_WANT_WRITE == nError || SSL_ERROR_WANT_READ == nError)
        {
            SOCKET_IO_INFO("send ssl data, buffer is blocking, errno: %d.", nError);
        }
        else
        {
            _ClearSendBuffer();
            SOCKET_IO_ERROR("send ssl data error, errno: %d.", nError);
            DoException(GetSocketID(), SOCKET_IO_SSL_SEND_FAILED);
        }
    }
    else if (nRet == 0)
    {
        int32_t nError = SSL_get_error(GetSSL(), nRet);
        if (SSL_ERROR_ZERO_RETURN == nError)
        {
            SOCKET_IO_WARN("send ssl data error, peer closed.");
        }
        else
        {
            SOCKET_IO_ERROR("send ssl data error, errno: %d.", nError);
        }
        _ClearSendBuffer();
        DoException(GetSocketID(), SOCKET_IO_SSL_SEND_FAILED);
    }
    else if (nRet != pBufferLoop->GetWriteOffset())
    {
        //将未成功的数据重新放置buffer loop中,待下次发送
        //对于ssl来说,应该不会出现此种情况
        int32_t nSize = 0;
        pBufferLoop->Read(NULL, nRet);
        SOCKET_IO_WARN("send ssl data, send size: %d, less than %d.", nRet, pBufferLoop->GetWriteOffset());
    }
    else
    {
        SOCKET_IO_INFO("send ssl data from buffer successed.");
        m_sendqueuemutex.Lock();
        delete pBufferLoop;
        pBufferLoop = NULL;
        m_sendqueue.pop();
        m_sendqueuemutex.Unlock();
    }
    return nErrorCode;
}
int32_t CSSLClientAsync::SendMsgAsync(const char *szBuf, int32_t nBufSize)
{
    CSimpleBuffer* pBufferLoop = new CSimpleBuffer();
    pBufferLoop->Write(szBuf, nBufSize);
    
    m_sendqueuemutex.Lock();
    if (m_sendqueue.size() != 0)
    {
        if (_GetWaitForCloseStatus() == TRUE)
        {
            SOCKET_IO_DEBUG("send ssl data error, socket will be closed.");
            delete pBufferLoop;
            pBufferLoop = NULL;
        }
        else
        {
            if (m_sendqueue.size() >= MAX_SEND_QUEUE_SIZE) {
                SOCKET_IO_WARN("send ssl data error, buffer is overload.");
                delete pBufferLoop;
                pBufferLoop = NULL;
            }
            else
            {
                SOCKET_IO_INFO("send ssl data, push data to buffer.");
                m_sendqueue.push(pBufferLoop);
                //m_pio->Add_WriteEvent(this);
            }
        }
        m_sendqueuemutex.Unlock();
        return SOCKET_IO_RESULT_OK;
    }
    m_sendqueuemutex.Unlock();
    
    int32_t nRet = SSL_write(GetSSL(), (void*)pBufferLoop->GetBuffer(), pBufferLoop->GetWriteOffset());
    if ( nRet < 0)
    {
        int32_t nError = SSL_get_error(GetSSL(), nRet);
        if (SSL_ERROR_WANT_WRITE == nError || SSL_ERROR_WANT_READ == nError)
        {
            m_sendqueuemutex.Lock();
            m_sendqueue.push(pBufferLoop);
            m_sendqueuemutex.Unlock();
            //有数据放入待发送队列,则注册为写事件
            m_pio->Add_WriteEvent(this);
            SOCKET_IO_INFO("send ssl data, buffer is blocking, errno: %d.", nError);
        }
        else
        {
            delete pBufferLoop;
            pBufferLoop = NULL;
            SOCKET_IO_ERROR("send ssl data error, errno: %d.", nError);
            DoException(GetSocketID(), SOCKET_IO_SSL_SEND_FAILED);
        }
    }
    else if (nRet == 0)
    {
        int32_t nError = SSL_get_error(GetSSL(), nRet);
        if (SSL_ERROR_ZERO_RETURN == nError)
        {
            SOCKET_IO_WARN("send ssl data error, peer closed.");
        }
        else
        {
            SOCKET_IO_ERROR("send ssl data error, errno: %d.", nError);
        }
        delete pBufferLoop;
        pBufferLoop = NULL;
        DoException(GetSocketID(), SOCKET_IO_SSL_SEND_FAILED);
    }
    else if (nRet != nBufSize)
    {
        int32_t nRest = nBufSize - nRet;
        pBufferLoop->Read(NULL, nRet);
        m_sendqueuemutex.Lock();
        m_sendqueue.push(pBufferLoop);
        m_sendqueuemutex.Unlock();
        //有数据放入待发送队列,则注册为写事件
        //对于ssl来说,应该不会出现此种情况
        m_pio->Add_WriteEvent(this);
        SOCKET_IO_WARN("send ssl data, send size: %d, less than %d.", nRet, nBufSize);
    }
    else if (nRet == nBufSize)
    {
        delete pBufferLoop;
        pBufferLoop = NULL;
        SOCKET_IO_DEBUG("send ssl data successed.");
    }
    else
    {
        delete pBufferLoop;
        pBufferLoop = NULL;
    }
    return SOCKET_IO_RESULT_OK;
}