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