/*  
    EQ2Emulator:  Everquest II Server Emulator
    Copyright (C) 2007  EQ2EMulator Development Team (http://www.eq2emulator.net)

    This file is part of EQ2Emulator.

    EQ2Emulator is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    EQ2Emulator is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with EQ2Emulator.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "../common/debug.h"

#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;

#include "TCPConnection.h"
#include "../common/servertalk.h"
#include "../common/timer.h"
#include "../common/packet_dump.h"
#include "Log.h"

#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#define MSG_NOSIGNAL 0
#endif

#ifdef WIN32
InitWinsock winsock;
#endif

#define LOOP_GRANULARITY 3	//# of ms between checking our socket/queues
#define SERVER_LOOP_GRANULARITY 3	//# of ms between checking our socket/queues

#define TCPN_DEBUG				0
#define TCPN_DEBUG_Console		0
#define TCPN_DEBUG_Memory		0
#define TCPN_LOG_PACKETS		0
#define TCPN_LOG_RAW_DATA_OUT	0
#define TCPN_LOG_RAW_DATA_IN	0

TCPConnection::TCPNetPacket_Struct* TCPConnection::MakePacket(ServerPacket* pack, int32 iDestination) {
	sint32 size = sizeof(TCPNetPacket_Struct) + pack->size;
	if (pack->compressed) {
		size += 4;
	}
	if (iDestination) {
		size += 4;
	}
	TCPNetPacket_Struct* tnps = (TCPNetPacket_Struct*) new uchar[size];
	tnps->size = size;
	tnps->opcode = pack->opcode;
	*((int8*) &tnps->flags) = 0;
	uchar* buffer = tnps->buffer;
	if (pack->compressed) {
		tnps->flags.compressed = 1;
		*((sint32*) buffer) = pack->InflatedSize;
		buffer += 4;
	}
	if (iDestination) {
		tnps->flags.destination = 1;
		*((sint32*) buffer) = iDestination;
		buffer += 4;
	}
	memcpy(buffer, pack->pBuffer, pack->size);
	return tnps;
}

TCPConnection::TCPConnection(bool iOldFormat, TCPServer* iRelayServer, eTCPMode iMode) {
	id = 0;
	Server = iRelayServer;
	if (Server)
		RelayServer = true;
	else
		RelayServer = false;
	RelayLink = 0;
	RelayCount = 0;
	RemoteID = 0;
	pOldFormat = iOldFormat;
	ConnectionType = Outgoing;
	TCPMode = iMode;
	pState = TCPS_Ready;
	pFree = false;
	pEcho = false;
	sock = 0;
	rIP = 0;
	rPort = 0;
	keepalive_timer = new Timer(SERVER_TIMEOUT);
	timeout_timer = new Timer(SERVER_TIMEOUT * 2);
	recvbuf = 0;
	sendbuf = 0;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	connection_socket = 0;
	recvbuf_size = 0;
	recvbuf_used = 0;
	recvbuf_echo = 0;
	sendbuf_size = 0;
	sendbuf_used = 0;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #1 on outgoing TCP# " << GetID() << endl;
#endif
}

TCPConnection::TCPConnection(TCPServer* iServer, SOCKET in_socket, int32 irIP, int16 irPort, bool iOldFormat) {
	Server = iServer;
	RelayLink = 0;
	RelayServer = false;
	RelayCount = 0;
	RemoteID = 0;
	id = Server->GetNextID();
	ConnectionType = Incomming;
	pOldFormat = iOldFormat;
	TCPMode = modePacket;
	pState = TCPS_Connected;
	pFree = false;
	pEcho = false;
	sock = 0;
	connection_socket = in_socket;
	rIP = irIP;
	rPort = irPort;
	keepalive_timer = new Timer(SERVER_TIMEOUT);
	timeout_timer = new Timer(SERVER_TIMEOUT * 2);
	recvbuf = 0;
	sendbuf = 0;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	recvbuf_size = 0;
	recvbuf_used = 0;
	recvbuf_echo = 0;
	sendbuf_size = 0;
	sendbuf_used = 0;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #2 on outgoing TCP# " << GetID() << endl;
#endif
}

TCPConnection::TCPConnection(TCPServer* iServer, TCPConnection* iRelayLink, int32 iRemoteID, int32 irIP, int16 irPort) {
	Server = iServer;
	RelayLink = iRelayLink;
	RelayServer = true;
	id = Server->GetNextID();
	RelayCount = 0;
	RemoteID = iRemoteID;
	if (!RemoteID)
		ThrowError("Error: TCPConnection: RemoteID == 0 on RelayLink constructor");
	pOldFormat = false;
	ConnectionType = Incomming;
	TCPMode = modePacket;
	pState = TCPS_Connected;
	pFree = false;
	pEcho = false;
	sock = 0;
	connection_socket = 0;
	rIP = irIP;
	rPort = irPort;
	keepalive_timer = 0;
	timeout_timer = 0;
	recvbuf = 0;
	sendbuf = 0;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	recvbuf_size = 0;
	recvbuf_used = 0;
	recvbuf_echo = 0;
	sendbuf_size = 0;
	sendbuf_used = 0;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #3 on outgoing TCP# " << GetID() << endl;
#endif
}

TCPConnection::~TCPConnection() {
	Disconnect();
	ClearBuffers();
	if (ConnectionType == Outgoing) {
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
		MLoopRunning.lock();
		MLoopRunning.unlock();
#if TCPN_DEBUG_Memory >= 6
		cout << "Deconstructor on outgoing TCP# " << GetID() << endl;
#endif
	}
#if TCPN_DEBUG_Memory >= 5
	else {
		cout << "Deconstructor on incomming TCP# " << GetID() << endl;
	}
#endif
	safe_delete(keepalive_timer);
	safe_delete(timeout_timer);
	safe_delete_array(recvbuf);
	safe_delete_array(sendbuf);
	safe_delete_array(charAsyncConnect);
}

void TCPConnection::SetState(int8 in_state) {
	MState.lock();
	pState = in_state;
	MState.unlock();
}

int8 TCPConnection::GetState() {
	int8 ret;
	MState.lock();
	ret = pState;
	MState.unlock();
	return ret;
}

void TCPConnection::Free() {
	if (ConnectionType == Outgoing) {
		ThrowError("TCPConnection::Free() called on an Outgoing connection");
	}
#if TCPN_DEBUG_Memory >= 5
	cout << "Free on TCP# " << GetID() << endl;
#endif
	Disconnect();
	pFree = true;
}

bool TCPConnection::SendPacket(ServerPacket* pack, int32 iDestination) {
	LockMutex lock(&MState);
	if (!Connected())
		return false;
	eTCPMode tmp = GetMode();
	if (tmp != modePacket && tmp != modeTransition)
		return false;
	if (RemoteID)
		return RelayLink->SendPacket(pack, RemoteID);
	else {
		TCPNetPacket_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);
				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() << 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 TCPConnection::SendPacket(TCPNetPacket_Struct* tnps) {
	LockMutex lock(&MState);
	if (RemoteID)
		return false;
	if (!Connected())
		return false;
	eTCPMode tmp = GetMode();
	if (tmp == modeTransition) {
		TCPNetPacket_Struct* tnps2 = (TCPNetPacket_Struct*) new uchar[tnps->size];
		memcpy(tnps2, tnps, tnps->size);
		InModeQueuePush(tnps2);
		return true;
	}
	if (GetMode() != modePacket)
		return false;
#if TCPN_LOG_PACKETS >= 1
	if (tnps && tnps->opcode != 0) {
		struct in_addr	in;
		in.s_addr = GetrIP();
		CoutTimestamp(true);
		cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << tnps->opcode << dec << ", size: " << setw(5) << setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort();
		if (pOldFormat)
			cout << " (OldFormat)";
		cout << 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::Send(const uchar* data, sint32 size) {
	if (!Connected())
		return false;
	if (GetMode() != modeConsole)
		return false;
	if (!size)
		return true;
	ServerSendQueuePushEnd(data, size);
	return true;
}

void TCPConnection::InModeQueuePush(TCPNetPacket_Struct* tnps) {
	MSendQueue.lock();
	InModeQueue.push(tnps);
	MSendQueue.unlock();
}

void TCPConnection::ServerSendQueuePushEnd(const uchar* data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = new uchar[size];
		sendbuf_size = size;
		sendbuf_used = 0;
	}
	else if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size + 1024;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(tmp, sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(&sendbuf[sendbuf_used], data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
}

void TCPConnection::ServerSendQueuePushEnd(uchar** data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = *data;
		sendbuf_size = size;
		sendbuf_used = size;
		MSendQueue.unlock();
		*data = 0;
		return;
	}
	if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(tmp, sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(&sendbuf[sendbuf_used], *data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
	delete[] (TCPNetPacket_Struct*)*data;
}

void TCPConnection::ServerSendQueuePushFront(uchar* data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = new uchar[size];
		sendbuf_size = size;
		sendbuf_used = 0;
	}
	else if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(&tmp[size], sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(sendbuf, data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
}

bool TCPConnection::ServerSendQueuePop(uchar** data, sint32* size) {
	bool ret;
	if (!MSendQueue.trylock())
		return false;
	if (sendbuf) {
		*data = sendbuf;
		*size = sendbuf_used;
		sendbuf = 0;
		ret = true;
	}
	else {
		ret = false;
	}
	MSendQueue.unlock();
	return ret;
}

ServerPacket* TCPConnection::PopPacket() {
	ServerPacket* ret;
	if (!MOutQueueLock.trylock())
		return 0;
	ret = OutQueue.pop();
	MOutQueueLock.unlock();
	return ret;
}

char* TCPConnection::PopLine() {
	char* ret;
	if (!MOutQueueLock.trylock())
		return 0;
	ret = (char*) LineOutQueue.pop();
	MOutQueueLock.unlock();
	return ret;
}

void TCPConnection::OutQueuePush(ServerPacket* pack) {
	MOutQueueLock.lock();
	OutQueue.push(pack);
	MOutQueueLock.unlock();
}

void TCPConnection::LineOutQueuePush(char* line) {
#if defined(GOTFRAGS) && 0
	if (strcmp(line, "**CRASHME**") == 0) {
		int i = 0;
		cout << (5 / i) << endl;
	}
#endif
	if (strcmp(line, "**PACKETMODE**") == 0) {
		MSendQueue.lock();
		safe_delete_array(sendbuf);
		if (TCPMode == modeConsole)
			Send((const uchar*) "\0**PACKETMODE**\r", 16);
		TCPMode = modePacket;
		TCPNetPacket_Struct* tnps = 0;
		while ((tnps = InModeQueue.pop())) {
			SendPacket(tnps);
			safe_delete_array(tnps);
		}
		MSendQueue.unlock();
		safe_delete_array(line);
		return;
	}
	MOutQueueLock.lock();
	LineOutQueue.push(line);
	MOutQueueLock.unlock();
}

void TCPConnection::Disconnect(bool iSendRelayDisconnect) {
	if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
		MState.lock();
		if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected)
			SendData();
		pState = TCPS_Closing;
		MState.unlock();
		shutdown(connection_socket, 0x01);
		shutdown(connection_socket, 0x00);
#ifdef WIN32
		closesocket(connection_socket);
#else
		close(connection_socket);
#endif
		connection_socket = 0;
		rIP = 0;
		rPort = 0;
		ClearBuffers();
	}
	SetState(TCPS_Ready);
	if (RelayLink) {
		RelayLink->RemoveRelay(this, iSendRelayDisconnect);
		RelayLink = 0;
	}
}

bool TCPConnection::GetAsyncConnect() {
	bool ret;
	MAsyncConnect.lock();
	ret = pAsyncConnect;
	MAsyncConnect.unlock();
	return ret;
}

bool TCPConnection::SetAsyncConnect(bool iValue) {
	bool ret;
	MAsyncConnect.lock();
	ret = pAsyncConnect;
	pAsyncConnect = iValue;
	MAsyncConnect.unlock();
	return ret;
}

void TCPConnection::AsyncConnect(char* irAddress, int16 irPort) {
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!");
		return;
	}
	if (GetState() != TCPS_Ready)
		return;
	MAsyncConnect.lock();
	if (pAsyncConnect) {
		MAsyncConnect.unlock();
		return;
	}
	pAsyncConnect = true;
	safe_delete_array(charAsyncConnect);
	charAsyncConnect = new char[strlen(irAddress) + 1];
	strcpy(charAsyncConnect, irAddress);
	rPort = irPort;
	MAsyncConnect.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
		pthread_detach(thread);
#endif
	}
	return;
}

void TCPConnection::AsyncConnect(int32 irIP, int16 irPort) {
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!");
		return;
	}
	if (GetState() != TCPS_Ready)
		return;
	MAsyncConnect.lock();
	if (pAsyncConnect) {
		MAsyncConnect.unlock();
		return;
	}
	pAsyncConnect = true;
	safe_delete(charAsyncConnect);
	rIP = irIP;
	rPort = irPort;
	MAsyncConnect.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
		pthread_detach(thread);
#endif
	}
	return;
}

bool TCPConnection::Connect(char* irAddress, int16 irPort, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	int32 tmpIP = ResolveIP(irAddress);
	if (!tmpIP) {
		if (errbuf) {
#ifdef WIN32
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
#else
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
#endif
		}
		return false;
	}
	return Connect(tmpIP, irPort, errbuf);
}

bool TCPConnection::Connect(int32 in_ip, int16 in_port, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::Connect() call on a Incomming connection object!");
		return false;
	}
	MState.lock();
	if (pState == TCPS_Ready) {
		pState = TCPS_Connecting;
	}
	else {
		MState.unlock();
		SetAsyncConnect(false);
		return false;
	}
	MState.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
		pthread_detach(thread);
#endif
	}

	connection_socket = INVALID_SOCKET;
	struct sockaddr_in	server_sin;
	//    struct in_addr	in;

	if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
#ifdef WIN32
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
#else
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
#endif
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
	server_sin.sin_family = AF_INET;
	server_sin.sin_addr.s_addr = in_ip;
	server_sin.sin_port = htons(in_port);

	// Establish a connection to the server socket.
#ifdef WIN32
	if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
		closesocket(connection_socket);
		connection_socket = 0;
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
#else
	if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
		close(connection_socket);
		connection_socket = 0;
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
#endif
	int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
	setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef WIN32
	unsigned long nonblocking = 1;
	ioctlsocket(connection_socket, FIONBIO, &nonblocking);
#else
	fcntl(connection_socket, F_SETFL, O_NONBLOCK);
#endif

	SetEcho(false);
	MSendQueue.lock();
	ClearBuffers();
	TCPMode = modePacket;

	MSendQueue.unlock();

	rIP = in_ip;
	rPort = in_port;
	SetState(TCPS_Connected);
	SetAsyncConnect(false);
	return true;
}

void TCPConnection::ClearBuffers() {
	LockMutex lock1(&MSendQueue);
	LockMutex lock2(&MOutQueueLock);
	LockMutex lock3(&MRunLoop);
	LockMutex lock4(&MState);
	safe_delete_array(recvbuf);
	safe_delete_array(sendbuf);
	ServerPacket* pack = 0;
	while ((pack = PopPacket()))
		safe_delete(pack);
	TCPNetPacket_Struct* tnps = 0;
	while ((tnps = InModeQueue.pop()))
		safe_delete(tnps);
	char* line = 0;
	while ((line = LineOutQueue.pop()))
		safe_delete_array(line);
	keepalive_timer->Start();
	timeout_timer->Start();
}

bool TCPConnection::CheckNetActive() {
	MState.lock();
	if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
		MState.unlock();
		return true;
	}
	MState.unlock();
	return false;
}

bool TCPConnection::Process() {
	char errbuf[TCPConnection_ErrorBufferSize];
	if (!CheckNetActive()) {
		if (ConnectionType == Outgoing) {
			if (GetAsyncConnect()) {
				if (charAsyncConnect)
					rIP = ResolveIP(charAsyncConnect);
				Connect(rIP, rPort);
			}
		}
		if (GetState() == TCPS_Disconnected) {
			Disconnect();
			return false;
		}
		else if (GetState() == TCPS_Connecting)
			return true;
		else
			return false;
	}
	if (!SendData(errbuf)) {
		struct in_addr	in;
		in.s_addr = GetrIP();
		cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
		return false;
	}
	if (!Connected())
		return false;
	if (!RecvData(errbuf)) {
		struct in_addr	in;
		in.s_addr = GetrIP();
		cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
		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 >= MaxTCPReceiveBufferSize) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBufferSize");
			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);
		cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
		if (pOldFormat)
			cout << " (OldFormat)";
		cout << endl;
#if TCPN_LOG_RAW_DATA_IN == 2
		sint32 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;
		timeout_timer->Start();
		if (!ProcessReceivedData(errbuf))
			return false;
	}
	else if (status == SOCKET_ERROR) {
#ifdef WIN32
		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
	}
	if ((TCPMode == modePacket || TCPMode == modeTransition) && timeout_timer->Check()) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection timeout");
		return false;
	}

	return true;
}


bool TCPConnection::GetEcho() {
	bool ret;
	MEcho.lock();
	ret = pEcho;
	MEcho.unlock();
	return ret;
}

void TCPConnection::SetEcho(bool iValue) {
	MEcho.lock();
	pEcho = iValue;
	MEcho.unlock();
}

bool TCPConnection::ProcessReceivedData(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (!recvbuf)
		return true;
	if (TCPMode == modePacket) {
		//if (pOldFormat)
		//	return ProcessReceivedDataAsOldPackets(errbuf);
		//else
		return ProcessReceivedDataAsPackets(errbuf);
	}
	else {
#if TCPN_DEBUG_Console >= 4
		if (recvbuf_used) {
			cout << "Starting Processing: recvbuf=" << recvbuf_used << endl;
			DumpPacket(recvbuf, recvbuf_used);
		}
#endif
		for (int i=0; i < recvbuf_used; i++) {
			if (GetEcho() && i >= recvbuf_echo) {
				Send(&recvbuf[i], 1);
				recvbuf_echo = i + 1;
			}
			switch(recvbuf[i]) {
			case 0: { // 0 is the code for clear buffer
				if (i==0) {
					recvbuf_used--;
					recvbuf_echo--;
					memcpy(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					if (i == recvbuf_used) {
						safe_delete_array(recvbuf);
						i = -1;
					}
					else {
						uchar* tmpdel = recvbuf;
						recvbuf = new uchar[recvbuf_size];
						memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
						recvbuf_used -= i + 1;
						recvbuf_echo -= i + 1;
						safe_delete(tmpdel);
						i = -1;
					}
				}
#if TCPN_DEBUG_Console >= 5
				cout << "Removed 0x00" << endl;
				if (recvbuf_used) {
					cout << "recvbuf left: " << recvbuf_used << endl;
					DumpPacket(recvbuf, recvbuf_used);
				}
				else
					cout << "recbuf left: None" << endl;
#endif
				break;
					}
			case 10:
			case 13: // newline marker
				{
					if (i==0) { // empty line
						recvbuf_used--;
						recvbuf_echo--;
						memcpy(recvbuf, &recvbuf[1], recvbuf_used);
						i = -1;
					} else {
						char* line = new char[i+1];
						memset(line, 0, i+1);
						memcpy(line, recvbuf, i);
#if TCPN_DEBUG_Console >= 3
						cout << "Line Out: " << endl;
						DumpPacket((uchar*) line, i);
#endif
						//line[i] = 0;
						uchar* tmpdel = recvbuf;
						recvbuf = new uchar[recvbuf_size];
						recvbuf_used -= i+1;
						recvbuf_echo -= i+1;
						memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
#if TCPN_DEBUG_Console >= 5
						cout << "i+1=" << i+1 << endl;
						if (recvbuf_used) {
							cout << "recvbuf left: " << recvbuf_used << endl;
							DumpPacket(recvbuf, recvbuf_used);
						}
						else
							cout << "recbuf left: None" << endl;
#endif
						safe_delete(tmpdel);
						if (strlen(line) > 0)
							LineOutQueuePush(line);
						else
							safe_delete_array(line);
						if (TCPMode == modePacket) {
							return ProcessReceivedDataAsPackets(errbuf);
						}
						i = -1;
					}
					break;
				}
			case 8: // backspace
				{
					if (i==0) { // nothin to backspace
						recvbuf_used--;
						recvbuf_echo--;
						memcpy(recvbuf, &recvbuf[1], recvbuf_used);
						i = -1;
					} else {
						uchar* tmpdel = recvbuf;
						recvbuf = new uchar[recvbuf_size];
						memcpy(recvbuf, tmpdel, i-1);
						memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
						recvbuf_used -= 2;
						recvbuf_echo -= 2;
						safe_delete(tmpdel);
						i -= 2;
					}
					break;
				}
			}
		}
		if (recvbuf_used < 0)
			safe_delete_array(recvbuf);
	}
	return true;
}

bool TCPConnection::ProcessReceivedDataAsPackets(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	sint32 base = 0;
	sint32 size = 7;
	uchar* buffer;
	ServerPacket* pack = 0;
	while ((recvbuf_used - base) >= size) {
		TCPNetPacket_Struct* tnps = (TCPNetPacket_Struct*) &recvbuf[base];
		buffer = tnps->buffer;
		size = tnps->size;
		if (size >= MaxTCPReceiveBufferSize) {
#if TCPN_DEBUG_Memory >= 1
			cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBufferSize" << endl;
#endif
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBufferSize");
			return false;
		}
		if ((recvbuf_used - base) >= size) {
			// ok, we got enough data to make this packet!
			safe_delete(pack);
			pack = new ServerPacket;
			pack->size = size - sizeof(TCPNetPacket_Struct);
			// read headers
			pack->opcode = tnps->opcode;
			if (tnps->flags.compressed) {
				pack->compressed = true;
				pack->InflatedSize = *((sint32*)buffer);
				pack->size -= 4;
				buffer += 4;
			}
			if (tnps->flags.destination) {
				pack->destination = *((sint32*)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;
					if(pack->InflatedSize < MaxTCPReceiveBufferSize)
					{
						pack->pBuffer = new uchar[pack->InflatedSize];
						pack->size = InflatePacket(buffer, pack->size, pack->pBuffer, pack->InflatedSize);
					}
					else
					{
						cout << "Invalid inflated packet." << endl;
						safe_delete(pack);
						return false;
					}
				}
				else {
					pack->pBuffer = new uchar[pack->size];
					memcpy(pack->pBuffer, buffer, pack->size);
				}
			}
			if (pack->opcode == 0) {
				if (pack->size) {
#if TCPN_DEBUG >= 2
					cout << "Received TCP Network layer packet" << endl;
#endif
					ProcessNetworkLayerPacket(pack);
				}
#if TCPN_DEBUG >= 5
				else {
					cout << "Received TCP keepalive packet. (opcode=0)" << endl;
				}
#endif
			}
			else {
#if TCPN_LOG_PACKETS >= 1
				if (pack && pack->opcode != 0) {
					struct in_addr	in;
					in.s_addr = GetrIP();
					CoutTimestamp(true);
					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() << 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) {
					TCPConnection* con = Server->GetConnection(pack->destination);
					if (!con) {
#if TCPN_DEBUG >= 1
						cout << "Error relaying packet: con = 0" << endl;
#endif
					}
					else{
						con->OutQueuePush(pack);
						pack = 0;
					}
				}
				else{
					OutQueuePush(pack);
					pack = 0;
				}
			}
			base += size;
			size = 7;
		}
	}
	safe_delete(pack);
	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 TCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) {
	sint32 base = 0;
	sint32 size = 4;
	uchar* buffer;
	ServerPacket* pack = 0;
	while ((recvbuf_used - base) >= size) {
		buffer = &recvbuf[base];
		memcpy(&size, &buffer[2], 2);
		if (size >= MaxTCPReceiveBufferSize) {
#if TCPN_DEBUG_Memory >= 1
			cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBufferSize" << endl;
#endif
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBufferSize");
			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;

			LogWrite(MISC__TODO, 1, "TODO", "Checksum or size check or something similar\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
				/* 
				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);
					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() << 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;
}

void TCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) {
	int8 opcode = pack->pBuffer[0];
	int8* 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();
			cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << 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;
			}
			TCPConnection* con = new TCPConnection(Server, this, *((int32*) data), *((int32*) &data[4]), *((int16*) &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;
			}
			TCPConnection* con = Server->GetConnection(*((int32*)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();
			cout "Received NetError: '";
			if (pack->size > 1)
				cout << (char*) data;
			cout << "': " << inet_ntoa(in) << ":" << GetPort() << endl;
#endif
			break;
				  }
	}
}

void TCPConnection::SendNetErrorPacket(const char* reason) {
#if TCPC_DEBUG >= 1
	struct in_addr	in;
	in.s_addr = GetrIP();
	cout "NetError: '";
	if (reason)
		cout << reason;
	cout << "': " << inet_ntoa(in) << ":" << GetPort() << 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);
}

void TCPConnection::RemoveRelay(TCPConnection* relay, bool iSendRelayDisconnect) {
	if (iSendRelayDisconnect) {
		ServerPacket* pack = new ServerPacket(0, 5);
		pack->pBuffer[0] = 3;
		*((int32*) &pack->pBuffer[1]) = relay->GetRemoteID();
		SendPacket(pack);
		safe_delete(pack);
	}
	RelayCount--;
}

bool TCPConnection::SendData(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	/************ Get first send packet on queue and send it! ************/
	uchar* data = 0;
	sint32 size = 0;
	int status = 0;
	if (ServerSendQueuePop(&data, &size)) {
#ifdef WIN32
		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);
			cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
			if (pOldFormat)
				cout << " (OldFormat)";
			cout << endl;
#if TCPN_LOG_RAW_DATA_OUT == 2
			sint32 tmp = status;
			if (tmp > 32)
				tmp = 32;
			DumpPacket(data, status);
#elif TCPN_LOG_RAW_DATA_OUT >= 3
			DumpPacket(data, status);
#endif
#endif
			keepalive_timer->Start();
			if (status < (signed)size) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
				struct in_addr	in;
				in.s_addr = GetrIP();
				CoutTimestamp(true);
				cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
				if (pOldFormat)
					cout << " (OldFormat)";
				cout << 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) {
				ThrowError("TCPConnection::SendData(): WTF! status > size");
				return false;
			}
			// else if (status == size) {}
		}
		else {
			ServerSendQueuePushFront(data, size);
		}

		safe_delete_array(data);
		if (status == SOCKET_ERROR) {
#ifdef WIN32
			if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
			if (errno != EWOULDBLOCK)
#endif
			{
				if (errbuf) {
#ifdef WIN32
					snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
#else
					snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
#endif
				}
				return false;
			}
		}
	}
	if (TCPMode == modePacket && keepalive_timer->Check()) {
		ServerPacket* pack = new ServerPacket(0, 0);
		SendPacket(pack);
		safe_delete(pack);
#if TCPN_DEBUG >= 5
		cout << "Sending TCP keepalive packet. (timeout=" << timeout_timer->GetRemainingTime() << " remaining)" << endl;
#endif
	}
	return true;
}

ThreadReturnType TCPConnectionLoop(void* tmp) {
#ifdef WIN32
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
	if (tmp == 0) {
		ThrowError("TCPConnectionLoop(): tmp = 0!");
		THREAD_RETURN(NULL);
	}
	TCPConnection* tcpc = (TCPConnection*) tmp;
	tcpc->MLoopRunning.lock();
	while (tcpc->RunLoop()) {
		Sleep(LOOP_GRANULARITY);
		if (tcpc->GetState() != TCPS_Ready) {
			if (!tcpc->Process()) {
				tcpc->Disconnect();
			}
		}
		else if (tcpc->GetAsyncConnect()) {
			if (tcpc->charAsyncConnect)
				tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
			else
				tcpc->Connect(tcpc->GetrIP(), tcpc->GetrPort());
			tcpc->SetAsyncConnect(false);
		}
		else
			Sleep(10);
	}
	tcpc->MLoopRunning.unlock();

	THREAD_RETURN(NULL);
}

bool TCPConnection::RunLoop() {
	bool ret;
	MRunLoop.lock();
	ret = pRunLoop;
	MRunLoop.unlock();
	return ret;
}





TCPServer::TCPServer(int16 in_port, bool iOldFormat) {
	NextID = 1;
	pPort = in_port;
	sock = 0;
	pOldFormat = iOldFormat;
	list = new LinkedList<TCPConnection*>;
	pRunLoop = true;
#ifdef WIN32
	_beginthread(TCPServerLoop, 0, this);
#else
	pthread_t thread;
	pthread_create(&thread, NULL, &TCPServerLoop, this);
	pthread_detach(thread);
#endif
}

TCPServer::~TCPServer() {
	MRunLoop.lock();
	pRunLoop = false;
	MRunLoop.unlock();
	MLoopRunning.lock();
	MLoopRunning.unlock();

	while (NewQueue.pop()); // the objects are deleted with the list, clear this queue so it doesnt try to delete them again
	safe_delete(list);
}

bool TCPServer::RunLoop() {
	bool ret;
	MRunLoop.lock();
	ret = pRunLoop;
	MRunLoop.unlock();
	return ret;
}

ThreadReturnType TCPServerLoop(void* tmp) {
#ifdef WIN32
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
	if (tmp == 0) {
		ThrowError("TCPServerLoop(): tmp = 0!");
		THREAD_RETURN(NULL);
	}
	TCPServer* tcps = (TCPServer*) tmp;
	tcps->MLoopRunning.lock();
	while (tcps->RunLoop()) {
		Sleep(SERVER_LOOP_GRANULARITY);
		tcps->Process();
	}
	tcps->MLoopRunning.unlock();

	THREAD_RETURN(NULL);
}

void TCPServer::Process() {
	CheckInQueue();
	ListenNewConnections();
	LinkedListIterator<TCPConnection*> iterator(*list);

	iterator.Reset();
	while(iterator.MoreElements()) {
		if (iterator.GetData()->IsFree() && (!iterator.GetData()->CheckNetActive())) {
#if _DEBUG
			LogWrite(NET__DEBUG, 0, "Net", "EQStream Connection deleted.");
#endif
			iterator.RemoveCurrent();
		}
		else { 
			if (!iterator.GetData()->Process())
				iterator.GetData()->Disconnect();
			iterator.Advance();
		}
	}
}

void TCPServer::ListenNewConnections() {
	SOCKET tmpsock;
	struct sockaddr_in	from;
	struct in_addr	in;
	unsigned int	fromlen;

	TCPConnection* con;

	from.sin_family = AF_INET;
	fromlen = sizeof(from);
	LockMutex lock(&MSock);
	if (!sock)
		return;

	// Check for pending connects
#ifdef WIN32
	unsigned long nonblocking = 1;
	while ((tmpsock = accept(sock, (struct sockaddr*) &from, (int *) &fromlen)) != INVALID_SOCKET) {
		ioctlsocket (tmpsock, FIONBIO, &nonblocking);
#else
	while ((tmpsock = accept(sock, (struct sockaddr*) &from, &fromlen)) != INVALID_SOCKET) {
		fcntl(tmpsock, F_SETFL, O_NONBLOCK);
#endif
		int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
		setsockopt(tmpsock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
		in.s_addr = from.sin_addr.s_addr;

		// New TCP connection
		con = new TCPConnection(this, tmpsock, in.s_addr, ntohs(from.sin_port), pOldFormat);
#if TCPN_DEBUG >= 1
		cout << "New TCP connection: " << inet_ntoa(in) << ":" << con->GetrPort() << endl;
#endif
		AddConnection(con);
	}
}

bool TCPServer::Open(int16 in_port, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	LockMutex lock(&MSock);
	if (sock != 0) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "Listening socket already open");
		return false;
	}
	if (in_port != 0) {
		pPort = in_port;
	}

#ifdef WIN32
	SOCKADDR_IN address;
	unsigned long nonblocking = 1;
#else
	struct sockaddr_in address;
#endif
	int reuse_addr = 1;

	//	Setup internet address information.  
	//	This is used with the bind() call
	memset((char *) &address, 0, sizeof(address));
	address.sin_family = AF_INET;
	address.sin_port = htons(pPort);
	address.sin_addr.s_addr = htonl(INADDR_ANY);

	//	Setting up TCP port for new TCP connections
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "socket(): INVALID_SOCKET");
		return false;
	}

	// Quag: dont think following is good stuff for TCP, good for UDP
	// Mis: SO_REUSEADDR shouldn't be a problem for tcp--allows you to restart
	// without waiting for conns in TIME_WAIT to die
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));


	if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		sock = 0;
		if (errbuf)
			sprintf(errbuf, "bind(): <0");
		return false;
	}

	int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef WIN32
	ioctlsocket (sock, FIONBIO, &nonblocking);
#else
	fcntl(sock, F_SETFL, O_NONBLOCK);
#endif

	if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
#ifdef WIN32
		closesocket(sock);
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "listen() failed, Error: %d", WSAGetLastError());
#else
		close(sock);
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "listen() failed, Error: %s", strerror(errno));
#endif
		sock = 0;
		return false;
	}

	return true;
}

void TCPServer::Close() {
	LockMutex lock(&MSock);
	if (sock) {
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
	}
	sock = 0;
}

bool TCPServer::IsOpen() {
	MSock.lock();
	bool ret = (bool) (sock != 0);
	MSock.unlock();
	return ret;
}

TCPConnection* TCPServer::NewQueuePop() {
	TCPConnection* ret;
	MNewQueue.lock();
	ret = NewQueue.pop();
	MNewQueue.unlock();
	return ret;
}

void TCPServer::AddConnection(TCPConnection* con) {
	list->Append(con);
	MNewQueue.lock();
	NewQueue.push(con);
	MNewQueue.unlock();
}

TCPConnection* TCPServer::GetConnection(int32 iID) {
	LinkedListIterator<TCPConnection*> iterator(*list);

	iterator.Reset();
	while(iterator.MoreElements()) {
		if (iterator.GetData()->GetID() == iID)
			return iterator.GetData();
		iterator.Advance();
	}
	return 0;
}

void TCPServer::SendPacket(ServerPacket* pack) {
	TCPConnection::TCPNetPacket_Struct* tnps = TCPConnection::MakePacket(pack);
	SendPacket(&tnps);
}

void TCPServer::SendPacket(TCPConnection::TCPNetPacket_Struct** tnps) {
	MInQueue.lock();
	InQueue.push(*tnps);
	MInQueue.unlock();
	tnps = 0;
}

void TCPServer::CheckInQueue() {
	LinkedListIterator<TCPConnection*> iterator(*list);	
	TCPConnection::TCPNetPacket_Struct* tnps = 0;

	while (( tnps = InQueuePop() )) {
		iterator.Reset();
		while(iterator.MoreElements()) {
			if (iterator.GetData()->GetMode() != modeConsole && iterator.GetData()->GetRemoteID() == 0)
				iterator.GetData()->SendPacket(tnps);
			iterator.Advance();
		}
		safe_delete(tnps);
	}
}

TCPConnection::TCPNetPacket_Struct* TCPServer::InQueuePop() {
	TCPConnection::TCPNetPacket_Struct* ret;
	MInQueue.lock();
	ret = InQueue.pop();
	MInQueue.unlock();
	return ret;
}


