bool CClient::Start() { do { if (m_socket == INVALID_SOCKET) { m_socket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); if (m_socket == INVALID_SOCKET) { LOGNET("Fail to create client[%d] socket.", GetID()); break; } } static GUID GuidAcceptEx = WSAID_ACCEPTEX; static LPFN_ACCEPTEX AcceptEx = (LPFN_ACCEPTEX)GetExtensionFunction(m_pServer->GetListenSocket(), GuidAcceptEx); NetData* pData = m_accept.GetNetData(); pData->extra = this; DWORD recvLen = 0; if (AcceptEx(m_pServer->GetListenSocket(), m_socket, pData->buffer.buf, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, &recvLen, &pData->overlapped) == FALSE) { if (WSAGetLastError() != WSA_IO_PENDING) { LOGNET("Client[%d] fail to call AcceptEx.", GetID()); break; } } return true; } while (false); Stop(); return false; }
void Connection::sendMsg(SendPacket* p) { if (m_status != CONN_STATUS_CONNECTED) { LOGERROR() << "sendmsg status not connected" <<"id"<<m_id <<LOGEND(); return; } short opCode = p->getOPCode(); std::string body = p->getData(); unsigned int pack = (13 << 24) + (body.size() & 0xFFFFFF); char header[MSG_HEADER_SIZE] = {0}; memmove(header, (char*)&opCode, sizeof(opCode)); memmove(header+sizeof(opCode), (char*)&pack, sizeof(pack)); std::stringstream ss; ss << std::string(header, 6) << body; m_outData.push_back(ss.str()); LOGNET() << "try send msg " << opCode << " pack size " << body.size() << LOGEND(); tryWrite(); }
// get some data void Connection::handleRead(const boost::system::error_code& error, size_t len) { if(!error) { LOGNET() << ">>> got " << len << " data from " <<"id"<<m_id <<LOGEND(); m_offSet += len; m_msgBuffer.push_back(std::string(m_buffer, m_buffer+m_offSet)); m_offSet = 0; // continue to read tryRead(); handlePacket(); } else { if (m_status == CONN_STATUS_CONNECTED) { m_status = CONN_STATUS_DISCONNECT; } else { // triggered by other event } if (m_writeStatus != SW_STATUS_WRITTING) { m_errHandler(error, this, "handleread"); } else { // write callback will call immediately } } }
void Connection::handleWrite(const boost::system::error_code& error, size_t len) { if(!error) { m_writeStatus = SW_STATUS_WRITEDONE; assert(m_outData.size() > 0); // ok write some chars //std::string& buf = m_outData.front(); // first buffer all flushed if (len == m_tempBuf.length()) { LOGNET() << "<<< write full " << len << " " <<"id"<<m_id << LOGEND(); m_outData.pop_front(); tryWrite(); } else { //LOGNET() << "<<< write partial " << len << " should " << buf.length() << " " LOGNET() << "<<< write partial " << len << " should " << m_tempBuf.length() << " " <<"id"<<m_id << LOGEND(); assert(len < m_tempBuf.length()); //buf = buf.substr(len); m_tempBuf = m_tempBuf.substr(len); tryWrite(); } } else { if (m_status == CONN_STATUS_CONNECTED) { m_status = CONN_STATUS_DISCONNECT; } else { // triggered by other event } if (m_errHandler) { m_errHandler(error, this, "handlewrite"); } } }
void CClient::TimeRoutine(int now) { CLock lock(&m_criticalSection); switch (m_status) { case NETSTATUS_CompletionNotify: { if (m_lastActionTime) { if (now-m_lastActionTime > MAX_IDLE_TIME) { LOG("Client[%d] has been idled for a long time.", GetID()); Restart(NETOP_Receive); } } else { DWORD connectTime = 0; int optSize = sizeof(connectTime); if (getsockopt(m_socket, SOL_SOCKET, SO_CONNECT_TIME, (char*)&connectTime, &optSize) == SOCKET_ERROR) { LOGNET("Client[%d] fail to get socket connection time.", GetID()); } else { if (connectTime!=0xFFFFFFFF && connectTime>DENIAL_SERVICE_TIME) { LOG("Client[%d] may be a malicious application.", GetID()); Restart(NETOP_Receive); } } } } break; case NETSTATUS_Disconnecting: { if (m_lastActionTime) { if (now-m_lastActionTime > MAX_DISCONNECT_TIME) { LOG("Client[%d] has been in disconnecting for a long time.", GetID()); Restart(NETOP_Disconnect); } } else { LOG("Client[%d] has been in disconnecting, but last action time is zero.", GetID()); } } break; default: break; } }
bool CClient::AppendDisconnect(bool restart) { static GUID GuidDisconnectEx = WSAID_DISCONNECTEX; static LPFN_DISCONNECTEX DisconnectEx = (LPFN_DISCONNECTEX)GetExtensionFunction(m_socket, GuidDisconnectEx); CLock lock(&m_criticalSection); NetData* pData = m_discon.GetNetData(); if (DisconnectEx(m_socket, &pData->overlapped, TF_REUSE_SOCKET, 0) == FALSE) { if (WSAGetLastError() != WSA_IO_PENDING) { LOGNET("Client[%d] to call DisconnectEx.", GetID()); return false; } } m_status = NETSTATUS_Disconnecting; m_lastActionTime = (int)time(NULL); return true; }
bool CClient::AppendReceive() { CLock lock(&m_criticalSection); if (m_status != NETSTATUS_CompletionNotify) return true; NetData* pData = m_recv.GetNetData(); DWORD recvBytes = 0; DWORD flag = 0; if (WSARecv(m_socket, &pData->buffer, 1, &recvBytes, &flag, &pData->overlapped, NULL) == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { LOGNET("Client[%d] fail to call WSARecv.", GetID()); return false; } } return true; }
bool CClient::AppendSend() { CLock lock(&m_criticalSection); if (m_status != NETSTATUS_CompletionNotify) return true; m_send.Tidy(); NetData* pData = m_send.GetNetData(); DWORD sendBytes = 0; if (WSASend(m_socket, &pData->buffer, 1, &sendBytes, 0, &pData->overlapped, NULL) == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { LOGNET("Client[%d] fail to call WSASend.", GetID()); return false; } } return true; }
bool CClient::PostConnect(NetData* pData) { CLock lock(&m_criticalSection); m_status = NETSTATUS_Connected; SOCKADDR* localAddr = NULL; SOCKADDR* remoteAddr = NULL; int localAddrLen = 0; int remoteAddrLen = 0; GetAcceptExSockaddrs(pData->buffer.buf, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, &localAddr, &localAddrLen, &remoteAddr, &remoteAddrLen); SOCKET listenSocket = m_pServer->GetListenSocket(); if (setsockopt(m_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (const char*)&listenSocket, sizeof(listenSocket)) == SOCKET_ERROR) { LOGNET("Client[%d] fail to update accept context.", GetID()); return false; } if (!m_completePort) { if (CreateIoCompletionPort((HANDLE)m_socket, m_pManager->GetIOCompletePort(), (ULONG_PTR)this, 0) == NULL) { LOG("Fail to associate client[%d] socket with completion port.", GetID()); return false; } m_completePort = true; } m_send.Clean(); m_recv.Clean(); m_discon.Clean(); m_accept.Clean(); m_lastActionTime = 0; m_status = NETSTATUS_CompletionNotify; return true; }
void Connection::handlePacket() { int count = 0; while(count++ < 20) { if(this->getBufSize() <= 0) { break; } std::string header; bool flag = this->getMsgSize(&header, MSG_HEADER_SIZE); if (!flag) { LOGERROR() << "not enough header" << LOGEND(); break; } else { char* buf = &header[0]; // check msg header int offset = 0; short msgID = 0; memcpy(&msgID, buf, sizeof(msgID)); unsigned int pack = 0; memcpy(&pack, buf+sizeof(msgID), sizeof(pack)); int msgSize = pack & 0xFFFFFF; unsigned int chaos = pack >> 24; if (chaos != 13) { LOGERROR() << "wrong pack chaos " << chaos << " msg " << msgID << " from " <<"id"<<m_id << LOGEND(); return; } // todo check valid msgid // body std::string body; flag = getMsgSize(&body, MSG_HEADER_SIZE+msgSize); if(flag) { this->skipMsgSize(msgSize+MSG_HEADER_SIZE); body.erase(0, MSG_HEADER_SIZE); LOGNET() << ">>> got msg " << msgID << " size " << msgSize << LOGEND(); Packet p(msgID, body); MsgHandlerType handler = MsgHandler::getHandler(p.getOP()); if (handler) { bool flag = handler(this, &p); if (!flag) { LOGERROR() << "return false handle " << p.getOP() << LOGEND(); } } else { LOGERROR() << "didn't find handler for " << p.getOP() << LOGEND(); } } else { LOGNET() << "not enough body need " << msgSize << " but have " << m_offSet - MSG_HEADER_SIZE << " msgID=" << msgID << LOGEND(); } } } }