bool EmuTCPConnection::SendPacket(ServerPacket* pack, uint32 iDestination) { if (!Connected()) return false; eTCPMode tmp = GetMode(); if (tmp != modePacket && tmp != modeTransition) return false; LockMutex lock(&MState); if (RemoteID) return RelayLink->SendPacket(pack, RemoteID); else if (pOldFormat) { #if TCPN_LOG_PACKETS >= 1 if (pack && pack->opcode != 0) { struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Logging outgoing TCP OldPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl; #if TCPN_LOG_PACKETS == 2 if (pack->size >= 32) DumpPacket(pack->pBuffer, 32); else DumpPacket(pack); #endif #if TCPN_LOG_PACKETS >= 3 DumpPacket(pack); #endif } #endif SPackSendQueue* spsq = MakeOldPacket(pack); ServerSendQueuePushEnd(spsq->buffer, spsq->size); safe_delete_array(spsq); } else { EmuTCPNetPacket_Struct* tnps = MakePacket(pack, iDestination); if (tmp == modeTransition) { InModeQueuePush(tnps); } else { #if TCPN_LOG_PACKETS >= 1 if (pack && pack->opcode != 0) { struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Logging outgoing TCP packet. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl; #if TCPN_LOG_PACKETS == 2 if (pack->size >= 32) DumpPacket(pack->pBuffer, 32); else DumpPacket(pack); #endif #if TCPN_LOG_PACKETS >= 3 DumpPacket(pack); #endif } #endif ServerSendQueuePushEnd((uchar**) &tnps, tnps->size); } } return true; }
bool EmuTCPConnection::SendPacket(EmuTCPNetPacket_Struct* tnps) { if (RemoteID) { return false; } if (!Connected()) { return false; } if (GetMode() != modePacket) { return false; } LockMutex lock(&MState); eTCPMode tmp = GetMode(); if (tmp == modeTransition) { EmuTCPNetPacket_Struct* tnps2 = (EmuTCPNetPacket_Struct*) new uchar[tnps->size]; memcpy(tnps2, tnps, tnps->size); InModeQueuePush(tnps2); return true; } #if TCPN_LOG_PACKETS >= 1 if (tnps && tnps->opcode != 0) { struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << tnps->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort(); if (pOldFormat) { std::cout << " (OldFormat)"; } std::cout << std::endl; #if TCPN_LOG_PACKETS == 2 if (tnps->size >= 32) { DumpPacket((uchar*) tnps, 32); } else { DumpPacket((uchar*) tnps, tnps->size); } #endif #if TCPN_LOG_PACKETS >= 3 DumpPacket((uchar*) tnps, tnps->size); #endif } #endif ServerSendQueuePushEnd((const uchar*) tnps, tnps->size); return true; }
bool TCPConnection::SendData(bool &sent_something, char* errbuf) { if (errbuf) errbuf[0] = 0; /************ Get first send packet on queue and send it! ************/ uchar* data = 0; int32 size = 0; int status = 0; if (ServerSendQueuePop(&data, &size)) { #ifdef _WINDOWS status = send(connection_socket, (const char *) data, size, 0); #else status = send(connection_socket, data, size, MSG_NOSIGNAL); if(errno==EPIPE) status = SOCKET_ERROR; #endif if (status >= 1) { #if TCPN_LOG_RAW_DATA_OUT >= 1 struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort(); std::cout << std::endl; #if TCPN_LOG_RAW_DATA_OUT == 2 int32 tmp = status; if (tmp > 32) tmp = 32; DumpPacket(data, status); #elif TCPN_LOG_RAW_DATA_OUT >= 3 DumpPacket(data, status); #endif #endif sent_something = true; if (status < (signed)size) { #if TCPN_LOG_RAW_DATA_OUT >= 1 struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort(); std::cout << std::endl; #endif // If there's network congestion, the number of bytes sent can be less than // what we tried to give it... Push the extra back on the queue for later ServerSendQueuePushFront(&data[status], size - status); } else if (status > (signed)size) { return false; } // else if (status == size) {} } else { ServerSendQueuePushFront(data, size); } safe_delete_array(data); if (status == SOCKET_ERROR) { #ifdef _WINDOWS if (WSAGetLastError() != WSAEWOULDBLOCK) #else if (errno != EWOULDBLOCK) #endif { if (errbuf) { #ifdef _WINDOWS snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError()); #else snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno)); #endif } //if we get an error while disconnecting, just jump to disconnected MState.lock(); if(pState == TCPS_Disconnecting) pState = TCPS_Disconnected; MState.unlock(); return false; } } } return true; }
bool TCPConnection::RecvData(char* errbuf) { if (errbuf) errbuf[0] = 0; if (!Connected()) { return false; } int status = 0; if (recvbuf == 0) { recvbuf = new uchar[5120]; recvbuf_size = 5120; recvbuf_used = 0; recvbuf_echo = 0; } else if ((recvbuf_size - recvbuf_used) < 2048) { uchar* tmpbuf = new uchar[recvbuf_size + 5120]; memcpy(tmpbuf, recvbuf, recvbuf_used); recvbuf_size += 5120; safe_delete_array(recvbuf); recvbuf = tmpbuf; if (recvbuf_size >= MaxTCPReceiveBuffferSize) { if (errbuf) snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize"); return false; } } status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0); if (status >= 1) { #if TCPN_LOG_RAW_DATA_IN >= 1 struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort(); std::cout << std::endl; #if TCPN_LOG_RAW_DATA_IN == 2 int32 tmp = status; if (tmp > 32) tmp = 32; DumpPacket(&recvbuf[recvbuf_used], status); #elif TCPN_LOG_RAW_DATA_IN >= 3 DumpPacket(&recvbuf[recvbuf_used], status); #endif #endif recvbuf_used += status; if (!ProcessReceivedData(errbuf)) return false; } else if (status == SOCKET_ERROR) { #ifdef _WINDOWS if (!(WSAGetLastError() == WSAEWOULDBLOCK)) { if (errbuf) snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError()); return false; } #else if (!(errno == EWOULDBLOCK)) { if (errbuf) snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno)); return false; } #endif } else if (status == 0) { snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed"); return false; } return true; }
bool EmuTCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) { int32 base = 0; int32 size = 4; uchar* buffer; ServerPacket* pack = 0; while ((recvbuf_used - base) >= size) { buffer = &recvbuf[base]; memcpy(&size, &buffer[2], 2); if (size >= MaxTCPReceiveBuffferSize) { #if TCPN_DEBUG_Memory >= 1 std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl; #endif if (errbuf) snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize"); return false; } if ((recvbuf_used - base) >= size) { // ok, we got enough data to make this packet! pack = new ServerPacket; memcpy(&pack->opcode, &buffer[0], 2); pack->size = size - 4; /* if () { // TODO: Checksum or size check or something similar // Datastream corruption, get the hell outta here! delete pack; return false; }*/ if (pack->size > 0) { pack->pBuffer = new uchar[pack->size]; memcpy(pack->pBuffer, &buffer[4], pack->size); } if (pack->opcode == 0) { // keepalive, no need to process safe_delete(pack); } else { #if TCPN_LOG_PACKETS >= 1 if (pack && pack->opcode != 0) { struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Logging incoming TCP OldPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl; #if TCPN_LOG_PACKETS == 2 if (pack->size >= 32) DumpPacket(pack->pBuffer, 32); else DumpPacket(pack); #endif #if TCPN_LOG_PACKETS >= 3 DumpPacket(pack); #endif } #endif OutQueuePush(pack); } base += size; size = 4; } } if (base != 0) { if (base >= recvbuf_used) { safe_delete_array(recvbuf); } else { uchar* tmpbuf = new uchar[recvbuf_size - base]; memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base); safe_delete_array(recvbuf); recvbuf = tmpbuf; recvbuf_used -= base; recvbuf_size -= base; } } return true; }
bool EmuTCPConnection::ProcessReceivedDataAsPackets(char* errbuf) { if (errbuf) errbuf[0] = 0; int32 base = 0; int32 size = 7; uchar* buffer; ServerPacket* pack = 0; while ((recvbuf_used - base) >= size) { EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) &recvbuf[base]; buffer = tnps->buffer; size = tnps->size; if (size >= MaxTCPReceiveBuffferSize) { #if TCPN_DEBUG_Memory >= 1 std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl; DumpPacket(&recvbuf[base], 16); #endif if (errbuf) snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize"); return false; } if ((recvbuf_used - base) >= size) { // ok, we got enough data to make this packet! pack = new ServerPacket; pack->size = size - sizeof(EmuTCPNetPacket_Struct); // read headers pack->opcode = tnps->opcode; if (tnps->flags.compressed) { pack->compressed = true; pack->InflatedSize = *((int32*)buffer); pack->size -= 4; buffer += 4; } if (tnps->flags.destination) { pack->destination = *((int32*)buffer); pack->size -= 4; buffer += 4; } // end read headers if (pack->size > 0) { if (tnps->flags.compressed) { // Lets decompress the packet here pack->compressed = false; pack->pBuffer = new uchar[pack->InflatedSize]; pack->size = InflatePacket(buffer, pack->size, pack->pBuffer, pack->InflatedSize); } else { pack->pBuffer = new uchar[pack->size]; memcpy(pack->pBuffer, buffer, pack->size); } } if (pack->opcode == 0) { if (pack->size) { #if TCPN_DEBUG >= 2 std::cout << "Received TCP Network layer packet" << std::endl; #endif ProcessNetworkLayerPacket(pack); } #if TCPN_DEBUG >= 5 else { std::cout << "Received TCP keepalive packet. (opcode=0)" << std::endl; } #endif // keepalive, no need to process safe_delete(pack); } else { #if TCPN_LOG_PACKETS >= 1 if (pack && pack->opcode != 0) { struct in_addr in; in.s_addr = GetrIP(); CoutTimestamp(true); std::cout << ": Logging incoming TCP packet. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl; #if TCPN_LOG_PACKETS == 2 if (pack->size >= 32) DumpPacket(pack->pBuffer, 32); else DumpPacket(pack); #endif #if TCPN_LOG_PACKETS >= 3 DumpPacket(pack); #endif } #endif if (RelayServer && Server && pack->destination) { EmuTCPConnection* con = Server->FindConnection(pack->destination); if (!con) { #if TCPN_DEBUG >= 1 std::cout << "Error relaying packet: con = 0" << std::endl; #endif safe_delete(pack); } else con->OutQueuePush(pack); } else OutQueuePush(pack); } base += size; size = 7; } } if (base != 0) { if (base >= recvbuf_used) { safe_delete_array(recvbuf); } else { uchar* tmpbuf = new uchar[recvbuf_size - base]; memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base); safe_delete_array(recvbuf); recvbuf = tmpbuf; recvbuf_used -= base; recvbuf_size -= base; } } return true; }