Example #1
0
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;
}
void EmuTCPConnection::SendNetErrorPacket(const char* reason)
{
#if TCPC_DEBUG >= 1
	struct in_addr	in;
	in.s_addr = GetrIP();
	std::cout "NetError: '";
	if (reason)
	{
		std::cout << reason;
	}
	std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
#endif
	ServerPacket* pack = new ServerPacket(0);
	pack->size = 1;
	if (reason)
	{
		pack->size += strlen(reason) + 1;
	}
	pack->pBuffer = new uchar[pack->size];
	memset(pack->pBuffer, 0, pack->size);
	pack->pBuffer[0] = 255;
	strcpy((char*) &pack->pBuffer[1], reason);
	SendPacket(pack);
	safe_delete(pack);
}
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
/* This is always called from an IO thread. Either the server socket's thread, or a
 * special thread we create when we make an outbound connection. */
bool TCPConnection::Process() {
	char errbuf[TCPConnection_ErrorBufferSize];
	switch(GetState()) {
	case TCPS_Ready:
	case TCPS_Connecting:
		if (ConnectionType == Outgoing) {
			if (GetAsyncConnect()) {
				if (charAsyncConnect)
					rIP = ResolveIP(charAsyncConnect);
				ConnectIP(rIP, rPort);
			}
		}
		return(true);

	case TCPS_Connected:
		// only receive data in the connected state, no others...
		if (!RecvData(errbuf)) {
			struct in_addr	in;
			in.s_addr = GetrIP();
			//cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
			return false;
		}
		/* we break to do the send */
		break;

	case TCPS_Disconnecting: {
		//waiting for any sending data to go out...
		MSendQueue.lock();
		if(sendbuf) {
			if(sendbuf_used > 0) {
				//something left to send, keep processing...
				MSendQueue.unlock();
				break;
			}
			//else, send buffer is empty.
			safe_delete_array(sendbuf);
		} //else, no send buffer, we are done.
		MSendQueue.unlock();
	}
		/* Fallthrough */

	case TCPS_Disconnected:
		FinishDisconnect();
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
//		SetState(TCPS_Ready);	//reset the state in case they want to use it again...
		return(false);

	case TCPS_Closing:
		//I dont understand this state...

	case TCPS_Error:
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
		return(false);
	}

	/* we get here in connected or disconnecting with more data to send */

	bool sent_something = false;
	if (!SendData(sent_something, errbuf)) {
		struct in_addr	in;
		in.s_addr = GetrIP();
		std::cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << std::endl;
		return false;
	}

	return true;
}
Example #7
0
void EmuTCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) {
	uint8 opcode = pack->pBuffer[0];
	uint8* data = &pack->pBuffer[1];
	switch (opcode) {
		case 0: {
			break;
		}
		case 1: { // Switch to RelayServer mode
			if (pack->size != 1) {
				SendNetErrorPacket("New RelayClient: wrong size, expected 1");
				break;
			}
			if (RelayServer) {
				SendNetErrorPacket("Switch to RelayServer mode when already in RelayServer mode");
				break;
			}
			if (RemoteID) {
				SendNetErrorPacket("Switch to RelayServer mode by a Relay Client");
				break;
			}
			if (ConnectionType != Incomming) {
				SendNetErrorPacket("Switch to RelayServer mode on outgoing connection");
				break;
			}
			#if TCPC_DEBUG >= 3
				struct in_addr	in;
				in.s_addr = GetrIP();
				std::cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << std::endl;
			#endif
			RelayServer = true;
			break;
		}
		case 2: { // New Relay Client
			if (!RelayServer) {
				SendNetErrorPacket("New RelayClient when not in RelayServer mode");
				break;
			}
			if (pack->size != 11) {
				SendNetErrorPacket("New RelayClient: wrong size, expected 11");
				break;
			}
			if (ConnectionType != Incomming) {
				SendNetErrorPacket("New RelayClient: illegal on outgoing connection");
				break;
			}
			EmuTCPConnection* con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32*) data), *((uint32*) &data[4]), *((uint16*) &data[8]));
			Server->AddConnection(con);
			RelayCount++;
			break;
		}
		case 3: { // Delete Relay Client
			if (!RelayServer) {
				SendNetErrorPacket("Delete RelayClient when not in RelayServer mode");
				break;
			}
			if (pack->size != 5) {
				SendNetErrorPacket("Delete RelayClient: wrong size, expected 5");
				break;
			}
			EmuTCPConnection* con = Server->FindConnection(*((uint32*)data));
			if (con) {
				if (ConnectionType == Incomming) {
					if (con->GetRelayLink() != this) {
						SendNetErrorPacket("Delete RelayClient: RelayLink != this");
						break;
					}
				}
				con->Disconnect(false);
			}
			break;
		}
		case 255: {
			#if TCPC_DEBUG >= 1
				struct in_addr	in;
				in.s_addr = GetrIP();
				std::cout "Received NetError: '";
				if (pack->size > 1)
					std::cout << (char*) data;
				std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
			#endif
			break;
		}
	}
}
Example #8
0
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;
}
Example #9
0
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;
}