Added papirus skin and minor debian fixes
[amule.git] / src / Proxy.cpp
blobcc555b859a195471e7b8a5fedc5623e224a92861
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 #ifndef ASIO_SOCKETS
89 //------------------------------------------------------------------------------
90 // ProxyEventHandler
91 //------------------------------------------------------------------------------
93 CProxyEventHandler::CProxyEventHandler()
97 BEGIN_EVENT_TABLE(CProxyEventHandler, wxEvtHandler)
98 EVT_SOCKET(ID_PROXY_SOCKET_EVENT, CProxyEventHandler::ProxySocketHandler)
99 END_EVENT_TABLE()
102 // THE one and only Event Handler
104 static CProxyEventHandler g_proxyEventHandler;
106 void CProxyEventHandler::ProxySocketHandler(wxSocketEvent& event)
108 CProxySocket *sock = dynamic_cast<CProxySocket *>(event.GetSocket());
109 if (sock) {
110 sock->m_proxyStateMachine->Schedule(event.GetSocketEvent());
111 sock->m_proxyStateMachine->Clock();
112 } else {
113 // we're doomed :)
117 #else
120 // In Asio mode the event handler is:
122 void CProxySocket::OnProxyEvent(int evt)
124 m_proxyStateMachine->Schedule(evt);
125 m_proxyStateMachine->Clock();
128 #endif
130 //------------------------------------------------------------------------------
131 // CProxyStateMachine
132 //------------------------------------------------------------------------------
134 CProxyStateMachine::CProxyStateMachine(
135 wxString name,
136 const unsigned int max_states,
137 const CProxyData &proxyData,
138 CProxyCommand proxyCommand)
140 CStateMachine(NewName(name, proxyCommand), max_states, PROXY_STATE_START),
141 m_proxyData(proxyData),
142 m_proxyCommand(proxyCommand),
143 m_isLost(false),
144 m_isConnected(false),
145 m_canReceive(false),
146 m_canSend(false),
147 m_ok(true),
148 m_lastRead(0),
149 // Will be initialized at Start()
150 m_peerAddress(NULL),
151 m_proxyClientSocket(NULL),
152 m_proxyBoundAddress(NULL),
153 // Temporary variables
154 m_lastReply(0),
155 m_packetLenght(0)
159 CProxyStateMachine::~CProxyStateMachine()
161 delete m_peerAddress;
164 wxString &CProxyStateMachine::NewName(wxString &s, CProxyCommand proxyCommand)
166 switch (proxyCommand) {
167 case PROXY_CMD_CONNECT:
168 s += wxT("-CONNECT");
169 break;
171 case PROXY_CMD_BIND:
172 s += wxT("-BIND");
173 break;
175 case PROXY_CMD_UDP_ASSOCIATE:
176 s += wxT("-UDP");
177 break;
180 return s;
183 bool CProxyStateMachine::Start(const amuleIPV4Address &peerAddress, CLibSocket *proxyClientSocket)
185 m_proxyClientSocket = proxyClientSocket;
186 m_peerAddress = new amuleIPV4Address(peerAddress);
187 //try {
188 // const wxIPV4address &peer = dynamic_cast<const wxIPV4address &>(peerAddress);
189 // m_peerAddress = new amuleIPV4Address(peer);
190 //} catch (const std::bad_cast& WXUNUSED(e)) {
191 // // Should process other types of wxIPAddres before quitting
192 // AddDebugLogLineN(logProxy, wxT("(1)bad_cast exception!"));
193 // wxFAIL;
194 // return false;
197 // To run the state machine, return and just let the events start to happen.
198 return true;
201 static const int MULE_SOCKET_DUMMY_VALUE = MULE_SOCKET_INPUT + MULE_SOCKET_OUTPUT + MULE_SOCKET_CONNECTION + MULE_SOCKET_LOST;
203 t_sm_state CProxyStateMachine::HandleEvent(t_sm_event event)
205 // Default is stay in current state
206 t_sm_state ret = GetState();
207 switch(event)
209 case MULE_SOCKET_CONNECTION:
210 AddDebugLogLineN(logProxy, wxT("Connection event"));
211 m_isConnected = true;
212 break;
214 case MULE_SOCKET_INPUT:
215 AddDebugLogLineN(logProxy, wxT("Input event"));
216 m_canReceive = true;
217 break;
219 case MULE_SOCKET_OUTPUT:
220 AddDebugLogLineN(logProxy, wxT("Output event"));
221 m_canSend = true;
222 break;
224 case MULE_SOCKET_LOST:
225 AddDebugLogLineN(logProxy, wxT("Lost connection event"));
226 m_isLost = true;
227 m_ok = false;
228 break;
230 case MULE_SOCKET_DUMMY_VALUE:
231 AddDebugLogLineN(logProxy, wxT("Dummy event"));
232 break;
234 default:
235 AddDebugLogLineN(logProxy, CFormat(wxT("Unknown event %d")) % event);
236 break;
239 // Aborting conditions:
240 // - MULE_SOCKET_LOST event
241 // - More than 10 times on the same state
242 if ( m_isLost ||
243 GetClocksInCurrentState() > 10) {
244 ret = PROXY_STATE_END;
247 return ret;
250 void CProxyStateMachine::AddDummyEvent()
252 #ifdef ASIO_SOCKETS
253 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
254 if (s) { // should always be
255 CoreNotify_ProxySocketEvent(s, MULE_SOCKET_DUMMY_VALUE);
257 #else
258 wxSocketEvent e(ID_PROXY_SOCKET_EVENT);
259 // Make sure this is an unknown event :)
260 e.m_event = (wxSocketNotify)(MULE_SOCKET_DUMMY_VALUE);
261 e.SetEventObject(m_proxyClientSocket);
262 g_proxyEventHandler.AddPendingEvent(e);
263 #endif
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().
461 t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
463 // Default is stay in current state
464 t_sm_state ret = HandleEvent(event);
465 switch (GetState()) {
466 case SOCKS5_STATE_START:
467 if (m_isConnected && !m_isLost && CanSend()) {
468 ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
470 break;
472 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
473 if (CanReceive()) {
474 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
476 break;
478 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
479 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
480 break;
482 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
483 if (m_ok) {
484 if (CanSend()) {
485 switch (m_lastReply) {
486 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
487 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
488 break;
490 case SOCKS5_AUTH_METHOD_GSSAPI:
491 ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
492 break;
494 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
495 ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
496 break;
498 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
499 default:
500 ret = SOCKS5_STATE_END;
501 break;
503 } else {
504 AddDebugLogLineN(logProxy, wxT("Can't send"));
506 } else {
507 ret = SOCKS5_STATE_END;
509 break;
511 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
512 if (m_ok) {
513 if (CanReceive()) {
514 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
516 } else {
517 ret = SOCKS5_STATE_END;
519 break;
521 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
522 if (m_ok) {
523 if (CanReceive()) {
524 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
526 } else {
527 ret = SOCKS5_STATE_END;
529 break;
531 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
532 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
533 break;
535 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
536 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
537 break;
539 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
540 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
541 if (m_ok) {
542 if (CanSend()) {
543 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
545 } else {
546 ret = SOCKS5_STATE_END;
548 break;
550 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
551 if (m_ok) {
552 if (CanReceive()) {
553 ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
555 } else {
556 ret = SOCKS5_STATE_END;
558 break;
560 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
561 ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
562 break;
564 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
565 ret = SOCKS5_STATE_END;
566 break;
568 case SOCKS5_STATE_END:
569 default:
570 break;
573 return ret;
577 * So, this is how you do it: the state machine is clocked by the events
578 * that happen inside the event handler. You can add a dummy event whenever
579 * you see that the system will not generate an event. But don't add dummy
580 * events before reads, reads should only be performed after input events.
582 * Maybe it makes sense to add a dummy event before a read if there is no
583 * state change (wait state).
585 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
586 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
587 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
588 * event will be generated. If you feel you will need more clocks than these, use
589 * AddDummyEvent(), but I suggest you review your state machine design first.
591 void CSocks5StateMachine::process_start(bool)
594 void CSocks5StateMachine::process_end(bool)
596 ReactivateSocket();
599 void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
601 if (entry) {
602 // Prepare the authentication method negotiation packet
603 m_buffer[0] = SOCKS5_VERSION;
604 m_buffer[1] = 2; // Number of supported methods
605 //m_buffer[1] = 3; // Number of supported methods
606 m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
607 m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
608 m_buffer[4] = SOCKS5_AUTH_METHOD_GSSAPI;
609 m_packetLenght = 4;
610 //m_packetLenght = 5;
612 // Send the authentication method negotiation packet
613 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
617 void CSocks5StateMachine::process_receive_authentication_method(bool entry)
619 if (entry) {
620 // Receive the method selection message
621 m_packetLenght = 2;
622 ProxyRead(*m_proxyClientSocket, m_buffer);
624 /* This is added because there will be no more input events. If the
625 * world was a nice place, we could think about joining the
626 * process_receive and the process_process states here, but some day
627 * we might have to deal with the fact that the i/o operation has been
628 * incomplete, and that we must finish our job the next time we enter
629 * this state. */
630 AddDummyEvent();
633 void CSocks5StateMachine::process_process_authentication_method(bool entry)
635 if (entry) {
636 m_lastReply = m_buffer[1];
637 m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
639 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
640 * once when you connect the socket, and after that, only after a
641 * wxSOCKET_WOULDBLOCK error happens. */
642 AddDummyEvent();
645 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
647 // TODO or not TODO? That is the question...
648 m_ok = false;
651 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
653 AddDummyEvent();
656 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
658 AddDummyEvent();
661 void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
663 if (entry) {
664 unsigned char lenUser = m_proxyData.m_userName.Len();
665 unsigned char lenPassword = m_proxyData.m_password.Len();
666 m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
667 unsigned int offsetUser = 2;
668 unsigned int offsetPassword = offsetUser + lenUser + 1;
670 // Prepare username/password buffer
671 m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
672 m_buffer[offsetUser-1] = lenUser;
673 memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
674 lenUser);
675 m_buffer[offsetPassword-1] = lenPassword;
676 memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
677 lenPassword);
679 // Send the username/password packet
680 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
684 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
686 if (entry) {
687 // Receive the server's authentication response
688 m_packetLenght = 2;
689 ProxyRead(*m_proxyClientSocket, m_buffer);
691 AddDummyEvent();
694 void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
696 if (entry) {
697 // Process the server's reply
698 m_lastReply = m_buffer[1];
699 m_ok = m_ok &&
700 m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
701 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
703 AddDummyEvent();
706 void CSocks5StateMachine::process_send_command_request(bool entry)
708 if (entry) {
709 // Prepare the request command buffer
710 m_buffer[0] = SOCKS5_VERSION;
711 switch (m_proxyCommand) {
712 case PROXY_CMD_CONNECT:
713 m_buffer[1] = SOCKS5_CMD_CONNECT;
714 break;
716 case PROXY_CMD_BIND:
717 m_buffer[1] = SOCKS5_CMD_BIND;
718 break;
720 case PROXY_CMD_UDP_ASSOCIATE:
721 m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
722 break;
724 m_buffer[2] = SOCKS5_RSV;
725 m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
726 PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
727 RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
729 // Send the command packet
730 m_packetLenght = 10;
731 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
735 void CSocks5StateMachine::process_receive_command_reply(bool entry)
737 if (entry) {
738 // The minimum number of bytes to read is 10 in the case of
739 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
740 m_packetLenght = 10;
741 ProxyRead(*m_proxyClientSocket, m_buffer);
743 AddDummyEvent();
746 void CSocks5StateMachine::process_process_command_reply(bool entry)
748 if (entry) {
749 m_lastReply = m_buffer[1];
750 unsigned char addressType = m_buffer[3];
751 // Process the server's reply
752 m_ok = m_ok &&
753 m_buffer[0] == SOCKS5_VERSION &&
754 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
755 if (m_ok) {
756 // Read BND.ADDR
757 unsigned int portOffset = 0;
758 switch(addressType) {
759 case SOCKS5_ATYP_IPV4_ADDRESS:
761 const unsigned int addrOffset = 4;
762 portOffset = 8;
763 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
764 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
765 break;
767 case SOCKS5_ATYP_DOMAINNAME:
769 // Read the domain name
770 const unsigned int addrOffset = 5;
771 portOffset = 10 + m_buffer[4];
772 char c = m_buffer[portOffset];
773 m_buffer[portOffset] = 0;
774 m_proxyBoundAddressIPV4.Hostname(
775 char2unicode(m_buffer+addrOffset));
776 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
777 m_buffer[portOffset] = c;
778 break;
780 case SOCKS5_ATYP_IPV6_ADDRESS:
782 portOffset = 20;
783 // TODO
784 // IPV6 not yet implemented in wx
785 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
786 // *((uint128 *)(m_buffer+addrOffset)) ));
787 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
788 m_ok = false;
789 break;
792 // Set the packet length at last
793 m_packetLenght = portOffset + 2;
794 // Read BND.PORT
795 m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) ) );
798 AddDummyEvent();
801 //------------------------------------------------------------------------------
802 // CSocks4StateMachine
803 //------------------------------------------------------------------------------
805 CSocks4StateMachine::CSocks4StateMachine(
806 const CProxyData &proxyData,
807 CProxyCommand proxyCommand)
809 CProxyStateMachine(
810 wxString(wxT("Socks4")), SOCKS4_MAX_STATES, proxyData, proxyCommand)
812 m_process_state[0] = &CSocks4StateMachine::process_start;
813 m_state_name[0] = wxT("process_start");
814 m_process_state[1] = &CSocks4StateMachine::process_end;
815 m_state_name[1] = wxT("process_end");
816 m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
817 m_state_name[2] = wxT("process_send_command_request");
818 m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
819 m_state_name[3] = wxT("process_receive_command_reply");
820 m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
821 m_state_name[4] = wxT("process_process_command_reply");
824 void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
826 (this->*m_process_state[state])(entry);
827 #ifdef __DEBUG__
828 int n = 0;
830 switch (state) {
831 case SOCKS4_STATE_START:
832 case SOCKS4_STATE_END:
833 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
834 default:
835 n = 0;
836 break;
838 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
839 n = m_packetLenght;
840 break;
842 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
843 n = m_lastRead;
844 break;
847 if (entry) {
848 DumpMem(m_buffer, n, m_state_name[state], m_ok);
849 } else {
850 AddDebugLogLineN(logProxy,
851 wxString(wxT("wait state -- ")) << m_state_name[state]);
853 #endif // __DEBUG__
856 t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
858 // Default is stay in current state
859 t_sm_state ret = HandleEvent(event);
860 switch (GetState()) {
861 case SOCKS4_STATE_START:
862 if (m_isConnected && !m_isLost && CanSend()) {
863 ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
865 break;
867 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
868 if (m_ok) {
869 if (CanReceive()) {
870 ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
872 } else {
873 ret = SOCKS4_STATE_END;
875 break;
877 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
878 ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
879 break;
881 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
882 ret = SOCKS4_STATE_END;
883 break;
885 case SOCKS4_STATE_END:
886 default:
887 break;
890 return ret;
893 void CSocks4StateMachine::process_start(bool)
896 void CSocks4StateMachine::process_end(bool)
898 ReactivateSocket();
901 void CSocks4StateMachine::process_send_command_request(bool entry)
903 if (entry) {
904 // Prepare the request command buffer
905 m_buffer[0] = SOCKS4_VERSION;
906 switch (m_proxyCommand) {
907 case PROXY_CMD_CONNECT:
908 m_buffer[1] = SOCKS4_CMD_CONNECT;
909 break;
911 case PROXY_CMD_BIND:
912 m_buffer[1] = SOCKS4_CMD_BIND;
913 break;
915 case PROXY_CMD_UDP_ASSOCIATE:
916 m_ok = false;
917 return;
918 break;
920 RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
921 // Special processing for SOCKS4a
922 switch (m_proxyData.m_proxyType) {
923 case PROXY_SOCKS4a:
924 PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
925 break;
926 case PROXY_SOCKS4:
927 default:
928 PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
929 break;
931 // Common processing for SOCKS4/SOCKS4a
932 unsigned int offsetUser = 8;
933 unsigned char lenUser = m_proxyData.m_userName.Len();
934 memcpy(m_buffer + offsetUser,
935 unicode2char(m_proxyData.m_userName), lenUser);
936 m_buffer[offsetUser + lenUser] = 0;
937 // Special processing for SOCKS4a
938 switch (m_proxyData.m_proxyType) {
939 case PROXY_SOCKS4a: {
940 unsigned int offsetDomain = offsetUser + lenUser + 1;
941 // The Hostname() method was used here before, but I don't see why we can't use
942 // the IP address which we actually know instead here.
943 wxString hostname(m_peerAddress->IPAddress());
944 unsigned char lenDomain = hostname.Len();
945 memcpy(m_buffer + offsetDomain,
946 unicode2char(hostname), lenDomain);
947 m_buffer[offsetDomain + lenDomain] = 0;
948 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
949 break;
951 case PROXY_SOCKS4:
952 default:
953 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
954 break;
956 // Send the command packet
957 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
961 void CSocks4StateMachine::process_receive_command_reply(bool entry)
963 if (entry) {
964 // Receive the server's reply
965 m_packetLenght = 8;
966 ProxyRead(*m_proxyClientSocket, m_buffer);
968 AddDummyEvent();
971 void CSocks4StateMachine::process_process_command_reply(bool entry)
973 if (entry) {
974 m_lastReply = m_buffer[1];
976 // Process the server's reply
977 m_ok = m_ok &&
978 m_buffer[0] == SOCKS4_REPLY_CODE &&
979 m_buffer[1] == SOCKS4_REPLY_GRANTED;
980 if (m_ok) {
981 // Read BND.PORT
982 const unsigned int portOffset = 2;
983 m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(
984 RawPeekUInt16( m_buffer+portOffset) ) );
985 // Read BND.ADDR
986 const unsigned int addrOffset = 4;
987 m_ok = m_ok &&
988 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
989 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
992 AddDummyEvent();
995 //------------------------------------------------------------------------------
996 // CHttpStateMachine
997 //------------------------------------------------------------------------------
999 CHttpStateMachine::CHttpStateMachine(
1000 const CProxyData &proxyData,
1001 CProxyCommand proxyCommand)
1003 CProxyStateMachine(
1004 wxString(wxT("Http")), HTTP_MAX_STATES, proxyData, proxyCommand)
1006 m_process_state[0] = &CHttpStateMachine::process_start;
1007 m_state_name[0] = wxT("process_start");
1008 m_process_state[1] = &CHttpStateMachine::process_end;
1009 m_state_name[1] = wxT("process_end");
1010 m_process_state[2] = &CHttpStateMachine::process_send_command_request;
1011 m_state_name[2] = wxT("process_send_command_request");
1012 m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
1013 m_state_name[3] = wxT("process_receive_command_reply");
1014 m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
1015 m_state_name[4] = wxT("process_process_command_reply");
1018 void CHttpStateMachine::process_state(t_sm_state state, bool entry)
1020 (this->*m_process_state[state])(entry);
1021 #ifdef __DEBUG__
1022 int n = 0;
1024 switch (state) {
1025 case HTTP_STATE_START:
1026 case HTTP_STATE_END:
1027 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1028 default:
1029 n = 0;
1030 break;
1032 case HTTP_STATE_SEND_COMMAND_REQUEST:
1033 n = m_packetLenght;
1034 break;
1036 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1037 n = m_lastRead;
1038 break;
1041 if (entry) {
1042 DumpMem(m_buffer, n, m_state_name[state], m_ok);
1043 } else {
1044 AddDebugLogLineN(logProxy,
1045 wxString(wxT("wait state -- ")) << m_state_name[state]);
1047 #endif // __DEBUG__
1050 t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1052 // Default is stay in current state
1053 t_sm_state ret = HandleEvent(event);
1054 switch (GetState()) {
1055 case HTTP_STATE_START:
1056 if (m_isConnected && !m_isLost && CanSend()) {
1057 ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1059 break;
1061 case HTTP_STATE_SEND_COMMAND_REQUEST:
1062 if (m_ok) {
1063 if (CanReceive()) {
1064 ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1066 } else {
1067 ret = HTTP_STATE_END;
1069 break;
1071 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1072 ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1073 break;
1075 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1076 ret = HTTP_STATE_END;
1077 break;
1079 case HTTP_STATE_END:
1080 default:
1081 break;
1084 return ret;
1087 void CHttpStateMachine::process_start(bool)
1090 void CHttpStateMachine::process_end(bool)
1092 ReactivateSocket();
1095 void CHttpStateMachine::process_send_command_request(bool entry)
1097 if (entry) {
1098 // Prepare the request command buffer
1099 wxString ip = m_peerAddress->IPAddress();
1100 uint16 port = m_peerAddress->Service();
1101 wxString userPass;
1102 wxString userPassEncoded;
1103 if (m_proxyData.m_enablePassword) {
1104 userPass = m_proxyData.m_userName + wxT(":") + m_proxyData.m_password;
1105 userPassEncoded =
1106 EncodeBase64(unicode2char(userPass), userPass.Length());
1108 wxString msg;
1110 switch (m_proxyCommand) {
1111 case PROXY_CMD_CONNECT:
1112 msg <<
1113 wxT("CONNECT ") << ip << wxT(":") << port << wxT(" HTTP/1.1\r\n") <<
1114 wxT("Host: ") << ip << wxT(":") << port << wxT("\r\n");
1115 if (m_proxyData.m_enablePassword) {
1116 msg <<
1117 wxT("Authorization: Basic ") << userPassEncoded << wxT("\r\n") <<
1118 wxT("Proxy-Authorization: Basic ") << userPassEncoded << wxT("\r\n");
1120 msg << wxT("\r\n");
1121 break;
1123 case PROXY_CMD_BIND:
1124 m_ok = false;
1125 break;
1127 case PROXY_CMD_UDP_ASSOCIATE:
1128 m_ok = false;
1129 return;
1130 break;
1132 // Send the command packet
1133 m_packetLenght = msg.Len();
1134 memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1135 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1139 void CHttpStateMachine::process_receive_command_reply(bool entry)
1141 if (entry) {
1142 // Receive the server's reply -- Use a large number, but don't
1143 // Expect to get it all. HTTP protocol does not have a fixed length.
1144 m_packetLenght = PROXY_BUFFER_SIZE;
1145 ProxyRead(*m_proxyClientSocket, m_buffer);
1147 AddDummyEvent();
1151 * HTTP Proxy server response should be something like:
1152 * "HTTP/1.1 200 Connection established\r\n\r\n"
1153 * but that may vary. The important thing is the "200"
1154 * code, that means success.
1156 static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1157 static const int HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
1158 void CHttpStateMachine::process_process_command_reply(bool entry)
1160 if (entry) {
1161 // The position of the first space in the buffer
1162 int i = 8;
1163 while (m_buffer[i] == ' ') {
1164 i++;
1166 // Process the server's reply
1167 m_ok = !memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1168 !memcmp(m_buffer + i, "200", 3);
1170 AddDummyEvent();
1173 //------------------------------------------------------------------------------
1174 // CProxySocket
1175 //------------------------------------------------------------------------------
1177 CProxySocket::CProxySocket(
1178 muleSocketFlags flags,
1179 const CProxyData *proxyData,
1180 CProxyCommand proxyCommand,
1181 CDatagramSocketProxy *udpSocket)
1183 CLibSocket(flags),
1184 m_proxyStateMachine(NULL),
1185 m_udpSocket(udpSocket)
1186 #ifndef ASIO_SOCKETS
1187 ,m_socketEventHandler(NULL)
1188 ,m_socketEventHandlerId(0)
1189 ,m_savedSocketEventHandler(NULL)
1190 ,m_savedSocketEventHandlerId(0)
1191 #endif
1193 SetProxyData(proxyData);
1194 if (m_useProxy) {
1195 switch (m_proxyData.m_proxyType) {
1196 case PROXY_NONE:
1197 break;
1199 case PROXY_SOCKS5:
1200 m_proxyStateMachine =
1201 new CSocks5StateMachine(*proxyData, proxyCommand);
1202 break;
1204 case PROXY_SOCKS4:
1205 case PROXY_SOCKS4a:
1206 m_proxyStateMachine =
1207 new CSocks4StateMachine(*proxyData, proxyCommand);
1208 break;
1210 case PROXY_HTTP:
1211 m_proxyStateMachine =
1212 new CHttpStateMachine(*proxyData, proxyCommand);
1213 break;
1215 default:
1216 break;
1221 CProxySocket::~CProxySocket()
1223 delete m_proxyStateMachine;
1226 void CProxySocket::SetProxyData(const CProxyData *proxyData)
1228 m_useProxy = proxyData != NULL && proxyData->m_proxyEnable;
1229 if (proxyData) {
1230 m_proxyData = *proxyData;
1231 m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1232 m_proxyAddress.Service(m_proxyData.m_proxyPort);
1233 } else {
1234 m_proxyData.Clear();
1238 bool CProxySocket::Start(const amuleIPV4Address &peerAddress)
1240 #ifdef ASIO_SOCKETS
1241 SetProxyState(true, &peerAddress);
1242 #else
1243 SaveState();
1244 // Important note! SaveState()/RestoreState() DO NOT save/restore
1245 // the event handler. The method SaveEventHandler() has been created
1246 // for that.
1247 SaveEventHandler();
1248 SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1249 SetNotify(
1250 wxSOCKET_CONNECTION_FLAG |
1251 wxSOCKET_INPUT_FLAG |
1252 wxSOCKET_OUTPUT_FLAG |
1253 wxSOCKET_LOST_FLAG);
1254 Notify(true);
1255 #endif
1256 Connect(m_proxyAddress, false);
1257 SetFlags(MULE_SOCKET_NONE);
1258 return m_proxyStateMachine->Start(peerAddress, this);
1261 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1263 bool ret = false;
1265 switch (m_proxyData.m_proxyType) {
1266 case PROXY_NONE:
1267 ret = false;
1268 break;
1270 case PROXY_SOCKS5:
1271 ret = proxyCommand == PROXY_CMD_CONNECT ||
1272 proxyCommand == PROXY_CMD_BIND ||
1273 proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1274 break;
1276 case PROXY_SOCKS4:
1277 case PROXY_SOCKS4a:
1278 ret = proxyCommand == PROXY_CMD_CONNECT ||
1279 proxyCommand == PROXY_CMD_BIND;
1280 break;
1282 case PROXY_HTTP:
1283 ret = proxyCommand == PROXY_CMD_CONNECT;
1284 break;
1287 return ret;
1290 //------------------------------------------------------------------------------
1291 // CSocketClientProxy
1292 //------------------------------------------------------------------------------
1294 CSocketClientProxy::CSocketClientProxy(
1295 muleSocketFlags flags,
1296 const CProxyData *proxyData)
1298 CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1302 bool CSocketClientProxy::Connect(amuleIPV4Address &address, bool wait)
1304 wxMutexLocker lock(m_socketLocker);
1305 bool ok;
1307 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1308 ok = Start(address);
1309 } else {
1310 ok = CLibSocket::Connect(address, wait);
1313 return ok;
1316 uint32 CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1318 wxMutexLocker lock(m_socketLocker);
1319 return CProxySocket::Read(buffer, nbytes);
1322 uint32 CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1324 wxMutexLocker lock(m_socketLocker);
1325 return CProxySocket::Write(buffer, nbytes);
1328 //------------------------------------------------------------------------------
1329 // CSocketServerProxy
1330 //------------------------------------------------------------------------------
1332 CSocketServerProxy::CSocketServerProxy(
1333 amuleIPV4Address &address,
1334 muleSocketFlags flags,
1335 const CProxyData *)
1337 CLibSocketServer(address, flags)
1339 /* Maybe some day when socks6 is out... :) */
1342 //------------------------------------------------------------------------------
1343 // CDatagramSocketProxy
1344 //------------------------------------------------------------------------------
1346 CDatagramSocketProxy::CDatagramSocketProxy(
1347 amuleIPV4Address &address, muleSocketFlags flags, const CProxyData *proxyData)
1349 CLibUDPSocket(address, flags),
1350 m_proxyTCPSocket(MULE_SOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1352 m_udpSocketOk = false;
1353 if ( m_proxyTCPSocket.GetUseProxy() &&
1354 m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1355 m_proxyTCPSocket.Start(address);
1356 } else {
1358 m_lastUDPOperation = UDP_OPERATION_NONE;
1361 CDatagramSocketProxy::~CDatagramSocketProxy()
1363 // From RFC-1928:
1364 // "A UDP association terminates when the TCP connection that the
1365 // UDP ASSOCIATE request arrived terminates."
1368 uint32 CDatagramSocketProxy::RecvFrom(amuleIPV4Address& addr, void* buf, uint32 nBytes)
1370 uint32 read = 0;
1371 wxMutexLocker lock(m_socketLocker);
1372 m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1373 if (m_proxyTCPSocket.GetUseProxy()) {
1374 if (m_udpSocketOk) {
1375 char *bufUDP = NULL;
1376 if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1377 bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1378 } else {
1379 bufUDP = m_proxyTCPSocket.GetBuffer();
1381 read = CLibUDPSocket::RecvFrom(
1382 m_proxyTCPSocket.GetProxyBoundAddress(),
1383 bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1384 unsigned int offset;
1385 switch (m_proxyTCPSocket.GetBuffer()[3]) {
1386 case SOCKS5_ATYP_IPV4_ADDRESS: {
1387 offset = PROXY_UDP_OVERHEAD_IPV4;
1388 try {
1389 amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1390 a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1391 a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) ) );
1392 } catch (const std::bad_cast& WXUNUSED(e)) {
1393 AddDebugLogLineN(logProxy,
1394 wxT("(2)bad_cast exception!"));
1395 wxFAIL;
1398 break;
1400 case SOCKS5_ATYP_DOMAINNAME:
1401 offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1402 break;
1404 case SOCKS5_ATYP_IPV6_ADDRESS:
1405 offset = PROXY_UDP_OVERHEAD_IPV6;
1406 break;
1408 default:
1409 /* Error! */
1410 offset = 0;
1411 break;
1413 memcpy(buf, bufUDP + offset, nBytes);
1414 // Uncomment here to see the buffer contents on console
1415 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1417 /* Only delete buffer if it was dynamically created */
1418 if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1419 /* We should use a fixed buffer to avoid
1420 * new/delete it all the time.
1421 * I need an upper bound */
1422 delete [] bufUDP;
1424 /* There is still one problem pending, fragmentation.
1425 * Either we support it or we have to drop fragmented
1426 * messages. I vote for drop :)
1429 } else {
1430 read = CLibUDPSocket::RecvFrom(addr, buf, nBytes);
1433 return read;
1436 uint32 CDatagramSocketProxy::SendTo(const amuleIPV4Address& addr, const void* buf, uint32 nBytes)
1438 uint32 sent = 0;
1439 wxMutexLocker lock(m_socketLocker);
1440 m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1441 m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1442 if (m_proxyTCPSocket.GetUseProxy()) {
1443 if (m_udpSocketOk) {
1444 m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV; // Reserved
1445 m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV; // Reserved
1446 m_proxyTCPSocket.GetBuffer()[2] = 0; // FRAG
1447 m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1448 PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1449 RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
1450 memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1451 nBytes += PROXY_UDP_OVERHEAD_IPV4;
1452 sent = CLibUDPSocket::SendTo(
1453 m_proxyTCPSocket.GetProxyBoundAddress(),
1454 m_proxyTCPSocket.GetBuffer(), nBytes);
1455 // Uncomment here to see the buffer contents on console
1456 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1458 } else {
1459 sent = CLibUDPSocket::SendTo(addr, buf, nBytes);
1462 return sent;
1465 #endif // CLIENT_GUI
1467 /******************************************************************************/
1468 // File_checked_for_headers