Improve speed of category tab title updates
[amule.git] / src / Proxy.cpp
blob830d384d0ab7ee69b5a6d52bd7f33b6bad3bf7d0
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2004-2008 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.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "Proxy.h" /* for Interface */
29 #include <common/EventIDs.h>
31 #include "ArchSpecific.h" /* for ENDIAN_HTONS() */
32 #include "Logger.h" /* for AddDebugLogLineN */
33 #include "OtherFunctions.h" /* for EncodeBase64() */
34 #include <common/StringFunctions.h> /* for unicode2char */
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),
58 /*
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 } else {
110 // we're doomed :)
112 sock->m_proxyStateMachine->Clock();
115 //------------------------------------------------------------------------------
116 // CProxyStateMachine
117 //------------------------------------------------------------------------------
119 CProxyStateMachine::CProxyStateMachine(
120 wxString name,
121 const unsigned int max_states,
122 const CProxyData &proxyData,
123 CProxyCommand proxyCommand)
125 CStateMachine(NewName(name, proxyCommand), max_states, PROXY_STATE_START),
126 m_proxyData(proxyData),
127 m_proxyCommand(proxyCommand),
128 m_isLost(false),
129 m_isConnected(false),
130 m_canReceive(false),
131 m_canSend(false),
132 m_ok(true),
133 m_lastRead(0),
134 m_lastWritten(0),
135 // Will be initialized at Start()
136 m_peerAddress(NULL),
137 m_proxyClientSocket(NULL),
138 m_proxyBoundAddress(NULL),
139 // Temporary variables
140 m_lastReply(0),
141 m_packetLenght(0)
145 CProxyStateMachine::~CProxyStateMachine()
147 delete m_peerAddress;
150 wxString &CProxyStateMachine::NewName(wxString &s, CProxyCommand proxyCommand)
152 switch (proxyCommand) {
153 case PROXY_CMD_CONNECT:
154 s += wxT("-CONNECT");
155 break;
157 case PROXY_CMD_BIND:
158 s += wxT("-BIND");
159 break;
161 case PROXY_CMD_UDP_ASSOCIATE:
162 s += wxT("-UDP");
163 break;
166 return s;
169 bool CProxyStateMachine::Start(const wxIPaddress &peerAddress, wxSocketClient *proxyClientSocket)
171 m_proxyClientSocket = proxyClientSocket;
172 try {
173 const wxIPV4address &peer = dynamic_cast<const wxIPV4address &>(peerAddress);
174 m_peerAddress = new amuleIPV4Address(peer);
175 } catch (const std::bad_cast& WXUNUSED(e)) {
176 // Should process other types of wxIPAddres before quitting
177 AddDebugLogLineN(logProxy, wxT("(1)bad_cast exception!"));
178 wxFAIL;
179 return false;
182 // To run the state machine, return and just let the events start to happen.
183 return true;
186 t_sm_state CProxyStateMachine::HandleEvent(t_sm_event event)
188 // Default is stay in current state
189 t_sm_state ret = GetState();
190 switch(event)
192 case wxSOCKET_CONNECTION:
193 AddDebugLogLineN(logProxy, wxT("Connection event"));
194 m_isConnected = true;
195 break;
197 case wxSOCKET_INPUT:
198 AddDebugLogLineN(logProxy, wxT("Input event"));
199 m_canReceive = true;
200 break;
202 case wxSOCKET_OUTPUT:
203 AddDebugLogLineN(logProxy, wxT("Output event"));
204 m_canSend = true;
205 break;
207 case wxSOCKET_LOST:
208 AddDebugLogLineN(logProxy, wxT("Lost connection event"));
209 m_isLost = true;
210 m_ok = false;
211 break;
213 default:
214 AddDebugLogLineN(logProxy, wxT("Unknown event"));
215 break;
218 // Aborting conditions:
219 // - wxSOCKET_LOST event
220 // - More than 10 times on the same state
221 if ( m_isLost ||
222 GetClocksInCurrentState() > 10) {
223 ret = PROXY_STATE_END;
226 return ret;
229 void CProxyStateMachine::AddDummyEvent()
231 wxSocketEvent e(ID_PROXY_SOCKET_EVENT);
232 // Make sure this is an unknown event :)
233 e.m_event = (wxSocketNotify)(
234 wxSOCKET_INPUT + wxSOCKET_OUTPUT +
235 wxSOCKET_CONNECTION + wxSOCKET_LOST);
236 e.SetEventObject(m_proxyClientSocket);
237 g_proxyEventHandler.AddPendingEvent(e);
241 * Notice! These includes are here as long as it is impossible to retrieve
242 * the event handler from the socket. They should be removed. For now,
243 * please leave it here.
246 void CProxyStateMachine::ReactivateSocket()
248 /* If proxy is beeing used, then the TCP socket handlers
249 * (CServerSocketHandler and CClientTCPSocketHandler) will not
250 * receive a wxSOCKET_CONNECTION event, because the connection has
251 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
252 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
253 * necessary to start sending data to the server. */
254 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
255 // If that is not true, we are in serious trouble...
256 wxASSERT(s);
257 if (CDatagramSocketProxy *udp = s->GetUDPSocket()) {
258 // The original socket was a UDP socket
259 if(m_ok) {
260 // From now on, the UDP socket can be used,
261 // remove the protection.
262 udp->SetUDPSocketOk();
264 // No need to call RestoreState(), that socket will no longer
265 // be used after proxy negotiation.
266 } else {
267 // The original socket was a TCP socket
268 s->RestoreEventHandler();
269 wxSocketEvent e(s->GetEventHandlerId());
270 e.m_event = wxSOCKET_CONNECTION;
271 e.SetEventObject(s);
272 wxEvtHandler *h(s->GetEventHandler());
273 h->AddPendingEvent(e);
274 e.m_event = wxSOCKET_OUTPUT;
275 h->AddPendingEvent(e);
276 if (!m_ok) {
277 e.m_event = wxSOCKET_LOST;
278 h->AddPendingEvent(e);
280 s->RestoreState();
284 wxSocketBase &CProxyStateMachine::ProxyWrite(wxSocketBase &socket, const void *buffer, wxUint32 nbytes)
286 wxSocketBase &ret = socket.Write(buffer, nbytes);
287 m_lastWritten = m_proxyClientSocket->LastCount();
288 /* Set the status of this operation */
289 m_lastError = wxSOCKET_NOERROR;
290 m_ok = !m_proxyClientSocket->Error();
291 if (!m_ok) {
292 m_lastError = m_proxyClientSocket->LastError();
293 m_ok = m_lastError == wxSOCKET_WOULDBLOCK;
294 if (m_ok) {
295 m_canSend = false;
299 return ret;
302 wxSocketBase &CProxyStateMachine::ProxyRead(wxSocketBase &socket, void *buffer)
304 /* Always try to read the full buffer. That explicitly demands that
305 * the socket has the flag wxSOCKET_NONE. */
306 wxSocketBase &ret = socket.Read(buffer, PROXY_BUFFER_SIZE);
307 m_lastRead = m_proxyClientSocket->LastCount();
308 /* Set the status of this operation */
309 m_lastError = wxSOCKET_NOERROR;
310 m_ok = !m_proxyClientSocket->Error();
311 if (!m_ok) {
312 m_lastError = m_proxyClientSocket->LastError();
313 m_ok = m_lastError == wxSOCKET_WOULDBLOCK;
314 if (m_ok) {
315 m_canReceive = false;
319 return ret;
322 bool CProxyStateMachine::CanReceive() const
324 #ifdef AMULE_DAEMON
325 return true;
326 #else
327 return m_canReceive;
328 #endif
331 bool CProxyStateMachine::CanSend() const
333 #ifdef AMULE_DAEMON
334 return true;
335 #else
336 return m_canSend;
337 #endif
340 //------------------------------------------------------------------------------
341 // CSocks5StateMachine
342 //------------------------------------------------------------------------------
345 * The state machine constructor must initialize the array of pointer to member
346 * functions. Don't waste you time trying to statically initialize this, pointer
347 * to member functions require an object to operate on, so this array must be
348 * initialized at run time.
350 CSocks5StateMachine::CSocks5StateMachine(
351 const CProxyData &proxyData,
352 CProxyCommand proxyCommand)
354 CProxyStateMachine(
355 wxString(wxT("Socks5")), SOCKS5_MAX_STATES, proxyData, proxyCommand)
357 m_process_state[ 0] = &CSocks5StateMachine::process_start;
358 m_state_name[ 0] = wxT("process_start");
359 m_process_state[ 1] = &CSocks5StateMachine::process_end;
360 m_state_name[ 1] = wxT("process_end");
361 m_process_state[ 2] = &CSocks5StateMachine::process_send_query_authentication_method;
362 m_state_name[ 2] = wxT("process_send_query_authentication_method");
363 m_process_state[ 3] = &CSocks5StateMachine::process_receive_authentication_method;
364 m_state_name[ 3] = wxT("process_receive_authentication_method");
365 m_process_state[ 4] = &CSocks5StateMachine::process_process_authentication_method;
366 m_state_name[ 4] = wxT("process_process_authentication_method");
367 m_process_state[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi;
368 m_state_name[ 5] = wxT("process_send_authentication_gssapi");
369 m_process_state[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi;
370 m_state_name[ 6] = wxT("process_receive_authentication_gssapi");
371 m_process_state[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi;
372 m_state_name[ 7] = wxT("process_process_authentication_gssapi");
373 m_process_state[ 8] = &CSocks5StateMachine::process_send_authentication_username_password;
374 m_state_name[ 8] = wxT("process_send_authentication_username_password");
375 m_process_state[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password;
376 m_state_name[ 9] = wxT("process_receive_authentication_username_password");
377 m_process_state[10] = &CSocks5StateMachine::process_process_authentication_username_password;
378 m_state_name[10] = wxT("process_process_authentication_username_password");
379 m_process_state[11] = &CSocks5StateMachine::process_send_command_request;
380 m_state_name[11] = wxT("process_send_command_request");
381 m_process_state[12] = &CSocks5StateMachine::process_receive_command_reply;
382 m_state_name[12] = wxT("process_receive_command_reply");
383 m_process_state[13] = &CSocks5StateMachine::process_process_command_reply;
384 m_state_name[13] = wxT("process_process_command_reply");
387 void CSocks5StateMachine::process_state(t_sm_state state, bool entry)
389 /* Ok, the syntax is terrible, but this is correct. This is a
390 * pointer to a member function. No C equivalent for that. */
391 (this->*m_process_state[state])(entry);
392 #ifdef __DEBUG__
393 int n = 0;
395 switch (state) {
396 case SOCKS5_STATE_START:
397 case SOCKS5_STATE_END:
398 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
399 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
400 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
401 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
402 default:
403 n = 0;
404 break;
406 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
407 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
408 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
409 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
410 n = m_packetLenght;
411 break;
413 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
414 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
415 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
416 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
417 n = m_lastRead;
418 break;
421 if (entry) {
422 DumpMem(m_buffer, n, m_state_name[state], m_ok);
423 } else {
424 AddDebugLogLineN(logProxy,
425 wxString(wxT("wait state -- ")) << m_state_name[state]);
427 #endif // __DEBUG__
431 * Code this such that the next state is only entered when it is able to
432 * perform the operation (read or write). State processing will assume
433 * that it can read or write upon entry of the state. This is done using
434 * CanSend() and CanReceive(). On daemon, these functions always return
435 * true, because sockets are blocking.
437 t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
439 // Default is stay in current state
440 t_sm_state ret = HandleEvent(event);
441 switch (GetState()) {
442 case SOCKS5_STATE_START:
443 if (m_isConnected && !m_isLost && CanSend()) {
444 ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
446 break;
448 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
449 if (CanReceive()) {
450 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
452 break;
454 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
455 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
456 break;
458 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
459 if (m_ok) {
460 if (CanSend()) {
461 switch (m_lastReply) {
462 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
463 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
464 break;
466 case SOCKS5_AUTH_METHOD_GSSAPI:
467 ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
468 break;
470 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
471 ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
472 break;
474 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
475 default:
476 ret = SOCKS5_STATE_END;
477 break;
479 } else {
480 AddDebugLogLineN(logProxy, wxT("Can't send"));
482 } else {
483 ret = SOCKS5_STATE_END;
485 break;
487 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
488 if (m_ok) {
489 if (CanReceive()) {
490 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
492 } else {
493 ret = SOCKS5_STATE_END;
495 break;
497 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
498 if (m_ok) {
499 if (CanReceive()) {
500 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
502 } else {
503 ret = SOCKS5_STATE_END;
505 break;
507 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
508 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
509 break;
511 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
512 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
513 break;
515 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
516 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
517 if (m_ok) {
518 if (CanSend()) {
519 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
521 } else {
522 ret = SOCKS5_STATE_END;
524 break;
526 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
527 if (m_ok) {
528 if (CanReceive()) {
529 ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
531 } else {
532 ret = SOCKS5_STATE_END;
534 break;
536 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
537 ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
538 break;
540 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
541 ret = SOCKS5_STATE_END;
542 break;
544 case SOCKS5_STATE_END:
545 default:
546 break;
549 return ret;
553 * So, this is how you do it: the state machine is clocked by the events
554 * that happen inside the event handler. You can add a dummy event whenever
555 * you see that the system will not generate an event. But don't add dummy
556 * events before reads, reads should only be performed after input events.
558 * Maybe it makes sense to add a dummy event before a read if there is no
559 * state change (wait state).
561 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
562 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
563 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
564 * event will be generated. If you feel you will need more clocks than these, use
565 * AddDummyEvent(), but I suggest you review your state machine design first.
567 void CSocks5StateMachine::process_start(bool entry)
569 if (entry) {
570 } else {
574 void CSocks5StateMachine::process_end(bool)
576 ReactivateSocket();
579 void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
581 if (entry) {
582 // Prepare the authentication method negotiation packet
583 m_buffer[0] = SOCKS5_VERSION;
584 m_buffer[1] = 2; // Number of supported methods
585 //m_buffer[1] = 3; // Number of supported methods
586 m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
587 m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
588 m_buffer[4] = SOCKS5_AUTH_METHOD_GSSAPI;
589 m_packetLenght = 4;
590 //m_packetLenght = 5;
592 // Send the authentication method negotiation packet
593 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
597 void CSocks5StateMachine::process_receive_authentication_method(bool entry)
599 if (entry) {
600 // Receive the method selection message
601 m_packetLenght = 2;
602 ProxyRead(*m_proxyClientSocket, m_buffer);
604 /* This is added because there will be no more input events. If the
605 * world was a nice place, we could think about joining the
606 * process_receive and the process_process states here, but some day
607 * we might have to deal with the fact that the i/o operation has been
608 * incomplete, and that we must finish our job the next time we enter
609 * this state. */
610 AddDummyEvent();
613 void CSocks5StateMachine::process_process_authentication_method(bool entry)
615 if (entry) {
616 m_lastReply = m_buffer[1];
617 m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
619 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
620 * once when you connect the socket, and after that, only after a
621 * wxSOCKET_WOULDBLOCK error happens. */
622 AddDummyEvent();
625 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
627 // TODO or not TODO? That is the question...
628 m_ok = false;
631 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
633 AddDummyEvent();
636 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
638 AddDummyEvent();
641 void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
643 if (entry) {
644 unsigned char lenUser = m_proxyData.m_userName.Len();
645 unsigned char lenPassword = m_proxyData.m_password.Len();
646 m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
647 unsigned int offsetUser = 2;
648 unsigned int offsetPassword = offsetUser + lenUser + 1;
650 // Prepare username/password buffer
651 m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
652 m_buffer[offsetUser-1] = lenUser;
653 memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
654 lenUser);
655 m_buffer[offsetPassword-1] = lenPassword;
656 memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
657 lenPassword);
659 // Send the username/password packet
660 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
664 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
666 if (entry) {
667 // Receive the server's authentication response
668 m_packetLenght = 2;
669 ProxyRead(*m_proxyClientSocket, m_buffer);
671 AddDummyEvent();
674 void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
676 if (entry) {
677 // Process the server's reply
678 m_lastReply = m_buffer[1];
679 m_ok = m_ok &&
680 m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
681 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
683 AddDummyEvent();
686 void CSocks5StateMachine::process_send_command_request(bool entry)
688 if (entry) {
689 // Prepare the request command buffer
690 m_buffer[0] = SOCKS5_VERSION;
691 switch (m_proxyCommand) {
692 case PROXY_CMD_CONNECT:
693 m_buffer[1] = SOCKS5_CMD_CONNECT;
694 break;
696 case PROXY_CMD_BIND:
697 m_buffer[1] = SOCKS5_CMD_BIND;
698 break;
700 case PROXY_CMD_UDP_ASSOCIATE:
701 m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
702 break;
704 m_buffer[2] = SOCKS5_RSV;
705 m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
706 PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
707 RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
709 // Send the command packet
710 m_packetLenght = 10;
711 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
715 void CSocks5StateMachine::process_receive_command_reply(bool entry)
717 if (entry) {
718 // The minimum number of bytes to read is 10 in the case of
719 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
720 m_packetLenght = 10;
721 ProxyRead(*m_proxyClientSocket, m_buffer);
723 AddDummyEvent();
726 void CSocks5StateMachine::process_process_command_reply(bool entry)
728 if (entry) {
729 m_lastReply = m_buffer[1];
730 unsigned char addressType = m_buffer[3];
731 // Process the server's reply
732 m_ok = m_ok &&
733 m_buffer[0] == SOCKS5_VERSION &&
734 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
735 if (m_ok) {
736 // Read BND.ADDR
737 unsigned int portOffset = 0;
738 switch(addressType) {
739 case SOCKS5_ATYP_IPV4_ADDRESS:
741 const unsigned int addrOffset = 4;
742 portOffset = 8;
743 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
744 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
745 break;
747 case SOCKS5_ATYP_DOMAINNAME:
749 // Read the domain name
750 const unsigned int addrOffset = 5;
751 portOffset = 10 + m_buffer[4];
752 char c = m_buffer[portOffset];
753 m_buffer[portOffset] = 0;
754 m_proxyBoundAddressIPV4.Hostname(
755 char2unicode(m_buffer+addrOffset));
756 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
757 m_buffer[portOffset] = c;
758 break;
760 case SOCKS5_ATYP_IPV6_ADDRESS:
762 portOffset = 20;
763 // TODO
764 // IPV6 not yet implemented in wx
765 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
766 // *((uint128 *)(m_buffer+addrOffset)) ));
767 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
768 m_ok = false;
769 break;
772 // Set the packet length at last
773 m_packetLenght = portOffset + 2;
774 // Read BND.PORT
775 m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) ) );
778 AddDummyEvent();
781 //------------------------------------------------------------------------------
782 // CSocks4StateMachine
783 //------------------------------------------------------------------------------
785 CSocks4StateMachine::CSocks4StateMachine(
786 const CProxyData &proxyData,
787 CProxyCommand proxyCommand)
789 CProxyStateMachine(
790 wxString(wxT("Socks4")), SOCKS4_MAX_STATES, proxyData, proxyCommand)
792 m_process_state[0] = &CSocks4StateMachine::process_start;
793 m_state_name[0] = wxT("process_start");
794 m_process_state[1] = &CSocks4StateMachine::process_end;
795 m_state_name[1] = wxT("process_end");
796 m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
797 m_state_name[2] = wxT("process_send_command_request");
798 m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
799 m_state_name[3] = wxT("process_receive_command_reply");
800 m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
801 m_state_name[4] = wxT("process_process_command_reply");
804 void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
806 (this->*m_process_state[state])(entry);
807 #ifdef __DEBUG__
808 int n = 0;
810 switch (state) {
811 case SOCKS4_STATE_START:
812 case SOCKS4_STATE_END:
813 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
814 default:
815 n = 0;
816 break;
818 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
819 n = m_packetLenght;
820 break;
822 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
823 n = m_lastRead;
824 break;
827 if (entry) {
828 DumpMem(m_buffer, n, m_state_name[state], m_ok);
829 } else {
830 AddDebugLogLineN(logProxy,
831 wxString(wxT("wait state -- ")) << m_state_name[state]);
833 #endif // __DEBUG__
836 t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
838 // Default is stay in current state
839 t_sm_state ret = HandleEvent(event);
840 switch (GetState()) {
841 case SOCKS4_STATE_START:
842 if (m_isConnected && !m_isLost && CanSend()) {
843 ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
845 break;
847 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
848 if (m_ok) {
849 if (CanReceive()) {
850 ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
852 } else {
853 ret = SOCKS4_STATE_END;
855 break;
857 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
858 ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
859 break;
861 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
862 ret = SOCKS4_STATE_END;
863 break;
865 case SOCKS4_STATE_END:
866 default:
867 break;
870 return ret;
873 void CSocks4StateMachine::process_start(bool entry)
875 if (entry) {
876 } else {
880 void CSocks4StateMachine::process_end(bool)
882 ReactivateSocket();
885 void CSocks4StateMachine::process_send_command_request(bool entry)
887 if (entry) {
888 // Prepare the request command buffer
889 m_buffer[0] = SOCKS4_VERSION;
890 switch (m_proxyCommand) {
891 case PROXY_CMD_CONNECT:
892 m_buffer[1] = SOCKS4_CMD_CONNECT;
893 break;
895 case PROXY_CMD_BIND:
896 m_buffer[1] = SOCKS4_CMD_BIND;
897 break;
899 case PROXY_CMD_UDP_ASSOCIATE:
900 m_ok = false;
901 return;
902 break;
904 RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
905 // Special processing for SOCKS4a
906 switch (m_proxyData.m_proxyType) {
907 case PROXY_SOCKS4a:
908 PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
909 break;
910 case PROXY_SOCKS4:
911 default:
912 PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
913 break;
915 // Common processing for SOCKS4/SOCKS4a
916 unsigned int offsetUser = 8;
917 unsigned char lenUser = m_proxyData.m_userName.Len();
918 memcpy(m_buffer + offsetUser,
919 unicode2char(m_proxyData.m_userName), lenUser);
920 m_buffer[offsetUser + lenUser] = 0;
921 // Special processing for SOCKS4a
922 switch (m_proxyData.m_proxyType) {
923 case PROXY_SOCKS4a: {
924 unsigned int offsetDomain = offsetUser + lenUser + 1;
925 unsigned char lenDomain = m_peerAddress->Hostname().Len();
926 memcpy(m_buffer + offsetDomain,
927 unicode2char(m_peerAddress->Hostname()), lenDomain);
928 m_buffer[offsetDomain + lenDomain] = 0;
929 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
930 break;
932 case PROXY_SOCKS4:
933 default:
934 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
935 break;
937 // Send the command packet
938 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
942 void CSocks4StateMachine::process_receive_command_reply(bool entry)
944 if (entry) {
945 // Receive the server's reply
946 m_packetLenght = 8;
947 ProxyRead(*m_proxyClientSocket, m_buffer);
949 AddDummyEvent();
952 void CSocks4StateMachine::process_process_command_reply(bool entry)
954 if (entry) {
955 m_lastReply = m_buffer[1];
957 // Process the server's reply
958 m_ok = m_ok &&
959 m_buffer[0] == SOCKS4_REPLY_CODE &&
960 m_buffer[1] == SOCKS4_REPLY_GRANTED;
961 if (m_ok) {
962 // Read BND.PORT
963 const unsigned int portOffset = 2;
964 m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(
965 RawPeekUInt16( m_buffer+portOffset) ) );
966 // Read BND.ADDR
967 const unsigned int addrOffset = 4;
968 m_ok = m_ok &&
969 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
970 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
973 AddDummyEvent();
976 //------------------------------------------------------------------------------
977 // CHttpStateMachine
978 //------------------------------------------------------------------------------
980 CHttpStateMachine::CHttpStateMachine(
981 const CProxyData &proxyData,
982 CProxyCommand proxyCommand)
984 CProxyStateMachine(
985 wxString(wxT("Http")), HTTP_MAX_STATES, proxyData, proxyCommand)
987 m_process_state[0] = &CHttpStateMachine::process_start;
988 m_state_name[0] = wxT("process_start");
989 m_process_state[1] = &CHttpStateMachine::process_end;
990 m_state_name[1] = wxT("process_end");
991 m_process_state[2] = &CHttpStateMachine::process_send_command_request;
992 m_state_name[2] = wxT("process_send_command_request");
993 m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
994 m_state_name[3] = wxT("process_receive_command_reply");
995 m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
996 m_state_name[4] = wxT("process_process_command_reply");
999 void CHttpStateMachine::process_state(t_sm_state state, bool entry)
1001 (this->*m_process_state[state])(entry);
1002 #ifdef __DEBUG__
1003 int n = 0;
1005 switch (state) {
1006 case HTTP_STATE_START:
1007 case HTTP_STATE_END:
1008 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1009 default:
1010 n = 0;
1011 break;
1013 case HTTP_STATE_SEND_COMMAND_REQUEST:
1014 n = m_packetLenght;
1015 break;
1017 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1018 n = m_lastRead;
1019 break;
1022 if (entry) {
1023 DumpMem(m_buffer, n, m_state_name[state], m_ok);
1024 } else {
1025 AddDebugLogLineN(logProxy,
1026 wxString(wxT("wait state -- ")) << m_state_name[state]);
1028 #endif // __DEBUG__
1031 t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1033 // Default is stay in current state
1034 t_sm_state ret = HandleEvent(event);
1035 switch (GetState()) {
1036 case HTTP_STATE_START:
1037 if (m_isConnected && !m_isLost && CanSend()) {
1038 ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1040 break;
1042 case HTTP_STATE_SEND_COMMAND_REQUEST:
1043 if (m_ok) {
1044 if (CanReceive()) {
1045 ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1047 } else {
1048 ret = HTTP_STATE_END;
1050 break;
1052 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1053 ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1054 break;
1056 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1057 ret = HTTP_STATE_END;
1058 break;
1060 case HTTP_STATE_END:
1061 default:
1062 break;
1065 return ret;
1068 void CHttpStateMachine::process_start(bool entry)
1070 if (entry) {
1071 } else {
1075 void CHttpStateMachine::process_end(bool)
1077 ReactivateSocket();
1080 void CHttpStateMachine::process_send_command_request(bool entry)
1082 if (entry) {
1083 // Prepare the request command buffer
1084 wxString ip = m_peerAddress->IPAddress();
1085 uint16 port = m_peerAddress->Service();
1086 wxString userPass;
1087 wxString userPassEncoded;
1088 if (m_proxyData.m_enablePassword) {
1089 userPass = m_proxyData.m_userName + wxT(":") + m_proxyData.m_password;
1090 userPassEncoded =
1091 EncodeBase64(unicode2char(userPass), userPass.Length());
1093 wxString msg;
1095 switch (m_proxyCommand) {
1096 case PROXY_CMD_CONNECT:
1097 msg <<
1098 wxT("CONNECT ") << ip << wxT(":") << port << wxT(" HTTP/1.1\r\n") <<
1099 wxT("Host: ") << ip << wxT(":") << port << wxT("\r\n");
1100 if (m_proxyData.m_enablePassword) {
1101 msg <<
1102 wxT("Authorization: Basic ") << userPassEncoded << wxT("\r\n") <<
1103 wxT("Proxy-Authorization: Basic ") << userPassEncoded << wxT("\r\n");
1105 msg << wxT("\r\n");
1106 break;
1108 case PROXY_CMD_BIND:
1109 m_ok = false;
1110 break;
1112 case PROXY_CMD_UDP_ASSOCIATE:
1113 m_ok = false;
1114 return;
1115 break;
1117 // Send the command packet
1118 m_packetLenght = msg.Len();
1119 memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1120 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1124 void CHttpStateMachine::process_receive_command_reply(bool entry)
1126 if (entry) {
1127 // Receive the server's reply -- Use a large number, but don't
1128 // Expect to get it all. HTTP protocol does not have a fixed length.
1129 m_packetLenght = PROXY_BUFFER_SIZE;
1130 ProxyRead(*m_proxyClientSocket, m_buffer);
1132 AddDummyEvent();
1136 * HTTP Proxy server response should be something like:
1137 * "HTTP/1.1 200 Connection established\r\n\r\n"
1138 * but that may vary. The important thing is the "200"
1139 * code, that means success.
1141 static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1142 static const int HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
1143 void CHttpStateMachine::process_process_command_reply(bool entry)
1145 if (entry) {
1146 // The position of the first space in the buffer
1147 int i = 8;
1148 while (m_buffer[i] == ' ') {
1149 i++;
1151 // Process the server's reply
1152 m_ok = !memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1153 !memcmp(m_buffer + i, "200", 3);
1155 AddDummyEvent();
1158 //------------------------------------------------------------------------------
1159 // CProxySocket
1160 //------------------------------------------------------------------------------
1162 CProxySocket::CProxySocket(
1163 wxSocketFlags flags,
1164 const CProxyData *proxyData,
1165 CProxyCommand proxyCommand,
1166 CDatagramSocketProxy *udpSocket)
1168 wxSocketClient(flags),
1169 m_proxyStateMachine(NULL),
1170 m_udpSocket(udpSocket),
1171 m_socketEventHandler(NULL),
1172 m_socketEventHandlerId(0),
1173 m_savedSocketEventHandler(NULL),
1174 m_savedSocketEventHandlerId(0)
1176 SetProxyData(proxyData);
1177 if (m_useProxy) {
1178 switch (m_proxyData.m_proxyType) {
1179 case PROXY_NONE:
1180 break;
1182 case PROXY_SOCKS5:
1183 m_proxyStateMachine =
1184 new CSocks5StateMachine(*proxyData, proxyCommand);
1185 break;
1187 case PROXY_SOCKS4:
1188 case PROXY_SOCKS4a:
1189 m_proxyStateMachine =
1190 new CSocks4StateMachine(*proxyData, proxyCommand);
1191 break;
1193 case PROXY_HTTP:
1194 m_proxyStateMachine =
1195 new CHttpStateMachine(*proxyData, proxyCommand);
1196 break;
1198 default:
1199 break;
1204 CProxySocket::~CProxySocket()
1206 delete m_proxyStateMachine;
1209 void CProxySocket::SetProxyData(const CProxyData *proxyData)
1211 m_useProxy = proxyData != NULL && proxyData->m_proxyEnable;
1212 if (proxyData) {
1213 m_proxyData = *proxyData;
1214 m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1215 m_proxyAddress.Service(m_proxyData.m_proxyPort);
1216 } else {
1217 m_proxyData.Clear();
1221 bool CProxySocket::Start(const wxIPaddress &peerAddress)
1223 SaveState();
1224 // Important note! SaveState()/RestoreState() DO NOT save/restore
1225 // the event handler. The method SaveEventHandler() has been created
1226 // for that.
1227 SaveEventHandler();
1228 SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1229 SetNotify(
1230 wxSOCKET_CONNECTION_FLAG |
1231 wxSOCKET_INPUT_FLAG |
1232 wxSOCKET_OUTPUT_FLAG |
1233 wxSOCKET_LOST_FLAG);
1234 Notify(true);
1235 Connect(m_proxyAddress, false);
1236 SetFlags(wxSOCKET_NONE);
1237 bool ok = m_proxyStateMachine->Start(peerAddress, this);
1239 return ok;
1242 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1244 bool ret = false;
1246 switch (m_proxyData.m_proxyType) {
1247 case PROXY_NONE:
1248 ret = false;
1249 break;
1251 case PROXY_SOCKS5:
1252 ret = proxyCommand == PROXY_CMD_CONNECT ||
1253 proxyCommand == PROXY_CMD_BIND ||
1254 proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1255 break;
1257 case PROXY_SOCKS4:
1258 case PROXY_SOCKS4a:
1259 ret = proxyCommand == PROXY_CMD_CONNECT ||
1260 proxyCommand == PROXY_CMD_BIND;
1261 break;
1263 case PROXY_HTTP:
1264 ret = proxyCommand == PROXY_CMD_CONNECT;
1265 break;
1268 return ret;
1271 //------------------------------------------------------------------------------
1272 // CSocketClientProxy
1273 //------------------------------------------------------------------------------
1275 CSocketClientProxy::CSocketClientProxy(
1276 wxSocketFlags flags,
1277 const CProxyData *proxyData)
1279 CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1283 bool CSocketClientProxy::Connect(wxIPaddress &address, bool wait)
1285 wxMutexLocker lock(m_socketLocker);
1286 bool ok;
1288 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1289 ok = Start(address);
1290 } else {
1291 ok = wxSocketClient::Connect(address, wait);
1294 return ok;
1297 CSocketClientProxy& CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1299 wxMutexLocker lock(m_socketLocker);
1300 CProxySocket::Read(buffer, nbytes);
1302 return *this;
1306 CSocketClientProxy& CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1308 wxMutexLocker lock(m_socketLocker);
1309 CProxySocket::Write(buffer, nbytes);
1311 return *this;
1314 //------------------------------------------------------------------------------
1315 // CSocketServerProxy
1316 //------------------------------------------------------------------------------
1318 CSocketServerProxy::CSocketServerProxy(
1319 wxIPaddress &address,
1320 wxSocketFlags flags,
1321 const CProxyData *)
1323 wxSocketServer(address, flags)
1325 /* Maybe some day when socks6 is out... :) */
1328 CSocketServerProxy& CSocketServerProxy::Read(void *buffer, wxUint32 nbytes)
1330 wxMutexLocker lock(m_socketLocker);
1331 wxSocketServer::Read(buffer, nbytes);
1333 return *this;
1336 CSocketServerProxy& CSocketServerProxy::Write(const void *buffer, wxUint32 nbytes)
1338 wxMutexLocker lock(m_socketLocker);
1339 wxSocketServer::Write(buffer, nbytes);
1341 return *this;
1344 //------------------------------------------------------------------------------
1345 // CDatagramSocketProxy
1346 //------------------------------------------------------------------------------
1348 CDatagramSocketProxy::CDatagramSocketProxy(
1349 wxIPaddress &address, wxSocketFlags flags, const CProxyData *proxyData)
1351 wxDatagramSocket(address, flags),
1352 m_proxyTCPSocket(wxSOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1354 m_udpSocketOk = false;
1355 if ( m_proxyTCPSocket.GetUseProxy() &&
1356 m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1357 m_proxyTCPSocket.Start(address);
1358 } else {
1360 m_lastUDPOperation = UDP_OPERATION_NONE;
1363 CDatagramSocketProxy::~CDatagramSocketProxy()
1365 // From RFC-1928:
1366 // "A UDP association terminates when the TCP connection that the
1367 // UDP ASSOCIATE request arrived terminates."
1370 wxDatagramSocket &CDatagramSocketProxy::RecvFrom(
1371 wxSockAddress &addr, void* buf, wxUint32 nBytes )
1373 wxMutexLocker lock(m_socketLocker);
1374 m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1375 if (m_proxyTCPSocket.GetUseProxy()) {
1376 if (m_udpSocketOk) {
1377 char *bufUDP = NULL;
1378 if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1379 bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1380 } else {
1381 bufUDP = m_proxyTCPSocket.GetBuffer();
1383 wxDatagramSocket::RecvFrom(
1384 m_proxyTCPSocket.GetProxyBoundAddress(),
1385 bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1386 unsigned int offset;
1387 switch (m_proxyTCPSocket.GetBuffer()[3]) {
1388 case SOCKS5_ATYP_IPV4_ADDRESS: {
1389 offset = PROXY_UDP_OVERHEAD_IPV4;
1390 try {
1391 amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1392 a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1393 a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) ) );
1394 } catch (const std::bad_cast& WXUNUSED(e)) {
1395 AddDebugLogLineN(logProxy,
1396 wxT("(2)bad_cast exception!"));
1397 wxFAIL;
1400 break;
1402 case SOCKS5_ATYP_DOMAINNAME:
1403 offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1404 break;
1406 case SOCKS5_ATYP_IPV6_ADDRESS:
1407 offset = PROXY_UDP_OVERHEAD_IPV6;
1408 break;
1410 default:
1411 /* Error! */
1412 offset = 0;
1413 break;
1415 memcpy(buf, bufUDP + offset, nBytes);
1416 // Uncomment here to see the buffer contents on console
1417 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1419 /* Only delete buffer if it was dynamically created */
1420 if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1421 /* We should use a fixed buffer to avoid
1422 * new/delete it all the time.
1423 * I need an upper bound */
1424 delete bufUDP;
1426 /* There is still one problem pending, fragmentation.
1427 * Either we support it or we have to drop fragmented
1428 * messages. I vote for drop :)
1431 } else {
1432 wxDatagramSocket::RecvFrom(addr, buf, nBytes);
1435 return *this;
1438 wxDatagramSocket &CDatagramSocketProxy::SendTo(
1439 wxIPaddress &addr, const void* buf, wxUint32 nBytes )
1441 wxMutexLocker lock(m_socketLocker);
1442 m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1443 m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1444 if (m_proxyTCPSocket.GetUseProxy()) {
1445 if (m_udpSocketOk) {
1446 m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV; // Reserved
1447 m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV; // Reserved
1448 m_proxyTCPSocket.GetBuffer()[2] = 0; // FRAG
1449 m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1450 PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1451 RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
1452 memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1453 nBytes += PROXY_UDP_OVERHEAD_IPV4;
1454 wxDatagramSocket::SendTo(
1455 m_proxyTCPSocket.GetProxyBoundAddress(),
1456 m_proxyTCPSocket.GetBuffer(), nBytes);
1457 // Uncomment here to see the buffer contents on console
1458 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1460 } else {
1461 wxDatagramSocket::SendTo(addr, buf, nBytes);
1464 return *this;
1467 wxUint32 CDatagramSocketProxy::LastCount(void) const
1469 wxUint32 ret;
1471 if (m_proxyTCPSocket.GetUseProxy()) {
1472 switch (m_lastUDPOperation) {
1473 case UDP_OPERATION_RECV_FROM:
1474 case UDP_OPERATION_SEND_TO:
1475 ret = Ok() ? wxDatagramSocket::LastCount() - m_lastUDPOverhead : 0;
1476 break;
1478 case UDP_OPERATION_NONE:
1479 default:
1480 ret = 0;
1481 break;
1484 } else {
1485 ret = wxDatagramSocket::LastCount();
1488 return ret;
1491 #endif // CLIENT_GUI
1493 /******************************************************************************/
1494 // File_checked_for_headers