Upstream tarball 20080405
[amule.git] / src / Proxy.cpp
blob8f549b80a01bb8a7eec9fb522c074a892fe4d481
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 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 AddDebugLogLineM */
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 AddDebugLogLineM(false, logProxy, wxT("(1)bad_cast exception!"));
178 wxASSERT(false);
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 AddDebugLogLineM(false, logProxy, wxT("Connection event"));
194 m_isConnected = true;
195 break;
197 case wxSOCKET_INPUT:
198 AddDebugLogLineM(false, logProxy, wxT("Input event"));
199 m_canReceive = true;
200 break;
202 case wxSOCKET_OUTPUT:
203 AddDebugLogLineM(false, logProxy, wxT("Output event"));
204 m_canSend = true;
205 break;
207 case wxSOCKET_LOST:
208 AddDebugLogLineM(false, logProxy, wxT("Lost connection event"));
209 m_isLost = true;
210 m_ok = false;
211 break;
213 default:
214 AddDebugLogLineM(false, 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 an 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 //------------------------------------------------------------------------------
323 // CSocks5StateMachine
324 //------------------------------------------------------------------------------
327 * The state machine constructor must initialize the array of pointer to member
328 * functions. Don't waste you time trying to statically initialize this, pointer
329 * to member functions require an object to operate on, so this array must be
330 * initialized at run time.
332 CSocks5StateMachine::CSocks5StateMachine(
333 const CProxyData &proxyData,
334 CProxyCommand proxyCommand)
336 CProxyStateMachine(
337 wxString(wxT("Socks5")), SOCKS5_MAX_STATES, proxyData, proxyCommand)
339 m_process_state[ 0] = &CSocks5StateMachine::process_start;
340 m_state_name[ 0] = wxT("process_start");
341 m_process_state[ 1] = &CSocks5StateMachine::process_end;
342 m_state_name[ 1] = wxT("process_end");
343 m_process_state[ 2] = &CSocks5StateMachine::process_send_query_authentication_method;
344 m_state_name[ 2] = wxT("process_send_query_authentication_method");
345 m_process_state[ 3] = &CSocks5StateMachine::process_receive_authentication_method;
346 m_state_name[ 3] = wxT("process_receive_authentication_method");
347 m_process_state[ 4] = &CSocks5StateMachine::process_process_authentication_method;
348 m_state_name[ 4] = wxT("process_process_authentication_method");
349 m_process_state[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi;
350 m_state_name[ 5] = wxT("process_send_authentication_gssapi");
351 m_process_state[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi;
352 m_state_name[ 6] = wxT("process_receive_authentication_gssapi");
353 m_process_state[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi;
354 m_state_name[ 7] = wxT("process_process_authentication_gssapi");
355 m_process_state[ 8] = &CSocks5StateMachine::process_send_authentication_username_password;
356 m_state_name[ 8] = wxT("process_send_authentication_username_password");
357 m_process_state[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password;
358 m_state_name[ 9] = wxT("process_receive_authentication_username_password");
359 m_process_state[10] = &CSocks5StateMachine::process_process_authentication_username_password;
360 m_state_name[10] = wxT("process_process_authentication_username_password");
361 m_process_state[11] = &CSocks5StateMachine::process_send_command_request;
362 m_state_name[11] = wxT("process_send_command_request");
363 m_process_state[12] = &CSocks5StateMachine::process_receive_command_reply;
364 m_state_name[12] = wxT("process_receive_command_reply");
365 m_process_state[13] = &CSocks5StateMachine::process_process_command_reply;
366 m_state_name[13] = wxT("process_process_command_reply");
369 void CSocks5StateMachine::process_state(t_sm_state state, bool entry)
371 /* Ok, the syntax is terrible, but this is correct. This is a
372 * pointer to a member function. No C equivalent for that. */
373 (this->*m_process_state[state])(entry);
374 #ifdef __DEBUG__
375 int n = 0;
377 switch (state) {
378 case SOCKS5_STATE_START:
379 case SOCKS5_STATE_END:
380 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
381 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
382 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
383 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
384 default:
385 n = 0;
386 break;
388 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
389 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
390 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
391 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
392 n = m_packetLenght;
393 break;
395 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
396 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
397 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
398 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
399 n = m_lastRead;
400 break;
403 if (entry) {
404 DumpMem(m_buffer, n, m_state_name[state], m_ok);
405 } else {
406 AddDebugLogLineM(false, logProxy,
407 wxString(wxT("wait state -- ")) << m_state_name[state]);
409 #endif // __DEBUG__
413 * Code this such that the next state is only entered when it is able to
414 * perform the operation (read or write). State processing will assume
415 * that it can read or write upon entry of the state. This is done using
416 * CanSend() and CanReceive(). On daemon, these functions always return
417 * true, because sockets are blocking.
419 t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
421 // Default is stay in current state
422 t_sm_state ret = HandleEvent(event);
423 switch (GetState()) {
424 case SOCKS5_STATE_START:
425 if (m_isConnected && !m_isLost && CanSend()) {
426 ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
428 break;
430 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
431 if (CanReceive()) {
432 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
434 break;
436 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
437 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
438 break;
440 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
441 if (m_ok) {
442 if (CanSend()) {
443 switch (m_lastReply) {
444 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
445 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
446 break;
448 case SOCKS5_AUTH_METHOD_GSSAPI:
449 ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
450 break;
452 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
453 ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
454 break;
456 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
457 default:
458 ret = SOCKS5_STATE_END;
459 break;
461 } else {
462 AddDebugLogLineM(false, logProxy, wxT("Cant send"));
464 } else {
465 ret = SOCKS5_STATE_END;
467 break;
469 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
470 if (m_ok) {
471 if (CanReceive()) {
472 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
474 } else {
475 ret = SOCKS5_STATE_END;
477 break;
479 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
480 if (m_ok) {
481 if (CanReceive()) {
482 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
484 } else {
485 ret = SOCKS5_STATE_END;
487 break;
489 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
490 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
491 break;
493 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
494 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
495 break;
497 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
498 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
499 if (m_ok) {
500 if (CanSend()) {
501 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
503 } else {
504 ret = SOCKS5_STATE_END;
506 break;
508 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
509 if (m_ok) {
510 if (CanReceive()) {
511 ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
513 } else {
514 ret = SOCKS5_STATE_END;
516 break;
518 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
519 ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
520 break;
522 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
523 ret = SOCKS5_STATE_END;
524 break;
526 case SOCKS5_STATE_END:
527 default:
528 break;
531 return ret;
535 * So, this is how you do it: the state machine is clocked by the events
536 * that happen inside the event handler. You can add a dummy event whenever
537 * you see that the system will not generate an event. But don't add dummy
538 * events before reads, reads should only be performed after input events.
540 * Maybe it makes sense to add a dummy event before a read if there is no
541 * state change (wait state).
543 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
544 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
545 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
546 * event will be generated. If you feel you will need more clocks than these, use
547 * AddDummyEvent(), but I suggest you review your state machine design first.
549 void CSocks5StateMachine::process_start(bool entry)
551 if (entry) {
552 } else {
556 void CSocks5StateMachine::process_end(bool)
558 ReactivateSocket();
561 void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
563 if (entry) {
564 // Prepare the authentication method negotiation packet
565 m_buffer[0] = SOCKS5_VERSION;
566 m_buffer[1] = 2; // Number of supported methods
567 //m_buffer[1] = 3; // Number of supported methods
568 m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
569 m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
570 m_buffer[4] = SOCKS5_AUTH_METHOD_GSSAPI;
571 m_packetLenght = 4;
572 //m_packetLenght = 5;
574 // Send the authentication method negotiation packet
575 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
579 void CSocks5StateMachine::process_receive_authentication_method(bool entry)
581 if (entry) {
582 // Receive the method selection message
583 m_packetLenght = 2;
584 ProxyRead(*m_proxyClientSocket, m_buffer);
586 /* This is added because there will be no more input events. If the
587 * world was a nice place, we could think about joining the
588 * process_receive and the process_process states here, but some day
589 * we might have to deal with the fact that the i/o operation has been
590 * incomplete, and that we must finish our job the next time we enter
591 * this state. */
592 AddDummyEvent();
595 void CSocks5StateMachine::process_process_authentication_method(bool entry)
597 if (entry) {
598 m_lastReply = m_buffer[1];
599 m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
601 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
602 * once when you connect the socket, and after that, only after a
603 * wxSOCKET_WOULDBLOCK error happens. */
604 AddDummyEvent();
607 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
609 // TODO or not TODO? That is the question...
610 m_ok = false;
613 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
615 AddDummyEvent();
618 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
620 AddDummyEvent();
623 void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
625 if (entry) {
626 unsigned char lenUser = m_proxyData.m_userName.Len();
627 unsigned char lenPassword = m_proxyData.m_password.Len();
628 m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
629 unsigned int offsetUser = 2;
630 unsigned int offsetPassword = offsetUser + lenUser + 1;
632 // Prepare username/password buffer
633 m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
634 m_buffer[offsetUser-1] = lenUser;
635 memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
636 lenUser);
637 m_buffer[offsetPassword-1] = lenPassword;
638 memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
639 lenPassword);
641 // Send the username/password packet
642 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
646 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
648 if (entry) {
649 // Receive the server's authentication response
650 m_packetLenght = 2;
651 ProxyRead(*m_proxyClientSocket, m_buffer);
653 AddDummyEvent();
656 void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
658 if (entry) {
659 // Process the server's reply
660 m_lastReply = m_buffer[1];
661 m_ok = m_ok &&
662 m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
663 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
665 AddDummyEvent();
668 void CSocks5StateMachine::process_send_command_request(bool entry)
670 if (entry) {
671 // Prepare the request command buffer
672 m_buffer[0] = SOCKS5_VERSION;
673 switch (m_proxyCommand) {
674 case PROXY_CMD_CONNECT:
675 m_buffer[1] = SOCKS5_CMD_CONNECT;
676 break;
678 case PROXY_CMD_BIND:
679 m_buffer[1] = SOCKS5_CMD_BIND;
680 break;
682 case PROXY_CMD_UDP_ASSOCIATE:
683 m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
684 break;
686 m_buffer[2] = SOCKS5_RSV;
687 m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
688 PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
689 RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
691 // Send the command packet
692 m_packetLenght = 10;
693 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
697 void CSocks5StateMachine::process_receive_command_reply(bool entry)
699 if (entry) {
700 // The minimum number of bytes to read is 10 in the case of
701 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
702 m_packetLenght = 10;
703 ProxyRead(*m_proxyClientSocket, m_buffer);
705 AddDummyEvent();
708 void CSocks5StateMachine::process_process_command_reply(bool entry)
710 if (entry) {
711 m_lastReply = m_buffer[1];
712 unsigned char addressType = m_buffer[3];
713 // Process the server's reply
714 m_ok = m_ok &&
715 m_buffer[0] == SOCKS5_VERSION &&
716 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
717 if (m_ok) {
718 // Read BND.ADDR
719 unsigned int portOffset = 0;
720 switch(addressType) {
721 case SOCKS5_ATYP_IPV4_ADDRESS:
723 const unsigned int addrOffset = 4;
724 portOffset = 8;
725 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
726 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
727 break;
729 case SOCKS5_ATYP_DOMAINNAME:
731 // Read the domain name
732 const unsigned int addrOffset = 5;
733 portOffset = 10 + m_buffer[4];
734 char c = m_buffer[portOffset];
735 m_buffer[portOffset] = 0;
736 m_proxyBoundAddressIPV4.Hostname(
737 char2unicode(m_buffer+addrOffset));
738 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
739 m_buffer[portOffset] = c;
740 break;
742 case SOCKS5_ATYP_IPV6_ADDRESS:
744 portOffset = 20;
745 // TODO
746 // IPV6 not yet implemented in wx
747 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
748 // *((uint128 *)(m_buffer+addrOffset)) ));
749 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
750 m_ok = false;
751 break;
754 // Set the packet length at last
755 m_packetLenght = portOffset + 2;
756 // Read BND.PORT
757 m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) ) );
760 AddDummyEvent();
763 //------------------------------------------------------------------------------
764 // CSocks4StateMachine
765 //------------------------------------------------------------------------------
767 CSocks4StateMachine::CSocks4StateMachine(
768 const CProxyData &proxyData,
769 CProxyCommand proxyCommand)
771 CProxyStateMachine(
772 wxString(wxT("Socks4")), SOCKS4_MAX_STATES, proxyData, proxyCommand)
774 m_process_state[0] = &CSocks4StateMachine::process_start;
775 m_state_name[0] = wxT("process_start");
776 m_process_state[1] = &CSocks4StateMachine::process_end;
777 m_state_name[1] = wxT("process_end");
778 m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
779 m_state_name[2] = wxT("process_send_command_request");
780 m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
781 m_state_name[3] = wxT("process_receive_command_reply");
782 m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
783 m_state_name[4] = wxT("process_process_command_reply");
786 void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
788 (this->*m_process_state[state])(entry);
789 #ifdef __DEBUG__
790 int n = 0;
792 switch (state) {
793 case SOCKS4_STATE_START:
794 case SOCKS4_STATE_END:
795 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
796 default:
797 n = 0;
798 break;
800 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
801 n = m_packetLenght;
802 break;
804 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
805 n = m_lastRead;
806 break;
809 if (entry) {
810 DumpMem(m_buffer, n, m_state_name[state], m_ok);
811 } else {
812 AddDebugLogLineM(false, logProxy,
813 wxString(wxT("wait state -- ")) << m_state_name[state]);
815 #endif // __DEBUG__
818 t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
820 // Default is stay in current state
821 t_sm_state ret = HandleEvent(event);
822 switch (GetState()) {
823 case SOCKS4_STATE_START:
824 if (m_isConnected && !m_isLost && CanSend()) {
825 ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
827 break;
829 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
830 if (m_ok) {
831 if (CanReceive()) {
832 ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
834 } else {
835 ret = SOCKS4_STATE_END;
837 break;
839 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
840 ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
841 break;
843 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
844 ret = SOCKS4_STATE_END;
845 break;
847 case SOCKS4_STATE_END:
848 default:
849 break;
852 return ret;
855 void CSocks4StateMachine::process_start(bool entry)
857 if (entry) {
858 } else {
862 void CSocks4StateMachine::process_end(bool)
864 ReactivateSocket();
867 void CSocks4StateMachine::process_send_command_request(bool entry)
869 if (entry) {
870 // Prepare the request command buffer
871 m_buffer[0] = SOCKS4_VERSION;
872 switch (m_proxyCommand) {
873 case PROXY_CMD_CONNECT:
874 m_buffer[1] = SOCKS4_CMD_CONNECT;
875 break;
877 case PROXY_CMD_BIND:
878 m_buffer[1] = SOCKS4_CMD_BIND;
879 break;
881 case PROXY_CMD_UDP_ASSOCIATE:
882 m_ok = false;
883 return;
884 break;
886 RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
887 // Special processing for SOCKS4a
888 switch (m_proxyData.m_proxyType) {
889 case PROXY_SOCKS4a:
890 PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
891 break;
892 case PROXY_SOCKS4:
893 default:
894 PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
895 break;
897 // Common processing for SOCKS4/SOCKS4a
898 unsigned int offsetUser = 8;
899 unsigned char lenUser = m_proxyData.m_userName.Len();
900 memcpy(m_buffer + offsetUser,
901 unicode2char(m_proxyData.m_userName), lenUser);
902 m_buffer[offsetUser + lenUser] = 0;
903 // Special processing for SOCKS4a
904 switch (m_proxyData.m_proxyType) {
905 case PROXY_SOCKS4a: {
906 unsigned int offsetDomain = offsetUser + lenUser + 1;
907 unsigned char lenDomain = m_peerAddress->Hostname().Len();
908 memcpy(m_buffer + offsetDomain,
909 unicode2char(m_peerAddress->Hostname()), lenDomain);
910 m_buffer[offsetDomain + lenDomain] = 0;
911 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
912 break;
914 case PROXY_SOCKS4:
915 default:
916 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
917 break;
919 // Send the command packet
920 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
924 void CSocks4StateMachine::process_receive_command_reply(bool entry)
926 if (entry) {
927 // Receive the server's reply
928 m_packetLenght = 8;
929 ProxyRead(*m_proxyClientSocket, m_buffer);
931 AddDummyEvent();
934 void CSocks4StateMachine::process_process_command_reply(bool entry)
936 if (entry) {
937 m_lastReply = m_buffer[1];
939 // Process the server's reply
940 m_ok = m_ok &&
941 m_buffer[0] == SOCKS4_REPLY_CODE &&
942 m_buffer[1] == SOCKS4_REPLY_GRANTED;
943 if (m_ok) {
944 // Read BND.PORT
945 const unsigned int portOffset = 2;
946 m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(
947 RawPeekUInt16( m_buffer+portOffset) ) );
948 // Read BND.ADDR
949 const unsigned int addrOffset = 4;
950 m_ok = m_ok &&
951 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
952 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
955 AddDummyEvent();
958 //------------------------------------------------------------------------------
959 // CHttpStateMachine
960 //------------------------------------------------------------------------------
962 CHttpStateMachine::CHttpStateMachine(
963 const CProxyData &proxyData,
964 CProxyCommand proxyCommand)
966 CProxyStateMachine(
967 wxString(wxT("Http")), HTTP_MAX_STATES, proxyData, proxyCommand)
969 m_process_state[0] = &CHttpStateMachine::process_start;
970 m_state_name[0] = wxT("process_start");
971 m_process_state[1] = &CHttpStateMachine::process_end;
972 m_state_name[1] = wxT("process_end");
973 m_process_state[2] = &CHttpStateMachine::process_send_command_request;
974 m_state_name[2] = wxT("process_send_command_request");
975 m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
976 m_state_name[3] = wxT("process_receive_command_reply");
977 m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
978 m_state_name[4] = wxT("process_process_command_reply");
981 void CHttpStateMachine::process_state(t_sm_state state, bool entry)
983 (this->*m_process_state[state])(entry);
984 #ifdef __DEBUG__
985 int n = 0;
987 switch (state) {
988 case HTTP_STATE_START:
989 case HTTP_STATE_END:
990 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
991 default:
992 n = 0;
993 break;
995 case HTTP_STATE_SEND_COMMAND_REQUEST:
996 n = m_packetLenght;
997 break;
999 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1000 n = m_lastRead;
1001 break;
1004 if (entry) {
1005 DumpMem(m_buffer, n, m_state_name[state], m_ok);
1006 } else {
1007 AddDebugLogLineM(false, logProxy,
1008 wxString(wxT("wait state -- ")) << m_state_name[state]);
1010 #endif // __DEBUG__
1013 t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1015 // Default is stay in current state
1016 t_sm_state ret = HandleEvent(event);
1017 switch (GetState()) {
1018 case HTTP_STATE_START:
1019 if (m_isConnected && !m_isLost && CanSend()) {
1020 ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1022 break;
1024 case HTTP_STATE_SEND_COMMAND_REQUEST:
1025 if (m_ok) {
1026 if (CanReceive()) {
1027 ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1029 } else {
1030 ret = HTTP_STATE_END;
1032 break;
1034 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1035 ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1036 break;
1038 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1039 ret = HTTP_STATE_END;
1040 break;
1042 case HTTP_STATE_END:
1043 default:
1044 break;
1047 return ret;
1050 void CHttpStateMachine::process_start(bool entry)
1052 if (entry) {
1053 } else {
1057 void CHttpStateMachine::process_end(bool)
1059 ReactivateSocket();
1062 void CHttpStateMachine::process_send_command_request(bool entry)
1064 if (entry) {
1065 // Prepare the request command buffer
1066 wxString ip = m_peerAddress->IPAddress();
1067 uint16 port = m_peerAddress->Service();
1068 wxString userPass;
1069 wxString userPassEncoded;
1070 if (m_proxyData.m_enablePassword) {
1071 userPass = m_proxyData.m_userName + wxT(":") + m_proxyData.m_password;
1072 userPassEncoded =
1073 EncodeBase64(unicode2char(userPass), PROXY_BUFFER_SIZE);
1075 wxString msg;
1077 switch (m_proxyCommand) {
1078 case PROXY_CMD_CONNECT:
1079 msg <<
1080 wxT("CONNECT ") << ip << wxT(":") << port << wxT(" HTTP/1.1\r\n") <<
1081 wxT("Host: ") << ip << wxT(":") << port << wxT("\r\n");
1082 if (m_proxyData.m_enablePassword) {
1083 msg <<
1084 wxT("Authorization: Basic ") << userPassEncoded << wxT("\r\n") <<
1085 wxT("Proxy-Authorization: Basic ") << userPassEncoded << wxT("\r\n");
1086 } else {
1087 msg << wxT("\r\n");
1089 break;
1091 case PROXY_CMD_BIND:
1092 m_ok = false;
1093 break;
1095 case PROXY_CMD_UDP_ASSOCIATE:
1096 m_ok = false;
1097 return;
1098 break;
1100 // Send the command packet
1101 m_packetLenght = msg.Len();
1102 memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1103 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1107 void CHttpStateMachine::process_receive_command_reply(bool entry)
1109 if (entry) {
1110 // Receive the server's reply -- Use a large number, but don't
1111 // Expect to get it all. HTTP protocol does not have a fixed length.
1112 m_packetLenght = PROXY_BUFFER_SIZE;
1113 ProxyRead(*m_proxyClientSocket, m_buffer);
1115 AddDummyEvent();
1119 * HTTP Proxy server response should be something like:
1120 * "HTTP/1.1 200 Connection established\r\n\r\n"
1121 * but that may vary. The important thing is the "200"
1122 * code, that means success.
1124 static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1125 static const int HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
1126 void CHttpStateMachine::process_process_command_reply(bool entry)
1128 if (entry) {
1129 // The position of the first space in the buffer
1130 int i = 8;
1131 while (m_buffer[i] == ' ') {
1132 i++;
1134 // Process the server's reply
1135 m_ok = !memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1136 !memcmp(m_buffer + i, "200", 3);
1138 AddDummyEvent();
1141 //------------------------------------------------------------------------------
1142 // CProxySocket
1143 //------------------------------------------------------------------------------
1145 CProxySocket::CProxySocket(
1146 wxSocketFlags flags,
1147 const CProxyData *proxyData,
1148 CProxyCommand proxyCommand,
1149 CDatagramSocketProxy *udpSocket)
1151 wxSocketClient(flags),
1152 m_proxyStateMachine(NULL),
1153 m_udpSocket(udpSocket),
1154 m_socketEventHandler(NULL),
1155 m_socketEventHandlerId(0),
1156 m_savedSocketEventHandler(NULL),
1157 m_savedSocketEventHandlerId(0)
1159 SetProxyData(proxyData);
1160 if (m_useProxy) {
1161 switch (m_proxyData.m_proxyType) {
1162 case PROXY_NONE:
1163 break;
1165 case PROXY_SOCKS5:
1166 m_proxyStateMachine =
1167 new CSocks5StateMachine(*proxyData, proxyCommand);
1168 break;
1170 case PROXY_SOCKS4:
1171 case PROXY_SOCKS4a:
1172 m_proxyStateMachine =
1173 new CSocks4StateMachine(*proxyData, proxyCommand);
1174 break;
1176 case PROXY_HTTP:
1177 m_proxyStateMachine =
1178 new CHttpStateMachine(*proxyData, proxyCommand);
1179 break;
1181 default:
1182 break;
1187 CProxySocket::~CProxySocket()
1189 delete m_proxyStateMachine;
1192 void CProxySocket::SetProxyData(const CProxyData *proxyData)
1194 m_useProxy = proxyData != NULL && proxyData->m_proxyEnable;
1195 if (proxyData) {
1196 m_proxyData = *proxyData;
1197 m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1198 m_proxyAddress.Service(m_proxyData.m_proxyPort);
1199 } else {
1200 m_proxyData.Clear();
1204 bool CProxySocket::Start(const wxIPaddress &peerAddress)
1206 SaveState();
1207 // Important note! SaveState()/RestoreState() DO NOT save/restore
1208 // the event handler. The method SaveEventHandler() has been created
1209 // for that.
1210 SaveEventHandler();
1211 SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1212 SetNotify(
1213 wxSOCKET_CONNECTION_FLAG |
1214 wxSOCKET_INPUT_FLAG |
1215 wxSOCKET_OUTPUT_FLAG |
1216 wxSOCKET_LOST_FLAG);
1217 Notify(true);
1218 Connect(m_proxyAddress, false);
1219 SetFlags(wxSOCKET_NONE);
1220 bool ok = m_proxyStateMachine->Start(peerAddress, this);
1222 return ok;
1225 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1227 bool ret = false;
1229 switch (m_proxyData.m_proxyType) {
1230 case PROXY_NONE:
1231 ret = false;
1232 break;
1234 case PROXY_SOCKS5:
1235 ret = proxyCommand == PROXY_CMD_CONNECT ||
1236 proxyCommand == PROXY_CMD_BIND ||
1237 proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1238 break;
1240 case PROXY_SOCKS4:
1241 case PROXY_SOCKS4a:
1242 ret = proxyCommand == PROXY_CMD_CONNECT ||
1243 proxyCommand == PROXY_CMD_BIND;
1244 break;
1246 case PROXY_HTTP:
1247 ret = proxyCommand == PROXY_CMD_CONNECT;
1248 break;
1251 return ret;
1254 //------------------------------------------------------------------------------
1255 // CSocketClientProxy
1256 //------------------------------------------------------------------------------
1258 CSocketClientProxy::CSocketClientProxy(
1259 wxSocketFlags flags,
1260 const CProxyData *proxyData)
1262 CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1266 bool CSocketClientProxy::Connect(wxIPaddress &address, bool wait)
1268 wxMutexLocker lock(m_socketLocker);
1269 bool ok;
1271 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1272 ok = Start(address);
1273 } else {
1274 ok = wxSocketClient::Connect(address, wait);
1277 return ok;
1280 CSocketClientProxy& CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1282 wxMutexLocker lock(m_socketLocker);
1283 CProxySocket::Read(buffer, nbytes);
1285 return *this;
1289 CSocketClientProxy& CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1291 wxMutexLocker lock(m_socketLocker);
1292 CProxySocket::Write(buffer, nbytes);
1294 return *this;
1297 //------------------------------------------------------------------------------
1298 // CSocketServerProxy
1299 //------------------------------------------------------------------------------
1301 CSocketServerProxy::CSocketServerProxy(
1302 wxIPaddress &address,
1303 wxSocketFlags flags,
1304 const CProxyData *)
1306 wxSocketServer(address, flags)
1308 /* Maybe some day when socks6 is out... :) */
1311 CSocketServerProxy& CSocketServerProxy::Read(void *buffer, wxUint32 nbytes)
1313 wxMutexLocker lock(m_socketLocker);
1314 wxSocketServer::Read(buffer, nbytes);
1316 return *this;
1319 CSocketServerProxy& CSocketServerProxy::Write(const void *buffer, wxUint32 nbytes)
1321 wxMutexLocker lock(m_socketLocker);
1322 wxSocketServer::Write(buffer, nbytes);
1324 return *this;
1327 //------------------------------------------------------------------------------
1328 // CDatagramSocketProxy
1329 //------------------------------------------------------------------------------
1331 CDatagramSocketProxy::CDatagramSocketProxy(
1332 wxIPaddress &address, wxSocketFlags flags, const CProxyData *proxyData)
1334 wxDatagramSocket(address, flags),
1335 m_proxyTCPSocket(wxSOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1337 m_udpSocketOk = false;
1338 if ( m_proxyTCPSocket.GetUseProxy() &&
1339 m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1340 m_proxyTCPSocket.Start(address);
1341 } else {
1343 m_lastUDPOperation = UDP_OPERATION_NONE;
1346 CDatagramSocketProxy::~CDatagramSocketProxy()
1348 // From RFC-1928:
1349 // "A UDP association terminates when the TCP connection that the
1350 // UDP ASSOCIATE request arrived terminates."
1353 wxDatagramSocket &CDatagramSocketProxy::RecvFrom(
1354 wxSockAddress &addr, void* buf, wxUint32 nBytes )
1356 wxMutexLocker lock(m_socketLocker);
1357 m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1358 if (m_proxyTCPSocket.GetUseProxy()) {
1359 if (m_udpSocketOk) {
1360 char *bufUDP = NULL;
1361 if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1362 bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1363 } else {
1364 bufUDP = m_proxyTCPSocket.GetBuffer();
1366 wxDatagramSocket::RecvFrom(
1367 m_proxyTCPSocket.GetProxyBoundAddress(),
1368 bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1369 unsigned int offset;
1370 switch (m_proxyTCPSocket.GetBuffer()[3]) {
1371 case SOCKS5_ATYP_IPV4_ADDRESS: {
1372 offset = PROXY_UDP_OVERHEAD_IPV4;
1373 try {
1374 amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1375 a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1376 a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) ) );
1377 } catch (const std::bad_cast& WXUNUSED(e)) {
1378 AddDebugLogLineM(false, logProxy,
1379 wxT("(2)bad_cast exception!"));
1380 wxASSERT(false);
1383 break;
1385 case SOCKS5_ATYP_DOMAINNAME:
1386 offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1387 break;
1389 case SOCKS5_ATYP_IPV6_ADDRESS:
1390 offset = PROXY_UDP_OVERHEAD_IPV6;
1391 break;
1393 default:
1394 /* Error! */
1395 offset = 0;
1396 break;
1398 memcpy(buf, bufUDP + offset, nBytes);
1399 // Uncomment here to see the buffer contents on console
1400 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1402 /* Only delete buffer if it was dynamically created */
1403 if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1404 /* We should use a fixed buffer to avoid
1405 * new/delete it all the time.
1406 * I need an upper bound */
1407 delete bufUDP;
1409 /* There is still one problem pending, fragmentation.
1410 * Either we support it or we have to drop fragmented
1411 * messages. I vote for drop :)
1414 } else {
1415 wxDatagramSocket::RecvFrom(addr, buf, nBytes);
1418 return *this;
1421 wxDatagramSocket &CDatagramSocketProxy::SendTo(
1422 wxIPaddress &addr, const void* buf, wxUint32 nBytes )
1424 wxMutexLocker lock(m_socketLocker);
1425 m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1426 m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1427 if (m_proxyTCPSocket.GetUseProxy()) {
1428 if (m_udpSocketOk) {
1429 m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV; // Reserved
1430 m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV; // Reserved
1431 m_proxyTCPSocket.GetBuffer()[2] = 0; // FRAG
1432 m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1433 PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1434 RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
1435 memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1436 nBytes += PROXY_UDP_OVERHEAD_IPV4;
1437 wxDatagramSocket::SendTo(
1438 m_proxyTCPSocket.GetProxyBoundAddress(),
1439 m_proxyTCPSocket.GetBuffer(), nBytes);
1440 // Uncomment here to see the buffer contents on console
1441 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1443 } else {
1444 wxDatagramSocket::SendTo(addr, buf, nBytes);
1447 return *this;
1450 wxUint32 CDatagramSocketProxy::LastCount(void) const
1452 wxUint32 ret;
1454 if (m_proxyTCPSocket.GetUseProxy()) {
1455 switch (m_lastUDPOperation) {
1456 case UDP_OPERATION_RECV_FROM:
1457 case UDP_OPERATION_SEND_TO:
1458 ret = Ok() ? wxDatagramSocket::LastCount() - m_lastUDPOverhead : 0;
1459 break;
1461 case UDP_OPERATION_NONE:
1462 default:
1463 ret = 0;
1464 break;
1467 } else {
1468 ret = wxDatagramSocket::LastCount();
1471 return ret;
1474 #endif // CLIENT_GUI
1476 /******************************************************************************/
1477 // File_checked_for_headers