Generalize naming of some constants
[amule.git] / src / Proxy.cpp
blob04848729d7da0a4c717620275279dfa49db1dc54
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 MULE_SOCKET_DUMMY_VALUE = MULE_SOCKET_INPUT + MULE_SOCKET_OUTPUT + MULE_SOCKET_CONNECTION + MULE_SOCKET_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 MULE_SOCKET_CONNECTION:
204 AddDebugLogLineN(logProxy, wxT("Connection event"));
205 m_isConnected = true;
206 break;
208 case MULE_SOCKET_INPUT:
209 AddDebugLogLineN(logProxy, wxT("Input event"));
210 m_canReceive = true;
211 break;
213 case MULE_SOCKET_OUTPUT:
214 AddDebugLogLineN(logProxy, wxT("Output event"));
215 m_canSend = true;
216 break;
218 case MULE_SOCKET_LOST:
219 AddDebugLogLineN(logProxy, wxT("Lost connection event"));
220 m_isLost = true;
221 m_ok = false;
222 break;
224 case MULE_SOCKET_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 // - MULE_SOCKET_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, MULE_SOCKET_DUMMY_VALUE);
251 #else
252 wxSocketEvent e(ID_PROXY_SOCKET_EVENT);
253 // Make sure this is an unknown event :)
254 e.m_event = (wxSocketNotify)(MULE_SOCKET_DUMMY_VALUE);
255 e.SetEventObject(m_proxyClientSocket);
256 g_proxyEventHandler.AddPendingEvent(e);
257 #endif
260 void CProxyStateMachine::ReactivateSocket()
262 /* If proxy is beeing used, then the TCP socket handlers
263 * (CServerSocketHandler and CClientTCPSocketHandler) will not
264 * receive a wxSOCKET_CONNECTION event, because the connection has
265 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
266 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
267 * necessary to start sending data to the server. */
268 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
269 // If that is not true, we are in serious trouble...
270 wxASSERT(s);
271 if (CDatagramSocketProxy *udp = s->GetUDPSocket()) {
272 // The original socket was a UDP socket
273 if(m_ok) {
274 // From now on, the UDP socket can be used,
275 // remove the protection.
276 udp->SetUDPSocketOk();
278 // No need to call RestoreState(), that socket will no longer
279 // be used after proxy negotiation.
280 } else {
281 // The original socket was a TCP socket
282 #ifdef ASIO_SOCKETS
283 if (s->GetProxyState()) { // somehow this gets called twice ?
284 s->SetProxyState(false);
285 CoreNotify_LibSocketConnect(s, 0);
286 if (m_ok) {
287 CoreNotify_LibSocketSend(s, 0);
288 } else {
289 CoreNotify_LibSocketLost(s);
292 #else
293 s->RestoreEventHandler();
294 wxSocketEvent e(s->GetEventHandlerId());
295 e.m_event = wxSOCKET_CONNECTION;
296 e.SetEventObject(s);
297 wxEvtHandler *h(s->GetEventHandler());
298 h->AddPendingEvent(e);
299 e.m_event = wxSOCKET_OUTPUT;
300 h->AddPendingEvent(e);
301 if (!m_ok) {
302 e.m_event = wxSOCKET_LOST;
303 h->AddPendingEvent(e);
305 s->RestoreState();
306 #endif
310 uint32 CProxyStateMachine::ProxyWrite(CLibSocket &socket, const void *buffer, wxUint32 nbytes)
312 uint32 written = socket.Write(buffer, nbytes);
313 /* Set the status of this operation */
314 m_ok = true;
315 if (m_proxyClientSocket->BlocksWrite()) {
316 m_lastError = 0;
317 m_canSend = false;
318 } else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
319 m_ok = false;
321 AddDebugLogLineN(logProxy, CFormat(wxT("ProxyWrite %d %d ok %d cansend %d")) % nbytes % written % m_ok % m_canSend);
323 return written;
326 uint32 CProxyStateMachine::ProxyRead(CLibSocket &socket, void *buffer)
328 /* Always try to read the full buffer. That explicitly demands that
329 * the socket has the flag wxSOCKET_NONE. */
330 m_lastRead = socket.Read(buffer, PROXY_BUFFER_SIZE);
331 /* Set the status of this operation */
332 m_ok = true;
333 if (m_proxyClientSocket->BlocksRead()) {
334 m_lastError = 0;
335 m_canReceive = false;
336 } else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
337 m_ok = false;
339 #ifdef ASIO_SOCKETS
340 // We will get a new event right away if data is left, or when new data gets available.
341 // So block for now.
342 m_canReceive = false;
343 #endif
344 AddDebugLogLineN(logProxy, CFormat(wxT("ProxyRead %d ok %d canrec %d")) % m_lastRead % m_ok % m_canReceive);
346 return m_lastRead;
349 bool CProxyStateMachine::CanReceive() const
351 return m_canReceive;
354 bool CProxyStateMachine::CanSend() const
356 return m_canSend;
359 //------------------------------------------------------------------------------
360 // CSocks5StateMachine
361 //------------------------------------------------------------------------------
364 * The state machine constructor must initialize the array of pointer to member
365 * functions. Don't waste you time trying to statically initialize this, pointer
366 * to member functions require an object to operate on, so this array must be
367 * initialized at run time.
369 CSocks5StateMachine::CSocks5StateMachine(
370 const CProxyData &proxyData,
371 CProxyCommand proxyCommand)
373 CProxyStateMachine(
374 wxString(wxT("Socks5")), SOCKS5_MAX_STATES, proxyData, proxyCommand)
376 m_process_state[ 0] = &CSocks5StateMachine::process_start;
377 m_state_name[ 0] = wxT("process_start");
378 m_process_state[ 1] = &CSocks5StateMachine::process_end;
379 m_state_name[ 1] = wxT("process_end");
380 m_process_state[ 2] = &CSocks5StateMachine::process_send_query_authentication_method;
381 m_state_name[ 2] = wxT("process_send_query_authentication_method");
382 m_process_state[ 3] = &CSocks5StateMachine::process_receive_authentication_method;
383 m_state_name[ 3] = wxT("process_receive_authentication_method");
384 m_process_state[ 4] = &CSocks5StateMachine::process_process_authentication_method;
385 m_state_name[ 4] = wxT("process_process_authentication_method");
386 m_process_state[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi;
387 m_state_name[ 5] = wxT("process_send_authentication_gssapi");
388 m_process_state[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi;
389 m_state_name[ 6] = wxT("process_receive_authentication_gssapi");
390 m_process_state[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi;
391 m_state_name[ 7] = wxT("process_process_authentication_gssapi");
392 m_process_state[ 8] = &CSocks5StateMachine::process_send_authentication_username_password;
393 m_state_name[ 8] = wxT("process_send_authentication_username_password");
394 m_process_state[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password;
395 m_state_name[ 9] = wxT("process_receive_authentication_username_password");
396 m_process_state[10] = &CSocks5StateMachine::process_process_authentication_username_password;
397 m_state_name[10] = wxT("process_process_authentication_username_password");
398 m_process_state[11] = &CSocks5StateMachine::process_send_command_request;
399 m_state_name[11] = wxT("process_send_command_request");
400 m_process_state[12] = &CSocks5StateMachine::process_receive_command_reply;
401 m_state_name[12] = wxT("process_receive_command_reply");
402 m_process_state[13] = &CSocks5StateMachine::process_process_command_reply;
403 m_state_name[13] = wxT("process_process_command_reply");
406 void CSocks5StateMachine::process_state(t_sm_state state, bool entry)
408 /* Ok, the syntax is terrible, but this is correct. This is a
409 * pointer to a member function. No C equivalent for that. */
410 (this->*m_process_state[state])(entry);
411 #ifdef __DEBUG__
412 int n = 0;
414 switch (state) {
415 case SOCKS5_STATE_START:
416 case SOCKS5_STATE_END:
417 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
418 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
419 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
420 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
421 default:
422 n = 0;
423 break;
425 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
426 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
427 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
428 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
429 n = m_packetLenght;
430 break;
432 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
433 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
434 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
435 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
436 n = m_lastRead;
437 break;
440 if (entry) {
441 DumpMem(m_buffer, n, m_state_name[state], m_ok);
442 } else {
443 AddDebugLogLineN(logProxy,
444 wxString(wxT("wait state -- ")) << m_state_name[state]);
446 #endif // __DEBUG__
450 * Code this such that the next state is only entered when it is able to
451 * perform the operation (read or write). State processing will assume
452 * that it can read or write upon entry of the state. This is done using
453 * CanSend() and CanReceive().
455 t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
457 // Default is stay in current state
458 t_sm_state ret = HandleEvent(event);
459 switch (GetState()) {
460 case SOCKS5_STATE_START:
461 if (m_isConnected && !m_isLost && CanSend()) {
462 ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
464 break;
466 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
467 if (CanReceive()) {
468 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
470 break;
472 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
473 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
474 break;
476 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
477 if (m_ok) {
478 if (CanSend()) {
479 switch (m_lastReply) {
480 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
481 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
482 break;
484 case SOCKS5_AUTH_METHOD_GSSAPI:
485 ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
486 break;
488 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
489 ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
490 break;
492 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
493 default:
494 ret = SOCKS5_STATE_END;
495 break;
497 } else {
498 AddDebugLogLineN(logProxy, wxT("Can't send"));
500 } else {
501 ret = SOCKS5_STATE_END;
503 break;
505 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
506 if (m_ok) {
507 if (CanReceive()) {
508 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
510 } else {
511 ret = SOCKS5_STATE_END;
513 break;
515 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
516 if (m_ok) {
517 if (CanReceive()) {
518 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
520 } else {
521 ret = SOCKS5_STATE_END;
523 break;
525 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
526 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
527 break;
529 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
530 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
531 break;
533 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
534 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
535 if (m_ok) {
536 if (CanSend()) {
537 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
539 } else {
540 ret = SOCKS5_STATE_END;
542 break;
544 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
545 if (m_ok) {
546 if (CanReceive()) {
547 ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
549 } else {
550 ret = SOCKS5_STATE_END;
552 break;
554 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
555 ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
556 break;
558 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
559 ret = SOCKS5_STATE_END;
560 break;
562 case SOCKS5_STATE_END:
563 default:
564 break;
567 return ret;
571 * So, this is how you do it: the state machine is clocked by the events
572 * that happen inside the event handler. You can add a dummy event whenever
573 * you see that the system will not generate an event. But don't add dummy
574 * events before reads, reads should only be performed after input events.
576 * Maybe it makes sense to add a dummy event before a read if there is no
577 * state change (wait state).
579 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
580 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
581 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
582 * event will be generated. If you feel you will need more clocks than these, use
583 * AddDummyEvent(), but I suggest you review your state machine design first.
585 void CSocks5StateMachine::process_start(bool)
588 void CSocks5StateMachine::process_end(bool)
590 ReactivateSocket();
593 void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
595 if (entry) {
596 // Prepare the authentication method negotiation packet
597 m_buffer[0] = SOCKS5_VERSION;
598 m_buffer[1] = 2; // Number of supported methods
599 //m_buffer[1] = 3; // Number of supported methods
600 m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
601 m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
602 m_buffer[4] = SOCKS5_AUTH_METHOD_GSSAPI;
603 m_packetLenght = 4;
604 //m_packetLenght = 5;
606 // Send the authentication method negotiation packet
607 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
611 void CSocks5StateMachine::process_receive_authentication_method(bool entry)
613 if (entry) {
614 // Receive the method selection message
615 m_packetLenght = 2;
616 ProxyRead(*m_proxyClientSocket, m_buffer);
618 /* This is added because there will be no more input events. If the
619 * world was a nice place, we could think about joining the
620 * process_receive and the process_process states here, but some day
621 * we might have to deal with the fact that the i/o operation has been
622 * incomplete, and that we must finish our job the next time we enter
623 * this state. */
624 AddDummyEvent();
627 void CSocks5StateMachine::process_process_authentication_method(bool entry)
629 if (entry) {
630 m_lastReply = m_buffer[1];
631 m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
633 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
634 * once when you connect the socket, and after that, only after a
635 * wxSOCKET_WOULDBLOCK error happens. */
636 AddDummyEvent();
639 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
641 // TODO or not TODO? That is the question...
642 m_ok = false;
645 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
647 AddDummyEvent();
650 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
652 AddDummyEvent();
655 void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
657 if (entry) {
658 unsigned char lenUser = m_proxyData.m_userName.Len();
659 unsigned char lenPassword = m_proxyData.m_password.Len();
660 m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
661 unsigned int offsetUser = 2;
662 unsigned int offsetPassword = offsetUser + lenUser + 1;
664 // Prepare username/password buffer
665 m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
666 m_buffer[offsetUser-1] = lenUser;
667 memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
668 lenUser);
669 m_buffer[offsetPassword-1] = lenPassword;
670 memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
671 lenPassword);
673 // Send the username/password packet
674 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
678 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
680 if (entry) {
681 // Receive the server's authentication response
682 m_packetLenght = 2;
683 ProxyRead(*m_proxyClientSocket, m_buffer);
685 AddDummyEvent();
688 void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
690 if (entry) {
691 // Process the server's reply
692 m_lastReply = m_buffer[1];
693 m_ok = m_ok &&
694 m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
695 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
697 AddDummyEvent();
700 void CSocks5StateMachine::process_send_command_request(bool entry)
702 if (entry) {
703 // Prepare the request command buffer
704 m_buffer[0] = SOCKS5_VERSION;
705 switch (m_proxyCommand) {
706 case PROXY_CMD_CONNECT:
707 m_buffer[1] = SOCKS5_CMD_CONNECT;
708 break;
710 case PROXY_CMD_BIND:
711 m_buffer[1] = SOCKS5_CMD_BIND;
712 break;
714 case PROXY_CMD_UDP_ASSOCIATE:
715 m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
716 break;
718 m_buffer[2] = SOCKS5_RSV;
719 m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
720 PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
721 RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
723 // Send the command packet
724 m_packetLenght = 10;
725 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
729 void CSocks5StateMachine::process_receive_command_reply(bool entry)
731 if (entry) {
732 // The minimum number of bytes to read is 10 in the case of
733 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
734 m_packetLenght = 10;
735 ProxyRead(*m_proxyClientSocket, m_buffer);
737 AddDummyEvent();
740 void CSocks5StateMachine::process_process_command_reply(bool entry)
742 if (entry) {
743 m_lastReply = m_buffer[1];
744 unsigned char addressType = m_buffer[3];
745 // Process the server's reply
746 m_ok = m_ok &&
747 m_buffer[0] == SOCKS5_VERSION &&
748 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
749 if (m_ok) {
750 // Read BND.ADDR
751 unsigned int portOffset = 0;
752 switch(addressType) {
753 case SOCKS5_ATYP_IPV4_ADDRESS:
755 const unsigned int addrOffset = 4;
756 portOffset = 8;
757 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
758 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
759 break;
761 case SOCKS5_ATYP_DOMAINNAME:
763 // Read the domain name
764 const unsigned int addrOffset = 5;
765 portOffset = 10 + m_buffer[4];
766 char c = m_buffer[portOffset];
767 m_buffer[portOffset] = 0;
768 m_proxyBoundAddressIPV4.Hostname(
769 char2unicode(m_buffer+addrOffset));
770 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
771 m_buffer[portOffset] = c;
772 break;
774 case SOCKS5_ATYP_IPV6_ADDRESS:
776 portOffset = 20;
777 // TODO
778 // IPV6 not yet implemented in wx
779 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
780 // *((uint128 *)(m_buffer+addrOffset)) ));
781 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
782 m_ok = false;
783 break;
786 // Set the packet length at last
787 m_packetLenght = portOffset + 2;
788 // Read BND.PORT
789 m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) ) );
792 AddDummyEvent();
795 //------------------------------------------------------------------------------
796 // CSocks4StateMachine
797 //------------------------------------------------------------------------------
799 CSocks4StateMachine::CSocks4StateMachine(
800 const CProxyData &proxyData,
801 CProxyCommand proxyCommand)
803 CProxyStateMachine(
804 wxString(wxT("Socks4")), SOCKS4_MAX_STATES, proxyData, proxyCommand)
806 m_process_state[0] = &CSocks4StateMachine::process_start;
807 m_state_name[0] = wxT("process_start");
808 m_process_state[1] = &CSocks4StateMachine::process_end;
809 m_state_name[1] = wxT("process_end");
810 m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
811 m_state_name[2] = wxT("process_send_command_request");
812 m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
813 m_state_name[3] = wxT("process_receive_command_reply");
814 m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
815 m_state_name[4] = wxT("process_process_command_reply");
818 void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
820 (this->*m_process_state[state])(entry);
821 #ifdef __DEBUG__
822 int n = 0;
824 switch (state) {
825 case SOCKS4_STATE_START:
826 case SOCKS4_STATE_END:
827 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
828 default:
829 n = 0;
830 break;
832 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
833 n = m_packetLenght;
834 break;
836 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
837 n = m_lastRead;
838 break;
841 if (entry) {
842 DumpMem(m_buffer, n, m_state_name[state], m_ok);
843 } else {
844 AddDebugLogLineN(logProxy,
845 wxString(wxT("wait state -- ")) << m_state_name[state]);
847 #endif // __DEBUG__
850 t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
852 // Default is stay in current state
853 t_sm_state ret = HandleEvent(event);
854 switch (GetState()) {
855 case SOCKS4_STATE_START:
856 if (m_isConnected && !m_isLost && CanSend()) {
857 ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
859 break;
861 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
862 if (m_ok) {
863 if (CanReceive()) {
864 ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
866 } else {
867 ret = SOCKS4_STATE_END;
869 break;
871 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
872 ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
873 break;
875 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
876 ret = SOCKS4_STATE_END;
877 break;
879 case SOCKS4_STATE_END:
880 default:
881 break;
884 return ret;
887 void CSocks4StateMachine::process_start(bool)
890 void CSocks4StateMachine::process_end(bool)
892 ReactivateSocket();
895 void CSocks4StateMachine::process_send_command_request(bool entry)
897 if (entry) {
898 // Prepare the request command buffer
899 m_buffer[0] = SOCKS4_VERSION;
900 switch (m_proxyCommand) {
901 case PROXY_CMD_CONNECT:
902 m_buffer[1] = SOCKS4_CMD_CONNECT;
903 break;
905 case PROXY_CMD_BIND:
906 m_buffer[1] = SOCKS4_CMD_BIND;
907 break;
909 case PROXY_CMD_UDP_ASSOCIATE:
910 m_ok = false;
911 return;
912 break;
914 RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
915 // Special processing for SOCKS4a
916 switch (m_proxyData.m_proxyType) {
917 case PROXY_SOCKS4a:
918 PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
919 break;
920 case PROXY_SOCKS4:
921 default:
922 PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
923 break;
925 // Common processing for SOCKS4/SOCKS4a
926 unsigned int offsetUser = 8;
927 unsigned char lenUser = m_proxyData.m_userName.Len();
928 memcpy(m_buffer + offsetUser,
929 unicode2char(m_proxyData.m_userName), lenUser);
930 m_buffer[offsetUser + lenUser] = 0;
931 // Special processing for SOCKS4a
932 switch (m_proxyData.m_proxyType) {
933 case PROXY_SOCKS4a: {
934 unsigned int offsetDomain = offsetUser + lenUser + 1;
935 // The Hostname() method was used here before, but I don't see why we can't use
936 // the IP address which we actually know instead here.
937 wxString hostname(m_peerAddress->IPAddress());
938 unsigned char lenDomain = hostname.Len();
939 memcpy(m_buffer + offsetDomain,
940 unicode2char(hostname), lenDomain);
941 m_buffer[offsetDomain + lenDomain] = 0;
942 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
943 break;
945 case PROXY_SOCKS4:
946 default:
947 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
948 break;
950 // Send the command packet
951 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
955 void CSocks4StateMachine::process_receive_command_reply(bool entry)
957 if (entry) {
958 // Receive the server's reply
959 m_packetLenght = 8;
960 ProxyRead(*m_proxyClientSocket, m_buffer);
962 AddDummyEvent();
965 void CSocks4StateMachine::process_process_command_reply(bool entry)
967 if (entry) {
968 m_lastReply = m_buffer[1];
970 // Process the server's reply
971 m_ok = m_ok &&
972 m_buffer[0] == SOCKS4_REPLY_CODE &&
973 m_buffer[1] == SOCKS4_REPLY_GRANTED;
974 if (m_ok) {
975 // Read BND.PORT
976 const unsigned int portOffset = 2;
977 m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(
978 RawPeekUInt16( m_buffer+portOffset) ) );
979 // Read BND.ADDR
980 const unsigned int addrOffset = 4;
981 m_ok = m_ok &&
982 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
983 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
986 AddDummyEvent();
989 //------------------------------------------------------------------------------
990 // CHttpStateMachine
991 //------------------------------------------------------------------------------
993 CHttpStateMachine::CHttpStateMachine(
994 const CProxyData &proxyData,
995 CProxyCommand proxyCommand)
997 CProxyStateMachine(
998 wxString(wxT("Http")), HTTP_MAX_STATES, proxyData, proxyCommand)
1000 m_process_state[0] = &CHttpStateMachine::process_start;
1001 m_state_name[0] = wxT("process_start");
1002 m_process_state[1] = &CHttpStateMachine::process_end;
1003 m_state_name[1] = wxT("process_end");
1004 m_process_state[2] = &CHttpStateMachine::process_send_command_request;
1005 m_state_name[2] = wxT("process_send_command_request");
1006 m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
1007 m_state_name[3] = wxT("process_receive_command_reply");
1008 m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
1009 m_state_name[4] = wxT("process_process_command_reply");
1012 void CHttpStateMachine::process_state(t_sm_state state, bool entry)
1014 (this->*m_process_state[state])(entry);
1015 #ifdef __DEBUG__
1016 int n = 0;
1018 switch (state) {
1019 case HTTP_STATE_START:
1020 case HTTP_STATE_END:
1021 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1022 default:
1023 n = 0;
1024 break;
1026 case HTTP_STATE_SEND_COMMAND_REQUEST:
1027 n = m_packetLenght;
1028 break;
1030 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1031 n = m_lastRead;
1032 break;
1035 if (entry) {
1036 DumpMem(m_buffer, n, m_state_name[state], m_ok);
1037 } else {
1038 AddDebugLogLineN(logProxy,
1039 wxString(wxT("wait state -- ")) << m_state_name[state]);
1041 #endif // __DEBUG__
1044 t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1046 // Default is stay in current state
1047 t_sm_state ret = HandleEvent(event);
1048 switch (GetState()) {
1049 case HTTP_STATE_START:
1050 if (m_isConnected && !m_isLost && CanSend()) {
1051 ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1053 break;
1055 case HTTP_STATE_SEND_COMMAND_REQUEST:
1056 if (m_ok) {
1057 if (CanReceive()) {
1058 ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1060 } else {
1061 ret = HTTP_STATE_END;
1063 break;
1065 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1066 ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1067 break;
1069 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1070 ret = HTTP_STATE_END;
1071 break;
1073 case HTTP_STATE_END:
1074 default:
1075 break;
1078 return ret;
1081 void CHttpStateMachine::process_start(bool)
1084 void CHttpStateMachine::process_end(bool)
1086 ReactivateSocket();
1089 void CHttpStateMachine::process_send_command_request(bool entry)
1091 if (entry) {
1092 // Prepare the request command buffer
1093 wxString ip = m_peerAddress->IPAddress();
1094 uint16 port = m_peerAddress->Service();
1095 wxString userPass;
1096 wxString userPassEncoded;
1097 if (m_proxyData.m_enablePassword) {
1098 userPass = m_proxyData.m_userName + wxT(":") + m_proxyData.m_password;
1099 userPassEncoded =
1100 EncodeBase64(unicode2char(userPass), userPass.Length());
1102 wxString msg;
1104 switch (m_proxyCommand) {
1105 case PROXY_CMD_CONNECT:
1106 msg <<
1107 wxT("CONNECT ") << ip << wxT(":") << port << wxT(" HTTP/1.1\r\n") <<
1108 wxT("Host: ") << ip << wxT(":") << port << wxT("\r\n");
1109 if (m_proxyData.m_enablePassword) {
1110 msg <<
1111 wxT("Authorization: Basic ") << userPassEncoded << wxT("\r\n") <<
1112 wxT("Proxy-Authorization: Basic ") << userPassEncoded << wxT("\r\n");
1114 msg << wxT("\r\n");
1115 break;
1117 case PROXY_CMD_BIND:
1118 m_ok = false;
1119 break;
1121 case PROXY_CMD_UDP_ASSOCIATE:
1122 m_ok = false;
1123 return;
1124 break;
1126 // Send the command packet
1127 m_packetLenght = msg.Len();
1128 memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1129 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1133 void CHttpStateMachine::process_receive_command_reply(bool entry)
1135 if (entry) {
1136 // Receive the server's reply -- Use a large number, but don't
1137 // Expect to get it all. HTTP protocol does not have a fixed length.
1138 m_packetLenght = PROXY_BUFFER_SIZE;
1139 ProxyRead(*m_proxyClientSocket, m_buffer);
1141 AddDummyEvent();
1145 * HTTP Proxy server response should be something like:
1146 * "HTTP/1.1 200 Connection established\r\n\r\n"
1147 * but that may vary. The important thing is the "200"
1148 * code, that means success.
1150 static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1151 static const int HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
1152 void CHttpStateMachine::process_process_command_reply(bool entry)
1154 if (entry) {
1155 // The position of the first space in the buffer
1156 int i = 8;
1157 while (m_buffer[i] == ' ') {
1158 i++;
1160 // Process the server's reply
1161 m_ok = !memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1162 !memcmp(m_buffer + i, "200", 3);
1164 AddDummyEvent();
1167 //------------------------------------------------------------------------------
1168 // CProxySocket
1169 //------------------------------------------------------------------------------
1171 CProxySocket::CProxySocket(
1172 muleSocketFlags flags,
1173 const CProxyData *proxyData,
1174 CProxyCommand proxyCommand,
1175 CDatagramSocketProxy *udpSocket)
1177 CLibSocket(flags),
1178 m_proxyStateMachine(NULL),
1179 m_udpSocket(udpSocket),
1180 m_socketEventHandler(NULL),
1181 m_socketEventHandlerId(0),
1182 m_savedSocketEventHandler(NULL),
1183 m_savedSocketEventHandlerId(0)
1185 SetProxyData(proxyData);
1186 if (m_useProxy) {
1187 switch (m_proxyData.m_proxyType) {
1188 case PROXY_NONE:
1189 break;
1191 case PROXY_SOCKS5:
1192 m_proxyStateMachine =
1193 new CSocks5StateMachine(*proxyData, proxyCommand);
1194 break;
1196 case PROXY_SOCKS4:
1197 case PROXY_SOCKS4a:
1198 m_proxyStateMachine =
1199 new CSocks4StateMachine(*proxyData, proxyCommand);
1200 break;
1202 case PROXY_HTTP:
1203 m_proxyStateMachine =
1204 new CHttpStateMachine(*proxyData, proxyCommand);
1205 break;
1207 default:
1208 break;
1213 CProxySocket::~CProxySocket()
1215 delete m_proxyStateMachine;
1218 void CProxySocket::SetProxyData(const CProxyData *proxyData)
1220 m_useProxy = proxyData != NULL && proxyData->m_proxyEnable;
1221 if (proxyData) {
1222 m_proxyData = *proxyData;
1223 m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1224 m_proxyAddress.Service(m_proxyData.m_proxyPort);
1225 } else {
1226 m_proxyData.Clear();
1230 bool CProxySocket::Start(const amuleIPV4Address &peerAddress)
1232 #ifdef ASIO_SOCKETS
1233 SetProxyState(true, &peerAddress);
1234 #else
1235 SaveState();
1236 // Important note! SaveState()/RestoreState() DO NOT save/restore
1237 // the event handler. The method SaveEventHandler() has been created
1238 // for that.
1239 SaveEventHandler();
1240 SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1241 SetNotify(
1242 wxSOCKET_CONNECTION_FLAG |
1243 wxSOCKET_INPUT_FLAG |
1244 wxSOCKET_OUTPUT_FLAG |
1245 wxSOCKET_LOST_FLAG);
1246 Notify(true);
1247 #endif
1248 Connect(m_proxyAddress, false);
1249 SetFlags(MULE_SOCKET_NONE);
1250 return m_proxyStateMachine->Start(peerAddress, this);
1253 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1255 bool ret = false;
1257 switch (m_proxyData.m_proxyType) {
1258 case PROXY_NONE:
1259 ret = false;
1260 break;
1262 case PROXY_SOCKS5:
1263 ret = proxyCommand == PROXY_CMD_CONNECT ||
1264 proxyCommand == PROXY_CMD_BIND ||
1265 proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1266 break;
1268 case PROXY_SOCKS4:
1269 case PROXY_SOCKS4a:
1270 ret = proxyCommand == PROXY_CMD_CONNECT ||
1271 proxyCommand == PROXY_CMD_BIND;
1272 break;
1274 case PROXY_HTTP:
1275 ret = proxyCommand == PROXY_CMD_CONNECT;
1276 break;
1279 return ret;
1282 //------------------------------------------------------------------------------
1283 // CSocketClientProxy
1284 //------------------------------------------------------------------------------
1286 CSocketClientProxy::CSocketClientProxy(
1287 muleSocketFlags flags,
1288 const CProxyData *proxyData)
1290 CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1294 bool CSocketClientProxy::Connect(amuleIPV4Address &address, bool wait)
1296 wxMutexLocker lock(m_socketLocker);
1297 bool ok;
1299 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1300 ok = Start(address);
1301 } else {
1302 ok = CLibSocket::Connect(address, wait);
1305 return ok;
1308 uint32 CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1310 wxMutexLocker lock(m_socketLocker);
1311 return CProxySocket::Read(buffer, nbytes);
1314 uint32 CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1316 wxMutexLocker lock(m_socketLocker);
1317 return CProxySocket::Write(buffer, nbytes);
1320 //------------------------------------------------------------------------------
1321 // CSocketServerProxy
1322 //------------------------------------------------------------------------------
1324 CSocketServerProxy::CSocketServerProxy(
1325 amuleIPV4Address &address,
1326 muleSocketFlags flags,
1327 const CProxyData *)
1329 CLibSocketServer(address, flags)
1331 /* Maybe some day when socks6 is out... :) */
1334 //------------------------------------------------------------------------------
1335 // CDatagramSocketProxy
1336 //------------------------------------------------------------------------------
1338 CDatagramSocketProxy::CDatagramSocketProxy(
1339 amuleIPV4Address &address, muleSocketFlags flags, const CProxyData *proxyData)
1341 CLibUDPSocket(address, flags),
1342 m_proxyTCPSocket(MULE_SOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1344 m_udpSocketOk = false;
1345 if ( m_proxyTCPSocket.GetUseProxy() &&
1346 m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1347 m_proxyTCPSocket.Start(address);
1348 } else {
1350 m_lastUDPOperation = UDP_OPERATION_NONE;
1353 CDatagramSocketProxy::~CDatagramSocketProxy()
1355 // From RFC-1928:
1356 // "A UDP association terminates when the TCP connection that the
1357 // UDP ASSOCIATE request arrived terminates."
1360 uint32 CDatagramSocketProxy::RecvFrom(amuleIPV4Address& addr, void* buf, uint32 nBytes)
1362 uint32 read = 0;
1363 wxMutexLocker lock(m_socketLocker);
1364 m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1365 if (m_proxyTCPSocket.GetUseProxy()) {
1366 if (m_udpSocketOk) {
1367 char *bufUDP = NULL;
1368 if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1369 bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1370 } else {
1371 bufUDP = m_proxyTCPSocket.GetBuffer();
1373 read = CLibUDPSocket::RecvFrom(
1374 m_proxyTCPSocket.GetProxyBoundAddress(),
1375 bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1376 unsigned int offset;
1377 switch (m_proxyTCPSocket.GetBuffer()[3]) {
1378 case SOCKS5_ATYP_IPV4_ADDRESS: {
1379 offset = PROXY_UDP_OVERHEAD_IPV4;
1380 try {
1381 amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1382 a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1383 a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) ) );
1384 } catch (const std::bad_cast& WXUNUSED(e)) {
1385 AddDebugLogLineN(logProxy,
1386 wxT("(2)bad_cast exception!"));
1387 wxFAIL;
1390 break;
1392 case SOCKS5_ATYP_DOMAINNAME:
1393 offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1394 break;
1396 case SOCKS5_ATYP_IPV6_ADDRESS:
1397 offset = PROXY_UDP_OVERHEAD_IPV6;
1398 break;
1400 default:
1401 /* Error! */
1402 offset = 0;
1403 break;
1405 memcpy(buf, bufUDP + offset, nBytes);
1406 // Uncomment here to see the buffer contents on console
1407 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1409 /* Only delete buffer if it was dynamically created */
1410 if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1411 /* We should use a fixed buffer to avoid
1412 * new/delete it all the time.
1413 * I need an upper bound */
1414 delete [] bufUDP;
1416 /* There is still one problem pending, fragmentation.
1417 * Either we support it or we have to drop fragmented
1418 * messages. I vote for drop :)
1421 } else {
1422 read = CLibUDPSocket::RecvFrom(addr, buf, nBytes);
1425 return read;
1428 uint32 CDatagramSocketProxy::SendTo(const amuleIPV4Address& addr, const void* buf, uint32 nBytes)
1430 uint32 sent = 0;
1431 wxMutexLocker lock(m_socketLocker);
1432 m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1433 m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1434 if (m_proxyTCPSocket.GetUseProxy()) {
1435 if (m_udpSocketOk) {
1436 m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV; // Reserved
1437 m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV; // Reserved
1438 m_proxyTCPSocket.GetBuffer()[2] = 0; // FRAG
1439 m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1440 PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1441 RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
1442 memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1443 nBytes += PROXY_UDP_OVERHEAD_IPV4;
1444 sent = CLibUDPSocket::SendTo(
1445 m_proxyTCPSocket.GetProxyBoundAddress(),
1446 m_proxyTCPSocket.GetBuffer(), nBytes);
1447 // Uncomment here to see the buffer contents on console
1448 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1450 } else {
1451 sent = CLibUDPSocket::SendTo(addr, buf, nBytes);
1454 return sent;
1457 #endif // CLIENT_GUI
1459 /******************************************************************************/
1460 // File_checked_for_headers