void CSSLClientAsync::UnInitSSL() { if (m_ssl) { int32_t nRet = SSL_shutdown(m_ssl); if (nRet == 0) { int32_t nErrorCode = SSL_get_error(GetSSL(), nRet); SOCKET_IO_WARN("ssl shutdown not finished, errno: %d.", nErrorCode); } else if (nRet == 1) { SOCKET_IO_DEBUG("ssl shutdown successed."); } else if (nRet < 0) { int32_t nErrorCode = SSL_get_error(GetSSL(), nRet); SOCKET_IO_ERROR("ssl shutdown failed, errno: %d.", nErrorCode); } SSL_free(m_ssl); m_ssl = NULL; } if (m_ctx) { SSL_CTX_free(m_ctx); m_ctx = NULL; } }
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(); } }
void CSSLClientAsync::_Close() { if (m_ssl) { UnInitSSL(); } if (GetSocket() != S_INVALID_SOCKET) { if (m_pio) { m_pio->Remove_Handler(this); } SetSSLConnectStatus(FALSE); S_CloseSocket(GetSocket()); SOCKET_IO_WARN("close ssl socket, sock %d, real sock: %d.", GetSocketID(), GetSocket()); m_socket = S_INVALID_SOCKET; DoClose(GetSocketID()); _ClearSendBuffer(); } }
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; }
/** @fn void CEpollIOLoop::Run() * @brief * @return */ void CEpollIOLoop::Run() { struct epoll_event ev; ev.data.fd=m_waker.GetWakeSocket(); //设置要处理的事件类型 ev.events=EPOLLIN; epoll_ctl(m_eid, EPOLL_CTL_ADD, m_waker.GetWakeSocket(), &ev); while (TRUE) { struct epoll_event* events = new epoll_event[_GetEpollSize()]; int32_t nfds = epoll_wait(m_eid, events, _GetEpollSize(), -1); if (nfds <= 0) continue; for (int32_t i = 0; i < nfds; i++) { S_SOCKET sock = events[i].data.fd; if (sock == m_waker.GetWakeSocket()) { m_waker.Recv(); } else if (events[i].events & EPOLLIN) { CBaseIOStream* pIOStream = _GetHandlerBySock(sock); if (pIOStream != NULL) { if (pIOStream->GetSockType() == SOCK_TCP_SERVER) { pIOStream->OnAccept(); } else { pIOStream->OnRecv(); SOCKET_IO_TRACE("socket recv data, sock id: %d.", pIOStream->GetSocketID()); } } else { //调试的时候可能数据还没读,但是对象已经没了,需要清掉 //epoll也会在调用close(sock)后会自己清除。 epoll_ctl(m_eid, EPOLL_CTL_DEL, sock, &events[i]); } }//EPOLLIN else if (events[i].events & EPOLLOUT) { CBaseIOStream* pIOStream = _GetHandlerBySock(sock); if (pIOStream != NULL) { if (pIOStream->GetSockType() == SOCK_TCP_CLIENT && pIOStream->CheckConnect()) { //连接成功 pIOStream->OnConnect(TRUE); } pIOStream->SendBufferAsync(); } }//EPOLLOUT else if (events[i].events & EPOLLERR) { CBaseIOStream* pIOStream = _GetHandlerBySock(sock); if (pIOStream->GetSockType() == SOCK_TCP_CLIENT && pIOStream->CheckConnect()) { int32_t nError, nCode; socklen_t nLen; nLen = sizeof(nError); nCode = getsockopt(pIOStream->GetSocket(), SOL_SOCKET, SO_ERROR, &nError, &nLen); if (nCode < 0 || nError) { //连接失败 SOCKET_IO_WARN("socket connect failed, nCode: %d, nError: %d.", nCode, nError); pIOStream->OnConnect(FALSE); } } }//EPOLLERR } } }
/** @fn void CIOLoop::Run() * @brief * @return */ void CIOLoop::Run() { fd_set fd_read, fd_write, fd_error; while (m_bCloseRequest == FALSE) { int nMaxfd = 0; FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_error); FD_SET(m_waker.GetWakeSocket(), &fd_read); if(m_waker.GetWakeSocket() > nMaxfd) nMaxfd = m_waker.GetWakeSocket(); m_MapMutex.Lock(); map<S_SOCKET, CBaseIOStream*> mapTmp = m_MapIOStreamBySocket; m_MapMutex.Unlock(); map<S_SOCKET, CBaseIOStream*>::iterator it = mapTmp.begin(); for (; it != mapTmp.end(); it++) { CBaseIOStream* pIOStream = it->second; if (pIOStream->CheckConnect() == FALSE) { //如果是要检查TCP CLIENT是否连接,则不设置可读 FD_SET(it->first, &fd_read); if(it->first > nMaxfd) nMaxfd = it->first; } if (pIOStream->CheckWrite() == TRUE) { //设置可写 FD_SET(it->first, &fd_write); if(it->first > nMaxfd) nMaxfd = it->first; //设置错误信号,用于windows的tcp connect超时检查,同时查看是否有其他触发错误 FD_SET(it->first, &fd_error); } } timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; int nRet = select(nMaxfd + 1, &fd_read, &fd_write, &fd_error, NULL); if (nRet > 0) { if (FD_ISSET(m_waker.GetWakeSocket(), &fd_read)) { //stop m_waker.Recv(); } map<S_SOCKET, CBaseIOStream*>::iterator it1 = mapTmp.begin(); for (; it1 != mapTmp.end(); it1++) { //read if (FD_ISSET(it1->first, &fd_read)) { CBaseIOStream* pIOStream = _GetHandlerBySock(it1->first); if (pIOStream != NULL) { if (pIOStream->GetSockType() == SOCK_TCP_SERVER) { pIOStream->OnAccept(); } else { pIOStream->OnRecv(); } } }//read //write if (FD_ISSET(it1->first, &fd_write)) { CBaseIOStream* pIOStream = _GetHandlerBySock(it1->first); if (pIOStream != NULL) { if (pIOStream->GetSockType() == SOCK_TCP_CLIENT && pIOStream->CheckConnect()) { #if (defined(_WIN32) || defined(_WIN64)) pIOStream->OnConnect(TRUE); //#elif defined(__linux__) //mac??? #else //这个是unix的处理方式,经测试linux也适用,mac同理 int32_t nError, nCode; socklen_t nLen; nLen = sizeof(nError); nCode = getsockopt(pIOStream->GetSocket(), SOL_SOCKET, SO_ERROR, &nError, &nLen); if (nCode < 0 || nError) { //连接失败 //linux的超时失败是也是根据这个可以判断 SOCKET_IO_WARN("socket connect failed, nCode: %d, nError: %d.", nCode, nError); pIOStream->OnConnect(FALSE); } else { //连接成功 //SOCKET_IO_WARN("socket connect successed.", nCode, nError); pIOStream->OnConnect(TRUE); } #endif } pIOStream->SendBufferAsync(); } }//wirte //error if (FD_ISSET(it1->first, &fd_error)) { CBaseIOStream* pIOStream = _GetHandlerBySock(it1->first); if (pIOStream != NULL) { //windows的超时判断是利用err_fds来判断 //对于不存在的IP(即linux会报111错误),或者IP存在,端口不存在(即linux会报110错误) //都是超时错误 if (pIOStream->CheckConnect() == TRUE) { SOCKET_IO_WARN("socket connect time out, remote ip: %s, port: %d.", pIOStream->GetRemoteIP(), pIOStream->GetRemotePort()); pIOStream->OnConnect(FALSE); } else { SOCKET_IO_WARN("err_fds, %d.", (int32_t)pIOStream->GetSockType()); } } }//error }//for }// nRet > 0 else if (0 == nRet) { //Time Out //map<HPR_SOCK_T, CBaseIOStream*>::iterator it1 = mapTmp.begin(); //for (; it1 != mapTmp.end(); it1++) //{ // //write // CBaseIOStream* pIOStream = _GetHandlerBySock(it1->first); // if (pIOStream != NULL) // { // if (pIOStream->GetSockType() == SOCK_TCP_CLIENT && pIOStream->CheckConnect()) // { // } // } //} } else { //TODO //Error SOCKET_IO_ERROR("socket select error"); break; } } }
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; }