Fix compile error
[amule.git] / src / Proxy.cpp
blob3c02579546d8cca1c692afc8e0169ff002bd212b
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2004-2011 Marcelo Roberto Jimenez ( phoenix@amule.org )
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.
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.
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.
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
26 #include "Proxy.h" /* for Interface */
28 #include <common/EventIDs.h>
30 #include "ArchSpecific.h" /* for ENDIAN_HTONS() */
31 #include "Logger.h" /* for AddDebugLogLineN */
32 #include "OtherFunctions.h" /* for EncodeBase64() */
33 #include <common/StringFunctions.h> /* for unicode2char */
34 #include "GuiEvents.h"
36 //------------------------------------------------------------------------------
37 // CProxyData
38 //------------------------------------------------------------------------------
40 CProxyData::CProxyData()
42 Clear();
45 CProxyData::CProxyData(
46 bool proxyEnable,
47 CProxyType proxyType,
48 const wxString &proxyHostName,
49 unsigned short proxyPort,
50 bool enablePassword,
51 const wxString &userName,
52 const wxString &password)
54 m_proxyEnable(proxyEnable),
55 m_proxyType(proxyType),
56 m_proxyHostName(proxyHostName),
57 m_proxyPort(proxyPort),
59 * The flag m_enablePassword is currently not used. The first
60 * authentication method tryed is No-Authentication, the second
61 * is username/password. If there is no username/password in
62 * CProxyData, a NULL username/password is sent. That will probably
63 * lead to a failure, but at least we tryed. Maybe this behaviour
64 * could be altered later.
66 m_enablePassword(enablePassword),
67 m_userName(userName),
68 m_password(password)
72 void CProxyData::Clear()
74 m_proxyEnable = false;
75 m_proxyType = PROXY_NONE;
76 m_proxyHostName.Clear();
77 m_proxyPort = 0;
78 m_enablePassword = false;
79 m_userName.Clear();
80 m_password.Clear();
83 #ifndef CLIENT_GUI
85 #include <typeinfo> // Do_not_auto_remove (NetBSD, older gccs)
87 //------------------------------------------------------------------------------
88 // ProxyEventHandler
89 //------------------------------------------------------------------------------
91 CProxyEventHandler::CProxyEventHandler()
95 BEGIN_EVENT_TABLE(CProxyEventHandler, wxEvtHandler)
96 EVT_SOCKET(ID_PROXY_SOCKET_EVENT, CProxyEventHandler::ProxySocketHandler)
97 END_EVENT_TABLE()
100 // THE one and only Event Handler
102 static CProxyEventHandler g_proxyEventHandler;
104 void CProxyEventHandler::ProxySocketHandler(wxSocketEvent& event)
106 CProxySocket *sock = dynamic_cast<CProxySocket *>(event.GetSocket());
107 if (sock) {
108 sock->m_proxyStateMachine->Schedule(event.GetSocketEvent());
109 sock->m_proxyStateMachine->Clock();
110 } else {
111 // we're doomed :)
116 // In Asio mode the event handler is:
118 void CProxySocket::OnProxyEvent(int evt)
120 m_proxyStateMachine->Schedule(evt);
121 m_proxyStateMachine->Clock();
124 //------------------------------------------------------------------------------
125 // CProxyStateMachine
126 //------------------------------------------------------------------------------
128 CProxyStateMachine::CProxyStateMachine(
129 wxString name,
130 const unsigned int max_states,
131 const CProxyData &proxyData,
132 CProxyCommand proxyCommand)
134 CStateMachine(NewName(name, proxyCommand), max_states, PROXY_STATE_START),
135 m_proxyData(proxyData),
136 m_proxyCommand(proxyCommand),
137 m_isLost(false),
138 m_isConnected(false),
139 m_canReceive(false),
140 m_canSend(false),
141 m_ok(true),
142 m_lastRead(0),
143 // Will be initialized at Start()
144 m_peerAddress(NULL),
145 m_proxyClientSocket(NULL),
146 m_proxyBoundAddress(NULL),
147 // Temporary variables
148 m_lastReply(0),
149 m_packetLenght(0)
153 CProxyStateMachine::~CProxyStateMachine()
155 delete m_peerAddress;
158 wxString &CProxyStateMachine::NewName(wxString &s, CProxyCommand proxyCommand)
160 switch (proxyCommand) {
161 case PROXY_CMD_CONNECT:
162 s += wxT("-CONNECT");
163 break;
165 case PROXY_CMD_BIND:
166 s += wxT("-BIND");
167 break;
169 case PROXY_CMD_UDP_ASSOCIATE:
170 s += wxT("-UDP");
171 break;
174 return s;
177 bool CProxyStateMachine::Start(const amuleIPV4Address &peerAddress, CLibSocket *proxyClientSocket)
179 m_proxyClientSocket = proxyClientSocket;
180 m_peerAddress = new amuleIPV4Address(peerAddress);
181 //try {
182 // const wxIPV4address &peer = dynamic_cast<const wxIPV4address &>(peerAddress);
183 // m_peerAddress = new amuleIPV4Address(peer);
184 //} catch (const std::bad_cast& WXUNUSED(e)) {
185 // // Should process other types of wxIPAddres before quitting
186 // AddDebugLogLineN(logProxy, wxT("(1)bad_cast exception!"));
187 // wxFAIL;
188 // return false;
191 // To run the state machine, return and just let the events start to happen.
192 return true;
195 static const int wxSOCKET_DUMMY_VALUE = wxSOCKET_INPUT + wxSOCKET_OUTPUT + wxSOCKET_CONNECTION + wxSOCKET_LOST;
197 t_sm_state CProxyStateMachine::HandleEvent(t_sm_event event)
199 // Default is stay in current state
200 t_sm_state ret = GetState();
201 switch(event)
203 case wxSOCKET_CONNECTION:
204 AddDebugLogLineN(logProxy, wxT("Connection event"));
205 m_isConnected = true;
206 break;
208 case wxSOCKET_INPUT:
209 AddDebugLogLineN(logProxy, wxT("Input event"));
210 m_canReceive = true;
211 break;
213 case wxSOCKET_OUTPUT:
214 AddDebugLogLineN(logProxy, wxT("Output event"));
215 m_canSend = true;
216 break;
218 case wxSOCKET_LOST:
219 AddDebugLogLineN(logProxy, wxT("Lost connection event"));
220 m_isLost = true;
221 m_ok = false;
222 break;
224 case wxSOCKET_DUMMY_VALUE:
225 AddDebugLogLineN(logProxy, wxT("Dummy event"));
226 break;
228 default:
229 AddDebugLogLineN(logProxy, CFormat(wxT("Unknown event %d")) % event);
230 break;
233 // Aborting conditions:
234 // - wxSOCKET_LOST event
235 // - More than 10 times on the same state
236 if ( m_isLost ||
237 GetClocksInCurrentState() > 10) {
238 ret = PROXY_STATE_END;
241 return ret;
244 void CProxyStateMachine::AddDummyEvent()
246 #ifdef ASIO_SOCKETS
247 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
248 if (s) { // should always be
249 CoreNotify_ProxySocketEvent(s, wxSOCKET_DUMMY_VALUE);
251 #else
252 wxSocketEvent e(ID_PROXY_SOCKET_EVENT);
253 // Make sure this is an unknown event :)
254 e.m_event = (wxSocketNotify)(wxSOCKET_DUMMY_VALUE);
255 e.SetEventObject(m_proxyClientSocket);
256 g_proxyEventHandler.AddPendingEvent(e);
257 #endif
261 * Notice! These includes are here as long as it is impossible to retrieve
262 * the event handler from the socket. They should be removed. For now,
263 * please leave it here.
266 void CProxyStateMachine::ReactivateSocket()
268 /* If proxy is beeing used, then the TCP socket handlers
269 * (CServerSocketHandler and CClientTCPSocketHandler) will not
270 * receive a wxSOCKET_CONNECTION event, because the connection has
271 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
272 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
273 * necessary to start sending data to the server. */
274 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
275 // If that is not true, we are in serious trouble...
276 wxASSERT(s);
277 if (CDatagramSocketProxy *udp = s->GetUDPSocket()) {
278 // The original socket was a UDP socket
279 if(m_ok) {
280 // From now on, the UDP socket can be used,
281 // remove the protection.
282 udp->SetUDPSocketOk();
284 // No need to call RestoreState(), that socket will no longer
285 // be used after proxy negotiation.
286 } else {
287 // The original socket was a TCP socket
288 #ifdef ASIO_SOCKETS
289 if (s->GetProxyState()) { // somehow this gets called twice ?
290 s->SetProxyState(false);
291 CoreNotify_LibSocketConnect(s, 0);
292 if (m_ok) {
293 CoreNotify_LibSocketSend(s, 0);
294 } else {
295 CoreNotify_LibSocketLost(s);
298 #else
299 s->RestoreEventHandler();
300 wxSocketEvent e(s->GetEventHandlerId());
301 e.m_event = wxSOCKET_CONNECTION;
302 e.SetEventObject(s);
303 wxEvtHandler *h(s->GetEventHandler());
304 h->AddPendingEvent(e);
305 e.m_event = wxSOCKET_OUTPUT;
306 h->AddPendingEvent(e);
307 if (!m_ok) {
308 e.m_event = wxSOCKET_LOST;
309 h->AddPendingEvent(e);
311 s->RestoreState();
312 #endif
316 uint32 CProxyStateMachine::ProxyWrite(CLibSocket &socket, const void *buffer, wxUint32 nbytes)
318 uint32 written = socket.Write(buffer, nbytes);
319 /* Set the status of this operation */
320 m_ok = true;
321 if (m_proxyClientSocket->BlocksWrite()) {
322 m_lastError = 0;
323 m_canSend = false;
324 } else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
325 m_ok = false;
327 AddDebugLogLineN(logProxy, CFormat(wxT("ProxyWrite %d %d ok %d cansend %d")) % nbytes % written % m_ok % m_canSend);
329 return written;
332 uint32 CProxyStateMachine::ProxyRead(CLibSocket &socket, void *buffer)
334 /* Always try to read the full buffer. That explicitly demands that
335 * the socket has the flag wxSOCKET_NONE. */
336 m_lastRead = socket.Read(buffer, PROXY_BUFFER_SIZE);
337 /* Set the status of this operation */
338 m_ok = true;
339 if (m_proxyClientSocket->BlocksRead()) {
340 m_lastError = 0;
341 m_canReceive = false;
342 } else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
343 m_ok = false;
345 #ifdef ASIO_SOCKETS
346 // We will get a new event right away if data is left, or when new data gets available.
347 // So block for now.
348 m_canReceive = false;
349 #endif
350 AddDebugLogLineN(logProxy, CFormat(wxT("ProxyRead %d ok %d canrec %d")) % m_lastRead % m_ok % m_canReceive);
352 return m_lastRead;
355 bool CProxyStateMachine::CanReceive() const
357 return m_canReceive;
360 bool CProxyStateMachine::CanSend() const
362 return m_canSend;
365 //------------------------------------------------------------------------------
366 // CSocks5StateMachine
367 //------------------------------------------------------------------------------
370 * The state machine constructor must initialize the array of pointer to member
371 * functions. Don't waste you time trying to statically initialize this, pointer
372 * to member functions require an object to operate on, so this array must be
373 * initialized at run time.
375 CSocks5StateMachine::CSocks5StateMachine(
376 const CProxyData &proxyData,
377 CProxyCommand proxyCommand)
379 CProxyStateMachine(
380 wxString(wxT("Socks5")), SOCKS5_MAX_STATES, proxyData, proxyCommand)
382 m_process_state[ 0] = &CSocks5StateMachine::process_start;
383 m_state_name[ 0] = wxT("process_start");
384 m_process_state[ 1] = &CSocks5StateMachine::process_end;
385 m_state_name[ 1] = wxT("process_end");
386 m_process_state[ 2] = &CSocks5StateMachine::process_send_query_authentication_method;
387 m_state_name[ 2] = wxT("process_send_query_authentication_method");
388 m_process_state[ 3] = &CSocks5StateMachine::process_receive_authentication_method;
389 m_state_name[ 3] = wxT("process_receive_authentication_method");
390 m_process_state[ 4] = &CSocks5StateMachine::process_process_authentication_method;
391 m_state_name[ 4] = wxT("process_process_authentication_method");
392 m_process_state[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi;
393 m_state_name[ 5] = wxT("process_send_authentication_gssapi");
394 m_process_state[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi;
395 m_state_name[ 6] = wxT("process_receive_authentication_gssapi");
396 m_process_state[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi;
397 m_state_name[ 7] = wxT("process_process_authentication_gssapi");
398 m_process_state[ 8] = &CSocks5StateMachine::process_send_authentication_username_password;
399 m_state_name[ 8] = wxT("process_send_authentication_username_password");
400 m_process_state[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password;
401 m_state_name[ 9] = wxT("process_receive_authentication_username_password");
402 m_process_state[10] = &CSocks5StateMachine::process_process_authentication_username_password;
403 m_state_name[10] = wxT("process_process_authentication_username_password");
404 m_process_state[11] = &CSocks5StateMachine::process_send_command_request;
405 m_state_name[11] = wxT("process_send_command_request");
406 m_process_state[12] = &CSocks5StateMachine::process_receive_command_reply;
407 m_state_name[12] = wxT("process_receive_command_reply");
408 m_process_state[13] = &CSocks5StateMachine::process_process_command_reply;
409 m_state_name[13] = wxT("process_process_command_reply");
412 void CSocks5StateMachine::process_state(t_sm_state state, bool entry)
414 /* Ok, the syntax is terrible, but this is correct. This is a
415 * pointer to a member function. No C equivalent for that. */
416 (this->*m_process_state[state])(entry);
417 #ifdef __DEBUG__
418 int n = 0;
420 switch (state) {
421 case SOCKS5_STATE_START:
422 case SOCKS5_STATE_END:
423 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
424 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
425 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
426 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
427 default:
428 n = 0;
429 break;
431 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
432 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
433 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
434 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
435 n = m_packetLenght;
436 break;
438 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
439 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
440 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
441 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
442 n = m_lastRead;
443 break;
446 if (entry) {
447 DumpMem(m_buffer, n, m_state_name[state], m_ok);
448 } else {
449 AddDebugLogLineN(logProxy,
450 wxString(wxT("wait state -- ")) << m_state_name[state]);
452 #endif // __DEBUG__
456 * Code this such that the next state is only entered when it is able to
457 * perform the operation (read or write). State processing will assume
458 * that it can read or write upon entry of the state. This is done using
459 * CanSend() and CanReceive(). On daemon, these functions always return
460 * true, because sockets are blocking.
462 t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
464 // Default is stay in current state
465 t_sm_state ret = HandleEvent(event);
466 switch (GetState()) {
467 case SOCKS5_STATE_START:
468 if (m_isConnected && !m_isLost && CanSend()) {
469 ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
471 break;
473 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
474 if (CanReceive()) {
475 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
477 break;
479 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
480 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
481 break;
483 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
484 if (m_ok) {
485 if (CanSend()) {
486 switch (m_lastReply) {
487 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
488 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
489 break;
491 case SOCKS5_AUTH_METHOD_GSSAPI:
492 ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
493 break;
495 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
496 ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
497 break;
499 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
500 default:
501 ret = SOCKS5_STATE_END;
502 break;
504 } else {
505 AddDebugLogLineN(logProxy, wxT("Can't send"));
507 } else {
508 ret = SOCKS5_STATE_END;
510 break;
512 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
513 if (m_ok) {
514 if (CanReceive()) {
515 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
517 } else {
518 ret = SOCKS5_STATE_END;
520 break;
522 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
523 if (m_ok) {
524 if (CanReceive()) {
525 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
527 } else {
528 ret = SOCKS5_STATE_END;
530 break;
532 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
533 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
534 break;
536 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
537 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
538 break;
540 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
541 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
542 if (m_ok) {
543 if (CanSend()) {
544 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
546 } else {
547 ret = SOCKS5_STATE_END;
549 break;
551 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
552 if (m_ok) {
553 if (CanReceive()) {
554 ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
556 } else {
557 ret = SOCKS5_STATE_END;
559 break;
561 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
562 ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
563 break;
565 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
566 ret = SOCKS5_STATE_END;
567 break;
569 case SOCKS5_STATE_END:
570 default:
571 break;
574 return ret;
578 * So, this is how you do it: the state machine is clocked by the events
579 * that happen inside the event handler. You can add a dummy event whenever
580 * you see that the system will not generate an event. But don't add dummy
581 * events before reads, reads should only be performed after input events.
583 * Maybe it makes sense to add a dummy event before a read if there is no
584 * state change (wait state).
586 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
587 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
588 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
589 * event will be generated. If you feel you will need more clocks than these, use
590 * AddDummyEvent(), but I suggest you review your state machine design first.
592 void CSocks5StateMachine::process_start(bool)
595 void CSocks5StateMachine::process_end(bool)
597 ReactivateSocket();
600 void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
602 if (entry) {
603 // Prepare the authentication method negotiation packet
604 m_buffer[0] = SOCKS5_VERSION;
605 m_buffer[1] = 2; // Number of supported methods
606 //m_buffer[1] = 3; // Number of supported methods
607 m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
608 m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
609 m_buffer[4] = SOCKS5_AUTH_METHOD_GSSAPI;
610 m_packetLenght = 4;
611 //m_packetLenght = 5;
613 // Send the authentication method negotiation packet
614 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
618 void CSocks5StateMachine::process_receive_authentication_method(bool entry)
620 if (entry) {
621 // Receive the method selection message
622 m_packetLenght = 2;
623 ProxyRead(*m_proxyClientSocket, m_buffer);
625 /* This is added because there will be no more input events. If the
626 * world was a nice place, we could think about joining the
627 * process_receive and the process_process states here, but some day
628 * we might have to deal with the fact that the i/o operation has been
629 * incomplete, and that we must finish our job the next time we enter
630 * this state. */
631 AddDummyEvent();
634 void CSocks5StateMachine::process_process_authentication_method(bool entry)
636 if (entry) {
637 m_lastReply = m_buffer[1];
638 m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
640 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
641 * once when you connect the socket, and after that, only after a
642 * wxSOCKET_WOULDBLOCK error happens. */
643 AddDummyEvent();
646 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
648 // TODO or not TODO? That is the question...
649 m_ok = false;
652 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
654 AddDummyEvent();
657 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
659 AddDummyEvent();
662 void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
664 if (entry) {
665 unsigned char lenUser = m_proxyData.m_userName.Len();
666 unsigned char lenPassword = m_proxyData.m_password.Len();
667 m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
668 unsigned int offsetUser = 2;
669 unsigned int offsetPassword = offsetUser + lenUser + 1;
671 // Prepare username/password buffer
672 m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
673 m_buffer[offsetUser-1] = lenUser;
674 memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
675 lenUser);
676 m_buffer[offsetPassword-1] = lenPassword;
677 memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
678 lenPassword);
680 // Send the username/password packet
681 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
685 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
687 if (entry) {
688 // Receive the server's authentication response
689 m_packetLenght = 2;
690 ProxyRead(*m_proxyClientSocket, m_buffer);
692 AddDummyEvent();
695 void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
697 if (entry) {
698 // Process the server's reply
699 m_lastReply = m_buffer[1];
700 m_ok = m_ok &&
701 m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
702 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
704 AddDummyEvent();
707 void CSocks5StateMachine::process_send_command_request(bool entry)
709 if (entry) {
710 // Prepare the request command buffer
711 m_buffer[0] = SOCKS5_VERSION;
712 switch (m_proxyCommand) {
713 case PROXY_CMD_CONNECT:
714 m_buffer[1] = SOCKS5_CMD_CONNECT;
715 break;
717 case PROXY_CMD_BIND:
718 m_buffer[1] = SOCKS5_CMD_BIND;
719 break;
721 case PROXY_CMD_UDP_ASSOCIATE:
722 m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
723 break;
725 m_buffer[2] = SOCKS5_RSV;
726 m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
727 PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
728 RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
730 // Send the command packet
731 m_packetLenght = 10;
732 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
736 void CSocks5StateMachine::process_receive_command_reply(bool entry)
738 if (entry) {
739 // The minimum number of bytes to read is 10 in the case of
740 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
741 m_packetLenght = 10;
742 ProxyRead(*m_proxyClientSocket, m_buffer);
744 AddDummyEvent();
747 void CSocks5StateMachine::process_process_command_reply(bool entry)
749 if (entry) {
750 m_lastReply = m_buffer[1];
751 unsigned char addressType = m_buffer[3];
752 // Process the server's reply
753 m_ok = m_ok &&
754 m_buffer[0] == SOCKS5_VERSION &&
755 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
756 if (m_ok) {
757 // Read BND.ADDR
758 unsigned int portOffset = 0;
759 switch(addressType) {
760 case SOCKS5_ATYP_IPV4_ADDRESS:
762 const unsigned int addrOffset = 4;
763 portOffset = 8;
764 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
765 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
766 break;
768 case SOCKS5_ATYP_DOMAINNAME:
770 // Read the domain name
771 const unsigned int addrOffset = 5;
772 portOffset = 10 + m_buffer[4];
773 char c = m_buffer[portOffset];
774 m_buffer[portOffset] = 0;
775 m_proxyBoundAddressIPV4.Hostname(
776 char2unicode(m_buffer+addrOffset));
777 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
778 m_buffer[portOffset] = c;
779 break;
781 case SOCKS5_ATYP_IPV6_ADDRESS:
783 portOffset = 20;
784 // TODO
785 // IPV6 not yet implemented in wx
786 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
787 // *((uint128 *)(m_buffer+addrOffset)) ));
788 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
789 m_ok = false;
790 break;
793 // Set the packet length at last
794 m_packetLenght = portOffset + 2;
795 // Read BND.PORT
796 m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) ) );
799 AddDummyEvent();
802 //------------------------------------------------------------------------------
803 // CSocks4StateMachine
804 //------------------------------------------------------------------------------
806 CSocks4StateMachine::CSocks4StateMachine(
807 const CProxyData &proxyData,
808 CProxyCommand proxyCommand)
810 CProxyStateMachine(
811 wxString(wxT("Socks4")), SOCKS4_MAX_STATES, proxyData, proxyCommand)
813 m_process_state[0] = &CSocks4StateMachine::process_start;
814 m_state_name[0] = wxT("process_start");
815 m_process_state[1] = &CSocks4StateMachine::process_end;
816 m_state_name[1] = wxT("process_end");
817 m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
818 m_state_name[2] = wxT("process_send_command_request");
819 m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
820 m_state_name[3] = wxT("process_receive_command_reply");
821 m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
822 m_state_name[4] = wxT("process_process_command_reply");
825 void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
827 (this->*m_process_state[state])(entry);
828 #ifdef __DEBUG__
829 int n = 0;
831 switch (state) {
832 case SOCKS4_STATE_START:
833 case SOCKS4_STATE_END:
834 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
835 default:
836 n = 0;
837 break;
839 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
840 n = m_packetLenght;
841 break;
843 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
844 n = m_lastRead;
845 break;
848 if (entry) {
849 DumpMem(m_buffer, n, m_state_name[state], m_ok);
850 } else {
851 AddDebugLogLineN(logProxy,
852 wxString(wxT("wait state -- ")) << m_state_name[state]);
854 #endif // __DEBUG__
857 t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
859 // Default is stay in current state
860 t_sm_state ret = HandleEvent(event);
861 switch (GetState()) {
862 case SOCKS4_STATE_START:
863 if (m_isConnected && !m_isLost && CanSend()) {
864 ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
866 break;
868 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
869 if (m_ok) {
870 if (CanReceive()) {
871 ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
873 } else {
874 ret = SOCKS4_STATE_END;
876 break;
878 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
879 ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
880 break;
882 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
883 ret = SOCKS4_STATE_END;
884 break;
886 case SOCKS4_STATE_END:
887 default:
888 break;
891 return ret;
894 void CSocks4StateMachine::process_start(bool)
897 void CSocks4StateMachine::process_end(bool)
899 ReactivateSocket();
902 void CSocks4StateMachine::process_send_command_request(bool entry)
904 if (entry) {
905 // Prepare the request command buffer
906 m_buffer[0] = SOCKS4_VERSION;
907 switch (m_proxyCommand) {
908 case PROXY_CMD_CONNECT:
909 m_buffer[1] = SOCKS4_CMD_CONNECT;
910 break;
912 case PROXY_CMD_BIND:
913 m_buffer[1] = SOCKS4_CMD_BIND;
914 break;
916 case PROXY_CMD_UDP_ASSOCIATE:
917 m_ok = false;
918 return;
919 break;
921 RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
922 // Special processing for SOCKS4a
923 switch (m_proxyData.m_proxyType) {
924 case PROXY_SOCKS4a:
925 PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
926 break;
927 case PROXY_SOCKS4:
928 default:
929 PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
930 break;
932 // Common processing for SOCKS4/SOCKS4a
933 unsigned int offsetUser = 8;
934 unsigned char lenUser = m_proxyData.m_userName.Len();
935 memcpy(m_buffer + offsetUser,
936 unicode2char(m_proxyData.m_userName), lenUser);
937 m_buffer[offsetUser + lenUser] = 0;
938 // Special processing for SOCKS4a
939 switch (m_proxyData.m_proxyType) {
940 case PROXY_SOCKS4a: {
941 unsigned int offsetDomain = offsetUser + lenUser + 1;
942 // The Hostname() method was used here before, but I don't see why we can't use
943 // the IP address which we actually know instead here.
944 wxString hostname(m_peerAddress->IPAddress());
945 unsigned char lenDomain = hostname.Len();
946 memcpy(m_buffer + offsetDomain,
947 unicode2char(hostname), lenDomain);
948 m_buffer[offsetDomain + lenDomain] = 0;
949 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
950 break;
952 case PROXY_SOCKS4:
953 default:
954 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
955 break;
957 // Send the command packet
958 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
962 void CSocks4StateMachine::process_receive_command_reply(bool entry)
964 if (entry) {
965 // Receive the server's reply
966 m_packetLenght = 8;
967 ProxyRead(*m_proxyClientSocket, m_buffer);
969 AddDummyEvent();
972 void CSocks4StateMachine::process_process_command_reply(bool entry)
974 if (entry) {
975 m_lastReply = m_buffer[1];
977 // Process the server's reply
978 m_ok = m_ok &&
979 m_buffer[0] == SOCKS4_REPLY_CODE &&
980 m_buffer[1] == SOCKS4_REPLY_GRANTED;
981 if (m_ok) {
982 // Read BND.PORT
983 const unsigned int portOffset = 2;
984 m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(
985 RawPeekUInt16( m_buffer+portOffset) ) );
986 // Read BND.ADDR
987 const unsigned int addrOffset = 4;
988 m_ok = m_ok &&
989 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
990 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
993 AddDummyEvent();
996 //------------------------------------------------------------------------------
997 // CHttpStateMachine
998 //------------------------------------------------------------------------------
1000 CHttpStateMachine::CHttpStateMachine(
1001 const CProxyData &proxyData,
1002 CProxyCommand proxyCommand)
1004 CProxyStateMachine(
1005 wxString(wxT("Http")), HTTP_MAX_STATES, proxyData, proxyCommand)
1007 m_process_state[0] = &CHttpStateMachine::process_start;
1008 m_state_name[0] = wxT("process_start");
1009 m_process_state[1] = &CHttpStateMachine::process_end;
1010 m_state_name[1] = wxT("process_end");
1011 m_process_state[2] = &CHttpStateMachine::process_send_command_request;
1012 m_state_name[2] = wxT("process_send_command_request");
1013 m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
1014 m_state_name[3] = wxT("process_receive_command_reply");
1015 m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
1016 m_state_name[4] = wxT("process_process_command_reply");
1019 void CHttpStateMachine::process_state(t_sm_state state, bool entry)
1021 (this->*m_process_state[state])(entry);
1022 #ifdef __DEBUG__
1023 int n = 0;
1025 switch (state) {
1026 case HTTP_STATE_START:
1027 case HTTP_STATE_END:
1028 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1029 default:
1030 n = 0;
1031 break;
1033 case HTTP_STATE_SEND_COMMAND_REQUEST:
1034 n = m_packetLenght;
1035 break;
1037 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1038 n = m_lastRead;
1039 break;
1042 if (entry) {
1043 DumpMem(m_buffer, n, m_state_name[state], m_ok);
1044 } else {
1045 AddDebugLogLineN(logProxy,
1046 wxString(wxT("wait state -- ")) << m_state_name[state]);
1048 #endif // __DEBUG__
1051 t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1053 // Default is stay in current state
1054 t_sm_state ret = HandleEvent(event);
1055 switch (GetState()) {
1056 case HTTP_STATE_START:
1057 if (m_isConnected && !m_isLost && CanSend()) {
1058 ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1060 break;
1062 case HTTP_STATE_SEND_COMMAND_REQUEST:
1063 if (m_ok) {
1064 if (CanReceive()) {
1065 ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1067 } else {
1068 ret = HTTP_STATE_END;
1070 break;
1072 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1073 ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1074 break;
1076 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1077 ret = HTTP_STATE_END;
1078 break;
1080 case HTTP_STATE_END:
1081 default:
1082 break;
1085 return ret;
1088 void CHttpStateMachine::process_start(bool)
1091 void CHttpStateMachine::process_end(bool)
1093 ReactivateSocket();
1096 void CHttpStateMachine::process_send_command_request(bool entry)
1098 if (entry) {
1099 // Prepare the request command buffer
1100 wxString ip = m_peerAddress->IPAddress();
1101 uint16 port = m_peerAddress->Service();
1102 wxString userPass;
1103 wxString userPassEncoded;
1104 if (m_proxyData.m_enablePassword) {
1105 userPass = m_proxyData.m_userName + wxT(":") + m_proxyData.m_password;
1106 userPassEncoded =
1107 EncodeBase64(unicode2char(userPass), userPass.Length());
1109 wxString msg;
1111 switch (m_proxyCommand) {
1112 case PROXY_CMD_CONNECT:
1113 msg <<
1114 wxT("CONNECT ") << ip << wxT(":") << port << wxT(" HTTP/1.1\r\n") <<
1115 wxT("Host: ") << ip << wxT(":") << port << wxT("\r\n");
1116 if (m_proxyData.m_enablePassword) {
1117 msg <<
1118 wxT("Authorization: Basic ") << userPassEncoded << wxT("\r\n") <<
1119 wxT("Proxy-Authorization: Basic ") << userPassEncoded << wxT("\r\n");
1121 msg << wxT("\r\n");
1122 break;
1124 case PROXY_CMD_BIND:
1125 m_ok = false;
1126 break;
1128 case PROXY_CMD_UDP_ASSOCIATE:
1129 m_ok = false;
1130 return;
1131 break;
1133 // Send the command packet
1134 m_packetLenght = msg.Len();
1135 memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1136 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1140 void CHttpStateMachine::process_receive_command_reply(bool entry)
1142 if (entry) {
1143 // Receive the server's reply -- Use a large number, but don't
1144 // Expect to get it all. HTTP protocol does not have a fixed length.
1145 m_packetLenght = PROXY_BUFFER_SIZE;
1146 ProxyRead(*m_proxyClientSocket, m_buffer);
1148 AddDummyEvent();
1152 * HTTP Proxy server response should be something like:
1153 * "HTTP/1.1 200 Connection established\r\n\r\n"
1154 * but that may vary. The important thing is the "200"
1155 * code, that means success.
1157 static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1158 static const int HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
1159 void CHttpStateMachine::process_process_command_reply(bool entry)
1161 if (entry) {
1162 // The position of the first space in the buffer
1163 int i = 8;
1164 while (m_buffer[i] == ' ') {
1165 i++;
1167 // Process the server's reply
1168 m_ok = !memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1169 !memcmp(m_buffer + i, "200", 3);
1171 AddDummyEvent();
1174 //------------------------------------------------------------------------------
1175 // CProxySocket
1176 //------------------------------------------------------------------------------
1178 CProxySocket::CProxySocket(
1179 wxSocketFlags flags,
1180 const CProxyData *proxyData,
1181 CProxyCommand proxyCommand,
1182 CDatagramSocketProxy *udpSocket)
1184 CLibSocket(flags),
1185 m_proxyStateMachine(NULL),
1186 m_udpSocket(udpSocket),
1187 m_socketEventHandler(NULL),
1188 m_socketEventHandlerId(0),
1189 m_savedSocketEventHandler(NULL),
1190 m_savedSocketEventHandlerId(0)
1192 SetProxyData(proxyData);
1193 if (m_useProxy) {
1194 switch (m_proxyData.m_proxyType) {
1195 case PROXY_NONE:
1196 break;
1198 case PROXY_SOCKS5:
1199 m_proxyStateMachine =
1200 new CSocks5StateMachine(*proxyData, proxyCommand);
1201 break;
1203 case PROXY_SOCKS4:
1204 case PROXY_SOCKS4a:
1205 m_proxyStateMachine =
1206 new CSocks4StateMachine(*proxyData, proxyCommand);
1207 break;
1209 case PROXY_HTTP:
1210 m_proxyStateMachine =
1211 new CHttpStateMachine(*proxyData, proxyCommand);
1212 break;
1214 default:
1215 break;
1220 CProxySocket::~CProxySocket()
1222 delete m_proxyStateMachine;
1225 void CProxySocket::SetProxyData(const CProxyData *proxyData)
1227 m_useProxy = proxyData != NULL && proxyData->m_proxyEnable;
1228 if (proxyData) {
1229 m_proxyData = *proxyData;
1230 m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1231 m_proxyAddress.Service(m_proxyData.m_proxyPort);
1232 } else {
1233 m_proxyData.Clear();
1237 bool CProxySocket::Start(const amuleIPV4Address &peerAddress)
1239 #ifdef ASIO_SOCKETS
1240 SetProxyState(true, &peerAddress);
1241 #else
1242 SaveState();
1243 // Important note! SaveState()/RestoreState() DO NOT save/restore
1244 // the event handler. The method SaveEventHandler() has been created
1245 // for that.
1246 SaveEventHandler();
1247 SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1248 SetNotify(
1249 wxSOCKET_CONNECTION_FLAG |
1250 wxSOCKET_INPUT_FLAG |
1251 wxSOCKET_OUTPUT_FLAG |
1252 wxSOCKET_LOST_FLAG);
1253 Notify(true);
1254 #endif
1255 Connect(m_proxyAddress, false);
1256 SetFlags(wxSOCKET_NONE);
1257 return m_proxyStateMachine->Start(peerAddress, this);
1260 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1262 bool ret = false;
1264 switch (m_proxyData.m_proxyType) {
1265 case PROXY_NONE:
1266 ret = false;
1267 break;
1269 case PROXY_SOCKS5:
1270 ret = proxyCommand == PROXY_CMD_CONNECT ||
1271 proxyCommand == PROXY_CMD_BIND ||
1272 proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1273 break;
1275 case PROXY_SOCKS4:
1276 case PROXY_SOCKS4a:
1277 ret = proxyCommand == PROXY_CMD_CONNECT ||
1278 proxyCommand == PROXY_CMD_BIND;
1279 break;
1281 case PROXY_HTTP:
1282 ret = proxyCommand == PROXY_CMD_CONNECT;
1283 break;
1286 return ret;
1289 //------------------------------------------------------------------------------
1290 // CSocketClientProxy
1291 //------------------------------------------------------------------------------
1293 CSocketClientProxy::CSocketClientProxy(
1294 wxSocketFlags flags,
1295 const CProxyData *proxyData)
1297 CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1301 bool CSocketClientProxy::Connect(amuleIPV4Address &address, bool wait)
1303 wxMutexLocker lock(m_socketLocker);
1304 bool ok;
1306 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1307 ok = Start(address);
1308 } else {
1309 ok = CLibSocket::Connect(address, wait);
1312 return ok;
1315 uint32 CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1317 wxMutexLocker lock(m_socketLocker);
1318 return CProxySocket::Read(buffer, nbytes);
1321 uint32 CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1323 wxMutexLocker lock(m_socketLocker);
1324 return CProxySocket::Write(buffer, nbytes);
1327 //------------------------------------------------------------------------------
1328 // CSocketServerProxy
1329 //------------------------------------------------------------------------------
1331 CSocketServerProxy::CSocketServerProxy(
1332 amuleIPV4Address &address,
1333 wxSocketFlags flags,
1334 const CProxyData *)
1336 CLibSocketServer(address, flags)
1338 /* Maybe some day when socks6 is out... :) */
1341 //------------------------------------------------------------------------------
1342 // CDatagramSocketProxy
1343 //------------------------------------------------------------------------------
1345 CDatagramSocketProxy::CDatagramSocketProxy(
1346 amuleIPV4Address &address, wxSocketFlags flags, const CProxyData *proxyData)
1348 CLibUDPSocket(address, flags),
1349 m_proxyTCPSocket(wxSOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1351 m_udpSocketOk = false;
1352 if ( m_proxyTCPSocket.GetUseProxy() &&
1353 m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1354 m_proxyTCPSocket.Start(address);
1355 } else {
1357 m_lastUDPOperation = UDP_OPERATION_NONE;
1360 CDatagramSocketProxy::~CDatagramSocketProxy()
1362 // From RFC-1928:
1363 // "A UDP association terminates when the TCP connection that the
1364 // UDP ASSOCIATE request arrived terminates."
1367 uint32 CDatagramSocketProxy::RecvFrom(amuleIPV4Address& addr, void* buf, uint32 nBytes)
1369 uint32 read = 0;
1370 wxMutexLocker lock(m_socketLocker);
1371 m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1372 if (m_proxyTCPSocket.GetUseProxy()) {
1373 if (m_udpSocketOk) {
1374 char *bufUDP = NULL;
1375 if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1376 bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1377 } else {
1378 bufUDP = m_proxyTCPSocket.GetBuffer();
1380 read = CLibUDPSocket::RecvFrom(
1381 m_proxyTCPSocket.GetProxyBoundAddress(),
1382 bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1383 unsigned int offset;
1384 switch (m_proxyTCPSocket.GetBuffer()[3]) {
1385 case SOCKS5_ATYP_IPV4_ADDRESS: {
1386 offset = PROXY_UDP_OVERHEAD_IPV4;
1387 try {
1388 amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1389 a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1390 a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) ) );
1391 } catch (const std::bad_cast& WXUNUSED(e)) {
1392 AddDebugLogLineN(logProxy,
1393 wxT("(2)bad_cast exception!"));
1394 wxFAIL;
1397 break;
1399 case SOCKS5_ATYP_DOMAINNAME:
1400 offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1401 break;
1403 case SOCKS5_ATYP_IPV6_ADDRESS:
1404 offset = PROXY_UDP_OVERHEAD_IPV6;
1405 break;
1407 default:
1408 /* Error! */
1409 offset = 0;
1410 break;
1412 memcpy(buf, bufUDP + offset, nBytes);
1413 // Uncomment here to see the buffer contents on console
1414 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1416 /* Only delete buffer if it was dynamically created */
1417 if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1418 /* We should use a fixed buffer to avoid
1419 * new/delete it all the time.
1420 * I need an upper bound */
1421 delete [] bufUDP;
1423 /* There is still one problem pending, fragmentation.
1424 * Either we support it or we have to drop fragmented
1425 * messages. I vote for drop :)
1428 } else {
1429 read = CLibUDPSocket::RecvFrom(addr, buf, nBytes);
1432 return read;
1435 uint32 CDatagramSocketProxy::SendTo(const amuleIPV4Address& addr, const void* buf, uint32 nBytes)
1437 uint32 sent = 0;
1438 wxMutexLocker lock(m_socketLocker);
1439 m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1440 m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1441 if (m_proxyTCPSocket.GetUseProxy()) {
1442 if (m_udpSocketOk) {
1443 m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV; // Reserved
1444 m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV; // Reserved
1445 m_proxyTCPSocket.GetBuffer()[2] = 0; // FRAG
1446 m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1447 PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1448 RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
1449 memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1450 nBytes += PROXY_UDP_OVERHEAD_IPV4;
1451 sent = CLibUDPSocket::SendTo(
1452 m_proxyTCPSocket.GetProxyBoundAddress(),
1453 m_proxyTCPSocket.GetBuffer(), nBytes);
1454 // Uncomment here to see the buffer contents on console
1455 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1457 } else {
1458 sent = CLibUDPSocket::SendTo(addr, buf, nBytes);
1461 return sent;
1464 #endif // CLIENT_GUI
1466 /******************************************************************************/
1467 // File_checked_for_headers