1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26#include "ServerSocket.h"	// Interface declarations
27
28#include <protocol/Protocols.h>
29#include <common/EventIDs.h>
30#include <tags/ServerTags.h>
31
32#include <wx/tokenzr.h>
33
34#include "Packet.h"		// Needed for CPacket
35#include "updownclient.h"	// Needed for CUpDownClient
36#include "ClientList.h"		// Needed for CClientList
37#include "MemFile.h"		// Needed for CMemFile
38#include "PartFile.h"		// Needed for CPartFile
39#include "SearchList.h"		// Needed for CSearchList
40#include "Preferences.h"	// Needed for CPreferences
41#include "DownloadQueue.h"	// Needed for CDownloadQueue
42#include "ServerList.h"		// Needed for CServerList
43#include "Server.h"		// Needed for CServer
44#include "amule.h"		// Needed for theApp
45#include "Statistics.h"		// Needed for theStats
46#include "AsyncDNS.h" // Needed for CAsyncDNS
47#include "Logger.h"
48#include <common/Format.h>
49#include "IPFilter.h"
50#include "GuiEvents.h"		// Needed for Notify_*
51
52
53
54//------------------------------------------------------------------------------
55// CServerSocketHandler
56//------------------------------------------------------------------------------
57
58//------------------------------------------------------------------------------
59// CServerSocketHandler
60//------------------------------------------------------------------------------
61
62
63class CServerSocketHandler: public wxEvtHandler
64{
65public:
66	CServerSocketHandler() {};
67
68public:
69private:
70	void ServerSocketHandler(wxSocketEvent& event);
71	DECLARE_EVENT_TABLE()
72};
73
74
75BEGIN_EVENT_TABLE(CServerSocketHandler, wxEvtHandler)
76	EVT_SOCKET(ID_SERVERSOCKET_EVENT, CServerSocketHandler::ServerSocketHandler)
77END_EVENT_TABLE()
78
79void CServerSocketHandler::ServerSocketHandler(wxSocketEvent& event)
80{
81	CServerSocket *socket = dynamic_cast<CServerSocket *>(event.GetSocket());
82	wxASSERT(socket);
83	if (!socket) {
84		return;
85	}
86
87	if (socket->OnDestroy()) {
88		return;
89	}
90
91	switch(event.GetSocketEvent()) {
92		case wxSOCKET_CONNECTION:
93			socket->OnConnect(wxSOCKET_NOERROR);
94			break;
95		case wxSOCKET_LOST:
96			socket->OnError(socket->LastError());
97			break;
98		case wxSOCKET_INPUT:
99			socket->OnReceive(wxSOCKET_NOERROR);
100			break;
101		case wxSOCKET_OUTPUT:
102			socket->OnSend(wxSOCKET_NOERROR);
103			break;
104		default:
105			wxFAIL;
106			break;
107	}
108
109
110}
111
112//
113// There can be only one. :)
114//
115static CServerSocketHandler g_serverSocketHandler;
116
117
118//------------------------------------------------------------------------------
119// CServerSocket
120//------------------------------------------------------------------------------
121
122CServerSocket::CServerSocket(CServerConnect* in_serverconnect, const CProxyData *ProxyData)
123:
124CEMSocket(ProxyData)
125{
126	serverconnect = in_serverconnect;
127	connectionstate = 0;
128	cur_server = 0;
129	info.Clear();
130	m_bIsDeleting = false;
131
132	SetEventHandler(g_serverSocketHandler, ID_SERVERSOCKET_EVENT);
133
134	SetNotify(
135		wxSOCKET_CONNECTION_FLAG |
136		wxSOCKET_INPUT_FLAG |
137		wxSOCKET_OUTPUT_FLAG |
138		wxSOCKET_LOST_FLAG);
139	Notify(true);
140
141	m_dwLastTransmission = 0;
142	m_IsSolving = false;
143	m_bNoCrypt = false;
144}
145
146CServerSocket::~CServerSocket()
147{
148	// remove event handler...
149	SetNotify(0);
150	Notify(FALSE);
151
152	if (cur_server) {
153		delete cur_server;
154	}
155	cur_server = NULL;
156}
157
158
159void CServerSocket::OnConnect(wxSocketError nErrorCode)
160{
161	switch (nErrorCode) {
162		case wxSOCKET_NOERROR:
163			if (cur_server->HasDynIP()) {
164				amuleIPV4Address tmpaddr;
165				GetPeer(tmpaddr);
166				uint32 server_ip = StringIPtoUint32(tmpaddr.IPAddress());
167				cur_server->SetID(server_ip);
168				// GetServerByAddress may return NULL, so we must test!
169				// This was the reason why amule would crash when trying to
170				// connect in wxWidgets 2.5.2
171				CServer *pServer = theApp->serverlist->GetServerByAddress(
172					cur_server->GetAddress(), cur_server->GetPort());
173				if (pServer) {
174					pServer->SetID(server_ip);
175				} else {
176					AddDebugLogLineN(logServer, wxT("theApp->serverlist->GetServerByAddress() returned NULL"));
177					return;
178				}
179			}
180			SetConnectionState(CS_WAITFORLOGIN);
181			break;
182
183		case wxSOCKET_INVADDR:
184		case wxSOCKET_NOHOST:
185		case wxSOCKET_INVPORT:
186		case wxSOCKET_TIMEDOUT:
187			m_bIsDeleting = true;
188			SetConnectionState(CS_SERVERDEAD);
189			serverconnect->DestroySocket(this);
190			return;
191
192		case wxSOCKET_IOERR:
193		case wxSOCKET_MEMERR:
194		case wxSOCKET_INVOP:
195		default:
196			m_bIsDeleting = true;
197			SetConnectionState(CS_FATALERROR);
198			serverconnect->DestroySocket(this);
199			return;
200
201	}
202
203}
204
205void CServerSocket::OnReceive(wxSocketError nErrorCode)
206{
207	if (connectionstate != CS_CONNECTED && !serverconnect->IsConnecting()) {
208		serverconnect->DestroySocket(this);
209		return;
210	}
211	CEMSocket::OnReceive((int)nErrorCode);
212	m_dwLastTransmission = GetTickCount();
213}
214
215bool CServerSocket::ProcessPacket(const byte* packet, uint32 size, int8 opcode)
216{
217	try {
218		AddDebugLogLineN( logServer, wxT("Processing Server Packet: ") );
219
220		switch(opcode) {
221			case OP_SERVERMESSAGE: {
222				/* Kry import of lugdunum 16.40 new features */
223				AddDebugLogLineN( logServer, wxT("Server: OP_SERVERMESSAGE") );
224
225				theStats::AddDownOverheadServer(size);
226				char* buffer = new char[size-1];
227				memcpy(buffer,&packet[2],size-2);
228				buffer[size-2] = 0;
229
230				wxString strMessages(char2unicode(buffer));
231
232				delete[] buffer;
233
234				// 16.40 servers do not send separate OP_SERVERMESSAGE packets for each line;
235				// instead of this they are sending all text lines with one OP_SERVERMESSAGE packet.
236
237				wxStringTokenizer token(strMessages,wxT("\r\n"),wxTOKEN_DEFAULT );
238
239				while (token.HasMoreTokens()) {
240					wxString message = token.GetNextToken();
241
242					bool bOutputMessage = true;
243					if (message.StartsWith(wxT("server version"))) {
244						wxString strVer = message.Mid(15,64); // truncate string to avoid misuse by servers in showing ads
245						strVer.Trim();
246						CServer* eserver = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(),cur_server->GetPort());
247						if (eserver) {
248							eserver->SetVersion(strVer);
249							Notify_ServerRefresh(eserver);
250						}
251					} else if (message.StartsWith(wxT("ERROR"))) {
252						CServer* pServer = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(),cur_server->GetPort());
253						wxString servername;
254						if (pServer) {
255							servername	= pServer->GetListName();
256						} else {
257							servername = _("Server");
258						}
259						AddLogLineN(CFormat( _("ERROR: %s (%s) - %s") )
260							% servername
261							% Uint32_16toStringIP_Port(cur_server->GetIP(), cur_server->GetPort())
262							% message.Mid(5,message.Len()).Trim(wxT(" :")));
263						bOutputMessage = false;
264
265					} else if (message.StartsWith(wxT("WARNING"))) {
266
267						CServer* pServer = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(),cur_server->GetPort());
268						wxString servername;
269						if (pServer) {
270							servername	= pServer->GetListName();
271						} else {
272							servername = _("Server");
273						}
274						AddLogLineN(CFormat( _("WARNING: %s (%s) - %s") )
275							% servername
276							% Uint32_16toStringIP_Port(cur_server->GetIP(), cur_server->GetPort())
277							% message.Mid(5,message.Len()).Trim(wxT(" :")));
278
279						bOutputMessage = false;
280					}
281
282					if (message.Find(wxT("[emDynIP: ")) != (-1) && message.Find(wxT("]")) != (-1) && message.Find(wxT("[emDynIP: ")) < message.Find(wxT("]"))){
283						wxString dynip = message.Mid(message.Find(wxT("[emDynIP: "))+10,message.Find(wxT("]")) - (message.Find(wxT("[emDynIP: "))+10));
284						dynip.Trim(wxT(" "));
285						if ( dynip.Length() && dynip.Length() < 51){
286							CServer* eserver = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(),cur_server->GetPort());
287							if (eserver){
288								eserver->SetDynIP(dynip);
289								cur_server->SetDynIP(dynip);
290								Notify_ServerRefresh(eserver);
291							}
292						}
293					}
294
295					if (bOutputMessage) {
296						theApp->AddServerMessageLine(message);
297					}
298				}
299				break;
300			}
301			case OP_IDCHANGE: {
302				AddDebugLogLineN(logServer, wxT("Server: OP_IDCHANGE"));
303
304				theStats::AddDownOverheadServer(size);
305
306				if (size < 4 /* uint32 (ID)*/) {
307					throw wxString(wxT("Corrupt or invalid loginanswer from server received"));
308				}
309
310				CMemFile data(packet, size);
311
312				uint32 new_id = data.ReadUInt32();
313
314				// save TCP flags in 'cur_server'
315				wxASSERT(cur_server);
316				uint32 ConnPort = 0;
317				CServer* pServer = NULL;
318				if (cur_server) {
319					uint32 rport = cur_server->GetConnPort();
320					pServer = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(), rport);
321					if (size >= 4+4 /* uint32 (ID) + uint32 (TCP flags)*/) {
322						cur_server->SetTCPFlags(data.ReadUInt32());
323						if (size >= 4+4+4 /* uint32 (ID) + uint32 (TCP flags) + uint32 (aux port) */) {
324							// aux port login : we should use the 'standard' port of this server to advertize to other clients
325							ConnPort = data.ReadUInt32();
326							cur_server->SetPort(ConnPort);
327							if (cur_server->GetAuxPortsList().IsEmpty()) {
328								cur_server->SetAuxPortsList(CFormat(wxT("%u")) % rport);
329							}
330						}
331					} else {
332						cur_server->SetTCPFlags(0);
333					}
334					// copy TCP flags into the server in the server list
335					if (pServer) {
336						pServer->SetTCPFlags(cur_server->GetTCPFlags());
337						if (ConnPort) {
338							pServer->SetPort(ConnPort);
339							if (pServer->GetAuxPortsList().IsEmpty()) {
340								pServer->SetAuxPortsList(CFormat(wxT("%u")) % pServer->GetConnPort());
341							}
342							Notify_ServerRefresh(pServer);
343							Notify_ServerUpdateED2KInfo();
344						}
345					}
346				}
347
348				uint32 dwServerReportedIP = 0;
349				uint32 dwObfuscationTCPPort = 0;
350				if (size >= 4 + 4 + 4 + 4 + 4 /* All of the above + reported ip + obfuscation port */) {
351					dwServerReportedIP = data.ReadUInt32();
352					if (::IsLowID(dwServerReportedIP)){
353						wxFAIL;
354						dwServerReportedIP = 0;
355					}
356					wxASSERT( dwServerReportedIP == new_id || ::IsLowID(new_id) );
357					dwObfuscationTCPPort = data.ReadUInt32();
358					if (cur_server != NULL && dwObfuscationTCPPort != 0) {
359						cur_server->SetObfuscationPortTCP((uint16)dwObfuscationTCPPort);
360					}
361
362					if (pServer != NULL && dwObfuscationTCPPort != 0) {
363						pServer->SetObfuscationPortTCP((uint16)dwObfuscationTCPPort);
364					}
365				}
366
367				if (new_id == 0) {
368					uint8 state = thePrefs::GetSmartIdState();
369					if ( state > 0 ) {
370						state++;
371						if(state > 3) {
372							thePrefs::SetSmartIdState(0);
373						} else {
374							thePrefs::SetSmartIdState(state);
375						}
376					}
377					break;
378				}
379				if(thePrefs::GetSmartIdCheck()) {
380					if (!IsLowID(new_id)) {
381						thePrefs::SetSmartIdState(1);
382					} else {
383						uint8 state = thePrefs::GetSmartIdState();
384						if ( state > 0 ) {
385							state++;
386							if(state > 3) {
387								thePrefs::SetSmartIdState(0);
388							} else {
389								thePrefs::SetSmartIdState(state);
390							}
391							break;
392						}
393					}
394				}
395
396				// we need to know our client when sending our shared files (done indirectly on SetConnectionState)
397
398				serverconnect->SetClientID(new_id);
399
400				if (::IsLowID(new_id) && dwServerReportedIP != 0) {
401					theApp->SetPublicIP(dwServerReportedIP);
402				}
403
404				if (connectionstate != CS_CONNECTED) {
405					AddDebugLogLineN(logServer, wxT("Connected"));
406
407					SetConnectionState(CS_CONNECTED);
408					theApp->OnlineSig();       // Added By Bouc7
409				}
410
411				theApp->ShowConnectionState();
412
413				AddLogLineN(CFormat(_("New clientid is %u")) % new_id);
414				if (::IsLowID(new_id)) {
415					AddLogLineC(_("WARNING: You have received Low-ID!"));
416					AddLogLineN(_("\tMost likely this is because you're behind a firewall or router."));
417					AddLogLineN(_("\tFor more information, please refer to http://wiki.amule.org"));
418				}
419
420				theApp->downloadqueue->ResetLocalServerRequests();
421				break;
422			}
423			case OP_SEARCHRESULT: {
424				AddDebugLogLineN(logServer, wxT("Server: OP_SEARCHRESULT"));
425
426				theStats::AddDownOverheadServer(size);
427				CServer* cur_srv = (serverconnect) ?
428					serverconnect->GetCurrentServer() : NULL;
429				theApp->searchlist->ProcessSearchAnswer(
430					packet,
431					size,
432					true /*(cur_srv && cur_srv->GetUnicodeSupport())*/,
433					cur_srv ? cur_srv->GetIP() : 0,
434					cur_srv ? cur_srv->GetPort() : 0);
435				theApp->searchlist->LocalSearchEnd();
436				break;
437			}
438			case OP_FOUNDSOURCES_OBFU:
439			case OP_FOUNDSOURCES: {
440				AddDebugLogLineN(logServer, CFormat(wxT("ServerMsg - OP_FoundSources; sources = %u")) % packet[16]);
441				theStats::AddDownOverheadServer(size);
442				CMemFile sources(packet,size);
443				CMD4Hash fileid = sources.ReadHash();
444				if (CPartFile* file = theApp->downloadqueue->GetFileByID(fileid)) {
445					file->AddSources(sources, cur_server->GetIP(), cur_server->GetPort(), SF_LOCAL_SERVER, (opcode == OP_FOUNDSOURCES_OBFU));
446				} else {
447					AddDebugLogLineN(logServer, wxT("Sources received for unknown file: ") + fileid.Encode());
448				}
449				break;
450			}
451			case OP_SERVERSTATUS: {
452				AddDebugLogLineN(logServer, wxT("Server: OP_SERVERSTATUS"));
453				// FIXME some statuspackets have a different size -> why? structur?
454				if (size < 8) {
455					throw wxString(wxT("Invalid server status packet"));
456					break;
457				}
458				CServer* update = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(), cur_server->GetPort());
459				if (update) {
460					CMemFile data(packet, size);
461					update->SetUserCount(data.ReadUInt32());
462					update->SetFileCount(data.ReadUInt32());
463					Notify_ServerRefresh( update );
464					theApp->ShowUserCount();
465				}
466				break;
467			}
468			// Cleaned.
469			case OP_SERVERIDENT: {
470				AddDebugLogLineN(logServer, wxT("Server: OP_SERVERIDENT"));
471
472				theStats::AddDownOverheadServer(size);
473				if (size<38) {
474					AddLogLineN(_("Unknown server info received! - too short"));
475					// throw wxString(wxT("Unknown server info received!"));
476					break;
477				}
478				CServer* update = theApp->serverlist->GetServerByAddress(cur_server->GetAddress(),cur_server->GetPort());
479				if (update) {
480					CMemFile data(packet,size);
481					CMD4Hash hash = data.ReadHash();
482					if (RawPeekUInt32(hash.GetHash()) == 0x2A2A2A2A){ // No endian problem here
483						const wxString& rstrVersion = update->GetVersion();
484						if (!rstrVersion.IsEmpty()) {
485							update->SetVersion(wxT("eFarm ") + rstrVersion);
486						} else {
487							update->SetVersion(wxT("eFarm"));
488						}
489					}
490					// Unused
491					/*uint32 nServerIP = */data.ReadUInt32();
492					/*uint16 nServerPort = */data.ReadUInt16();
493
494					uint32 nTags = data.ReadUInt32();
495					for (uint32 i = 0; i < nTags; i++){
496						CTag tag(data, update->GetUnicodeSupport());
497						if (tag.GetNameID() == ST_SERVERNAME){
498							update->SetListName(tag.GetStr());
499						} else if (tag.GetNameID() == ST_DESCRIPTION){
500							update->SetDescription(tag.GetStr());
501						} // No more known tags from server
502					}
503
504					theApp->ShowConnectionState();
505					Notify_ServerRefresh(update);
506				}
507				break;
508			}
509			// tecxx 1609 2002 - add server's serverlist to own serverlist
510			case OP_SERVERLIST: {
511				AddDebugLogLineN(logServer, wxT("Server: OP_SERVERLIST"));
512
513				CMemFile* servers = new CMemFile(packet,size);
514				uint8 count = servers->ReadUInt8();
515				if (((int32)(count*6 + 1) > size)) {
516					count = 0;
517				}
518				int addcount = 0;
519				while(count) {
520					uint32 ip	= servers->ReadUInt32();
521					uint16 port = servers->ReadUInt16();
522					CServer* srv = new CServer(
523								port ,				// Port
524								Uint32toStringIP(ip)); 	// Ip
525					srv->SetListName(srv->GetFullIP());
526					if (!theApp->AddServer(srv)) {
527						delete srv;
528					} else {
529						addcount++;
530					}
531					count--;
532				}
533				delete servers;
534				if (addcount) {
535					AddLogLineN(CFormat(wxPLURAL("Received %d new server", "Received %d new servers", addcount)) % addcount);
536				}
537				theApp->serverlist->SaveServerMet();
538				AddLogLineN(_("Saving of server-list completed."));
539				break;
540			}
541			case OP_CALLBACKREQUESTED: {
542				AddDebugLogLineN(logServer, wxT("Server: OP_CALLBACKREQUESTED"));
543
544				theStats::AddDownOverheadServer(size);
545				if (size >= 6) {
546					CMemFile data(packet,size);
547					uint32 dwIP = data.ReadUInt32();
548					uint16 nPort = data.ReadUInt16();
549
550					uint8 byCryptOptions = 0;
551					CMD4Hash achUserHash;
552					if (size >= 23){
553						byCryptOptions = data.ReadUInt8();;
554						achUserHash = data.ReadHash();
555					}
556
557					CUpDownClient* client = theApp->clientlist->FindClientByIP(dwIP,nPort);
558
559					if (!client) {
560						client = new CUpDownClient(nPort,dwIP,0,0,0, true, true);
561						theApp->clientlist->AddClient(client);
562					}
563					if (size >= 23 && client->HasValidHash()){
564						if (client->GetUserHash() != achUserHash){
565							AddDebugLogLineN(logServer, wxT("Reported Userhash from OP_CALLBACKREQUESTED differs with our stored hash"));
566							// disable crypt support since we dont know which hash is true
567							client->SetCryptLayerRequest(false);
568							client->SetCryptLayerSupport(false);
569							client->SetCryptLayerRequires(false);
570						} else {
571							client->SetConnectOptions(byCryptOptions, true, false);
572						}
573					} else if (size >= 23) {
574						client->SetUserHash(achUserHash);
575						client->SetConnectOptions(byCryptOptions, true, false);
576					}
577
578					client->TryToConnect();
579				}
580				break;
581			}
582			case OP_CALLBACK_FAIL: {
583				AddDebugLogLineN(logServer, wxT("Server: OP_CALLBACK_FAIL"));
584				break;
585			}
586			case OP_REJECT: {
587				AddDebugLogLineN(logServer, wxT("Server: OP_REJECT"));
588				AddLogLineN(_("Server rejected last command"));
589				break;
590			}
591			default:
592				AddDebugLogLineN(logPacketErrors, CFormat(wxT("Unknown server packet with OPcode %x")) % opcode);
593		}
594		return true;
595	} catch (const CInvalidPacket& e) {
596		AddLogLineN(CFormat( _("Bogus packet received from server: %s") ) % e.what());
597	} catch (const CEOFException& e) {
598		AddLogLineN(CFormat( _("Bogus packet received from server: %s") ) % e.what());
599	} catch (const wxString& error) {
600		AddLogLineN(CFormat( _("Unhandled error while processing packet from server: %s") ) % error);
601	}
602
603	// Don't disconnect because of wrong sources.
604	if (opcode==OP_SEARCHRESULT || opcode==OP_FOUNDSOURCES) {
605		return true;
606	}
607
608	SetConnectionState(CS_DISCONNECTED);
609	return false;
610}
611
612void CServerSocket::ConnectToServer(CServer* server, bool bNoCrypt)
613{
614	AddDebugLogLineN(logServer, wxT("Trying to connect"));
615
616	if (cur_server){
617		wxFAIL;
618		delete cur_server;
619		cur_server = NULL;
620	}
621
622	cur_server = new CServer(server);
623
624	m_bNoCrypt = bNoCrypt;
625
626	SetConnectionState(CS_CONNECTING);
627
628	info = cur_server->GetListName();
629
630	// This must be used if we want to reverse-check the addr of the server
631	if (cur_server->HasDynIP() || !cur_server->GetIP()) {
632		m_IsSolving = true;
633		// Send it to solving thread.
634		CAsyncDNS* dns = new CAsyncDNS(server->GetAddress(), DNS_SERVER_CONNECT, theApp, this);
635
636		if ( dns->Create() == wxTHREAD_NO_ERROR ) {
637			if ( dns->Run() != wxTHREAD_NO_ERROR ) {
638				dns->Delete();
639				AddLogLineN(CFormat( _("Cannot create DNS solving thread for connecting to %s") ) % cur_server->GetAddress());
640			}
641		} else {
642			dns->Delete();
643			AddLogLineN(CFormat( _("Cannot create DNS solving thread for connecting to %s") ) % cur_server->GetAddress());
644		}
645	} else {
646		// Nothing to solve, we already have the IP
647		OnHostnameResolved(cur_server->GetIP());
648	}
649
650}
651
652void CServerSocket::OnError(wxSocketError DEBUG_ONLY(nErrorCode))
653{
654	AddDebugLogLineN(logServer, CFormat(wxT("Error in serversocket: %s(%s:%i): %u"))
655		% cur_server->GetListName() % cur_server->GetFullIP() % cur_server->GetPort() % (int)nErrorCode);
656	SetConnectionState(CS_DISCONNECTED);
657}
658
659
660bool CServerSocket::PacketReceived(CPacket* packet)
661{
662	AddDebugLogLineN(logServer, CFormat(wxT("Server: Packet Received: Prot %x, Opcode %x, Length %u")) % packet->GetProtocol() % packet->GetOpCode() % packet->GetPacketSize());
663
664	if (packet->GetProtocol() == OP_PACKEDPROT) {
665		if (!packet->UnPackPacket(250000)){
666			AddDebugLogLineN(logZLib, CFormat(wxT("Failed to decompress server TCP packet: protocol=0x%02x  opcode=0x%02x  size=%u"))
667				% packet->GetProtocol() % packet->GetOpCode() % packet->GetPacketSize());
668			theStats::AddDownOverheadServer(packet->GetPacketSize());
669			return true;
670		}
671
672		packet->SetProtocol(OP_EDONKEYPROT);
673	}
674
675	if (packet->GetProtocol() == OP_EDONKEYPROT) {
676		ProcessPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
677	} else {
678		AddDebugLogLineN(logServer, CFormat(wxT("Received server TCP packet with unknown protocol: protocol=0x%02x  opcode=0x%02x  size=%u"))
679			% packet->GetProtocol() % packet->GetOpCode() % packet->GetPacketSize());
680		theStats::AddDownOverheadServer(packet->GetPacketSize());
681	}
682
683	return true;
684}
685
686
687void CServerSocket::OnClose(wxSocketError WXUNUSED(nErrorCode))
688{
689	CEMSocket::OnClose(0);
690
691	switch (connectionstate) {
692		case CS_WAITFORLOGIN:	SetConnectionState(CS_SERVERFULL);		break;
693		case CS_CONNECTED:	SetConnectionState(CS_DISCONNECTED);	break;
694		default:				SetConnectionState(CS_NOTCONNECTED);
695	}
696
697	serverconnect->DestroySocket(this);
698}
699
700void CServerSocket::SetConnectionState(sint8 newstate)
701{
702	connectionstate = newstate;
703	if (newstate < CS_CONNECTING) {
704		serverconnect->ConnectionFailed(this);
705	} else if (newstate == CS_CONNECTED || newstate == CS_WAITFORLOGIN) {
706		if (serverconnect) {
707			serverconnect->ConnectionEstablished(this);
708		}
709	}
710}
711
712
713void CServerSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
714{
715	m_dwLastTransmission = GetTickCount();
716	CEMSocket::SendPacket(packet, delpacket, controlpacket, actualPayloadSize);
717}
718
719
720void CServerSocket::OnHostnameResolved(uint32 ip) {
721
722	m_IsSolving = false;
723	if (ip) {
724		if (theApp->ipfilter->IsFiltered(ip, true)) {
725			AddLogLineC(CFormat( _("Server IP %s (%s) is filtered.  Not connecting.") )
726				% Uint32toStringIP(ip) % cur_server->GetAddress() );
727			OnConnect(wxSOCKET_INVADDR);
728		} else {
729			amuleIPV4Address addr;
730			addr.Hostname(ip);
731			uint16 nPort = 0;
732			wxString useObfuscation;
733			if ( !m_bNoCrypt && thePrefs::IsServerCryptLayerTCPRequested() && cur_server->GetObfuscationPortTCP() != 0 && cur_server->SupportsObfuscationTCP()){
734				nPort = cur_server->GetObfuscationPortTCP();
735				useObfuscation = _("using protocol obfuscation.");
736				SetConnectionEncryption(true, NULL, true);
737			} else {
738				nPort = cur_server->GetConnPort();
739				SetConnectionEncryption(false, NULL, true);
740			}
741
742			addr.Service(nPort);
743
744			AddLogLineN(CFormat( _("Connecting to %s (%s - %s:%i) %s") )
745				% cur_server->GetListName()
746				% cur_server->GetAddress()
747				% cur_server->GetFullIP()
748				% nPort
749				% useObfuscation
750			);
751
752			AddDebugLogLineN(logServer, CFormat(wxT("Server %s(%s) Port %i"))
753				% cur_server->GetAddress() % Uint32toStringIP(ip) % cur_server->GetConnPort());
754			Connect(addr, false);
755		}
756	} else {
757		AddLogLineC(CFormat( _("Could not solve dns for server %s: Unable to connect!") )
758			% cur_server->GetAddress() );
759		OnConnect(wxSOCKET_NOHOST);
760	}
761
762}
763uint32 CServerSocket::GetServerIP() const
764{
765	return cur_server ? cur_server->GetIP() : 0;
766}
767// File_checked_for_headers
768