| 
									
										
										
										
											2008-08-15 17:31:51 +00:00
										 |  |  | # -*- coding:utf-8 -*- | 
					
						
							| 
									
										
										
										
											2008-08-15 03:20:23 +00:00
										 |  |  | ## src/common/proxy65_manager.py | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | ## | 
					
						
							| 
									
										
										
										
											2008-08-15 03:20:23 +00:00
										 |  |  | ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com> | 
					
						
							|  |  |  | ##                    Jean-Marie Traissard <jim AT lapin.org> | 
					
						
							| 
									
										
										
										
											2012-01-11 22:20:34 +01:00
										 |  |  | ## Copyright (C) 2007-2012 Yann Leboulanger <asterix AT lagaule.org> | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | ## | 
					
						
							| 
									
										
										
										
											2007-10-22 11:13:13 +00:00
										 |  |  | ## This file is part of Gajim. | 
					
						
							|  |  |  | ## | 
					
						
							|  |  |  | ## Gajim is free software; you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | ## it under the terms of the GNU General Public License as published | 
					
						
							| 
									
										
										
										
											2007-10-22 11:13:13 +00:00
										 |  |  | ## by the Free Software Foundation; version 3 only. | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | ## | 
					
						
							| 
									
										
										
										
											2007-10-22 11:13:13 +00:00
										 |  |  | ## Gajim is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2008-08-15 03:20:23 +00:00
										 |  |  | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | ## GNU General Public License for more details. | 
					
						
							|  |  |  | ## | 
					
						
							| 
									
										
										
										
											2007-10-22 11:13:13 +00:00
										 |  |  | ## You should have received a copy of the GNU General Public License | 
					
						
							| 
									
										
										
										
											2008-08-15 03:20:23 +00:00
										 |  |  | ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2007-10-22 11:13:13 +00:00
										 |  |  | ## | 
					
						
							| 
									
										
										
										
											2008-08-15 03:20:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-03 21:56:12 +00:00
										 |  |  | import socket | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | import struct | 
					
						
							| 
									
										
										
										
											2006-05-10 11:22:47 +00:00
										 |  |  | import errno | 
					
						
							| 
									
										
										
										
											2009-02-14 16:41:31 +00:00
										 |  |  | import logging | 
					
						
							|  |  |  | log = logging.getLogger('gajim.c.proxy65_manager') | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  | import nbxmpp | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | from common import gajim | 
					
						
							| 
									
										
										
										
											2006-03-20 21:24:10 +00:00
										 |  |  | from common import helpers | 
					
						
							| 
									
										
										
										
											2013-01-02 13:54:02 +01:00
										 |  |  | from common.socks5 import Socks5 | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  | from nbxmpp.idlequeue import IdleObject | 
					
						
							| 
									
										
										
										
											2012-06-14 12:27:23 -04:00
										 |  |  | from common.file_props import FilesProp | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | S_INITIAL = 0 | 
					
						
							|  |  |  | S_STARTED = 1 | 
					
						
							|  |  |  | S_RESOLVED = 2 | 
					
						
							| 
									
										
										
										
											2006-03-20 21:24:10 +00:00
										 |  |  | S_ACTIVATED = 3 | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | S_FINISHED = 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CONNECT_TIMEOUT = 20 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Proxy65Manager: | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Keep records for file transfer proxies. Each time account establishes a | 
					
						
							|  |  |  |     connection to its server call proxy65manger.resolve(proxy) for every proxy | 
					
						
							|  |  |  |     that is convigured within the account. The class takes care to resolve and | 
					
						
							|  |  |  |     test each proxy only once | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, idlequeue): | 
					
						
							|  |  |  |         # dict {proxy: proxy properties} | 
					
						
							|  |  |  |         self.idlequeue = idlequeue | 
					
						
							|  |  |  |         self.proxies = {} | 
					
						
							|  |  |  |         # dict {account: proxy} default proxy for account | 
					
						
							|  |  |  |         self.default_proxies = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-23 20:26:28 +02:00
										 |  |  |     def resolve(self, proxy, connection, sender_jid, default=None, | 
					
						
							|  |  |  |     testit=True): | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Start | 
					
						
							| 
									
										
										
										
											2011-10-23 20:26:28 +02:00
										 |  |  |         if testit=False, Gajim won't try to resolve it | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         if proxy in self.proxies: | 
					
						
							|  |  |  |             resolver = self.proxies[proxy] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # proxy is being ressolved for the first time | 
					
						
							| 
									
										
										
										
											2011-10-23 20:26:28 +02:00
										 |  |  |             resolver = ProxyResolver(proxy, sender_jid, testit) | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |             self.proxies[proxy] = resolver | 
					
						
							|  |  |  |             resolver.add_connection(connection) | 
					
						
							|  |  |  |         if default: | 
					
						
							|  |  |  |             # add this proxy as default for account | 
					
						
							|  |  |  |             self.default_proxies[default] = proxy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def disconnect(self, connection): | 
					
						
							|  |  |  |         for resolver in self.proxies.values(): | 
					
						
							|  |  |  |             resolver.disconnect(connection) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def resolve_result(self, proxy, query): | 
					
						
							|  |  |  |         if proxy not in self.proxies: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         jid = None | 
					
						
							|  |  |  |         for item in query.getChildren(): | 
					
						
							|  |  |  |             if item.getName() == 'streamhost': | 
					
						
							|  |  |  |                 host = item.getAttr('host') | 
					
						
							|  |  |  |                 port = item.getAttr('port') | 
					
						
							|  |  |  |                 jid = item.getAttr('jid') | 
					
						
							| 
									
										
										
										
											2010-03-19 14:06:22 +01:00
										 |  |  |                 if not host or not port or not jid: | 
					
						
							|  |  |  |                     self.proxies[proxy]._on_connect_failure() | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |                 self.proxies[proxy].resolve_result(host, port, jid) | 
					
						
							|  |  |  |                 # we can have only one streamhost | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  |                 raise nbxmpp.NodeProcessed | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def error_cb(self, proxy, query): | 
					
						
							|  |  |  |         sid = query.getAttr('sid') | 
					
						
							|  |  |  |         for resolver in self.proxies.values(): | 
					
						
							|  |  |  |             if resolver.sid == sid: | 
					
						
							|  |  |  |                 resolver.keep_conf() | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_default_for_name(self, account): | 
					
						
							|  |  |  |         if account in self.default_proxies: | 
					
						
							|  |  |  |             return self.default_proxies[account] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_proxy(self, proxy, account): | 
					
						
							|  |  |  |         if proxy in self.proxies: | 
					
						
							|  |  |  |             resolver = self.proxies[proxy] | 
					
						
							|  |  |  |             if resolver.state == S_FINISHED: | 
					
						
							|  |  |  |                 return (resolver.host, resolver.port, resolver.jid) | 
					
						
							|  |  |  |         return (None, 0, None) | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ProxyResolver: | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |     def resolve_result(self, host, port, jid): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Test if host has a real proxy65 listening on port | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.host = str(host) | 
					
						
							|  |  |  |         self.port = int(port) | 
					
						
							| 
									
										
										
										
											2013-01-01 21:06:16 +01:00
										 |  |  |         self.jid = str(jid) | 
					
						
							| 
									
										
										
										
											2011-10-23 20:26:28 +02:00
										 |  |  |         if not self.testit: | 
					
						
							|  |  |  |             self.state = S_FINISHED | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2010-03-19 14:06:22 +01:00
										 |  |  |         self.state = S_INITIAL | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         log.info('start resolving %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |         self.receiver_tester = ReceiverTester(self.host, self.port, self.jid, | 
					
						
							|  |  |  |                 self.sid, self.sender_jid, self._on_receiver_success, | 
					
						
							|  |  |  |                 self._on_connect_failure) | 
					
						
							|  |  |  |         self.receiver_tester.connect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _on_receiver_success(self): | 
					
						
							|  |  |  |         log.debug('Receiver successfully connected %s:%s' % (self.host, | 
					
						
							|  |  |  |                 self.port)) | 
					
						
							|  |  |  |         self.host_tester = HostTester(self.host, self.port, self.jid, | 
					
						
							|  |  |  |                 self.sid, self.sender_jid, self._on_connect_success, | 
					
						
							|  |  |  |                 self._on_connect_failure) | 
					
						
							|  |  |  |         self.host_tester.connect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _on_connect_success(self): | 
					
						
							|  |  |  |         log.debug('Host successfully connected %s:%s' % (self.host, self.port)) | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  |         iq = nbxmpp.Protocol(name='iq', to=self.jid, typ='set') | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         query = iq.setTag('query') | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  |         query.setNamespace(nbxmpp.NS_BYTESTREAM) | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         query.setAttr('sid',  self.sid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         activate = query.setTag('activate') | 
					
						
							|  |  |  |         activate.setData('test@gajim.org/test2') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.active_connection: | 
					
						
							|  |  |  |             log.debug('Activating bytestream on %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |             self.active_connection.SendAndCallForResponse(iq, | 
					
						
							|  |  |  |                      self._result_received) | 
					
						
							|  |  |  |             self.state = S_ACTIVATED | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.state = S_INITIAL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _result_received(self, data): | 
					
						
							|  |  |  |         self.disconnect(self.active_connection) | 
					
						
							|  |  |  |         if data.getType() == 'result': | 
					
						
							|  |  |  |             self.keep_conf() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self._on_connect_failure() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def keep_conf(self): | 
					
						
							|  |  |  |         log.debug('Bytestream activated %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |         self.state = S_FINISHED | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _on_connect_failure(self): | 
					
						
							|  |  |  |         self.state = S_FINISHED | 
					
						
							|  |  |  |         self.host = None | 
					
						
							|  |  |  |         self.port = 0 | 
					
						
							|  |  |  |         self.jid = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def disconnect(self, connection): | 
					
						
							|  |  |  |         if self.host_tester: | 
					
						
							|  |  |  |             self.host_tester.disconnect() | 
					
						
							| 
									
										
										
										
											2012-08-23 12:13:20 +02:00
										 |  |  |             FilesProp.deleteFileProp(self.host_tester.file_props) | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |             self.host_tester = None | 
					
						
							|  |  |  |         if self.receiver_tester: | 
					
						
							|  |  |  |             self.receiver_tester.disconnect() | 
					
						
							| 
									
										
										
										
											2012-08-23 12:13:20 +02:00
										 |  |  |             FilesProp.deleteFileProp(self.receiver_tester.file_props) | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |             self.receiver_tester = None | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.connections.remove(connection) | 
					
						
							|  |  |  |         except ValueError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         if connection == self.active_connection: | 
					
						
							|  |  |  |             self.active_connection = None | 
					
						
							|  |  |  |             if self.state != S_FINISHED: | 
					
						
							|  |  |  |                 self.state = S_INITIAL | 
					
						
							|  |  |  |                 self.try_next_connection() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def try_next_connection(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Try to resolve proxy with the next possible connection | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.connections: | 
					
						
							|  |  |  |             connection = self.connections.pop(0) | 
					
						
							|  |  |  |             self.start_resolve(connection) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def add_connection(self, connection): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Add a new connection in case the first fails | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.connections.append(connection) | 
					
						
							|  |  |  |         if self.state == S_INITIAL: | 
					
						
							|  |  |  |             self.start_resolve(connection) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def start_resolve(self, connection): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Request network address from proxy | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.state = S_STARTED | 
					
						
							|  |  |  |         self.active_connection = connection | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  |         iq = nbxmpp.Protocol(name='iq', to=self.proxy, typ='get') | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         query = iq.setTag('query') | 
					
						
							| 
									
										
										
										
											2012-12-09 21:37:51 +01:00
										 |  |  |         query.setNamespace(nbxmpp.NS_BYTESTREAM) | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         connection.send(iq) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-23 20:26:28 +02:00
										 |  |  |     def __init__(self, proxy, sender_jid, testit): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if testit is False, don't test it, only get IP/port | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         self.proxy = proxy | 
					
						
							|  |  |  |         self.state = S_INITIAL | 
					
						
							|  |  |  |         self.active_connection = None | 
					
						
							|  |  |  |         self.connections = [] | 
					
						
							|  |  |  |         self.host_tester = None | 
					
						
							|  |  |  |         self.receiver_tester = None | 
					
						
							|  |  |  |         self.jid = None | 
					
						
							|  |  |  |         self.host = None | 
					
						
							|  |  |  |         self.port = None | 
					
						
							|  |  |  |         self.sid = helpers.get_random_string_16() | 
					
						
							|  |  |  |         self.sender_jid = sender_jid | 
					
						
							| 
									
										
										
										
											2011-10-23 20:26:28 +02:00
										 |  |  |         self.testit = testit | 
					
						
							| 
									
										
										
										
											2008-08-27 13:11:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-19 20:43:30 +00:00
										 |  |  | class HostTester(Socks5, IdleObject): | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Fake proxy tester | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Try to establish and auth to proxy at (host, port) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Calls on_success, or on_failure according to the result. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.host = host | 
					
						
							|  |  |  |         self.port = port | 
					
						
							|  |  |  |         self.jid = jid | 
					
						
							|  |  |  |         self.on_success = on_success | 
					
						
							|  |  |  |         self.on_failure = on_failure | 
					
						
							|  |  |  |         self._sock = None | 
					
						
							| 
									
										
										
										
											2012-06-14 12:27:23 -04:00
										 |  |  |         self.file_props = FilesProp.getNewFileProp(jid, sid) | 
					
						
							|  |  |  |         self.file_props.is_a_proxy = True | 
					
						
							|  |  |  |         self.file_props.proxy_sender = sender_jid | 
					
						
							|  |  |  |         self.file_props.proxy_receiver = 'test@gajim.org/test2' | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None) | 
					
						
							|  |  |  |         self.sid = sid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def connect(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Create the socket and plug it to the idlequeue | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.host is None: | 
					
						
							|  |  |  |             self.on_failure() | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | 
					
						
							|  |  |  |         self._sock.setblocking(False) | 
					
						
							|  |  |  |         self.fd = self._sock.fileno() | 
					
						
							|  |  |  |         self.state = 0 # about to be connected | 
					
						
							|  |  |  |         gajim.idlequeue.plug_idle(self, True, False) | 
					
						
							|  |  |  |         self.do_connect() | 
					
						
							|  |  |  |         self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def read_timeout(self): | 
					
						
							|  |  |  |         self.idlequeue.remove_timeout(self.fd) | 
					
						
							|  |  |  |         self.pollend() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pollend(self): | 
					
						
							|  |  |  |         self.disconnect() | 
					
						
							|  |  |  |         self.on_failure() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pollout(self): | 
					
						
							|  |  |  |         self.idlequeue.remove_timeout(self.fd) | 
					
						
							|  |  |  |         if self.state == 0: | 
					
						
							|  |  |  |             self.do_connect() | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         elif self.state == 1: # send initially: version and auth types | 
					
						
							|  |  |  |             data = self._get_auth_buff() | 
					
						
							|  |  |  |             self.send_raw(data) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.state += 1 | 
					
						
							|  |  |  |         # unplug and plug for reading | 
					
						
							|  |  |  |         gajim.idlequeue.plug_idle(self, False, True) | 
					
						
							|  |  |  |         gajim.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pollin(self): | 
					
						
							|  |  |  |         self.idlequeue.remove_timeout(self.fd) | 
					
						
							|  |  |  |         if self.state == 2: | 
					
						
							|  |  |  |             self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) | 
					
						
							|  |  |  |             # begin negotiation. on success 'address' != 0 | 
					
						
							|  |  |  |             buff = self.receive() | 
					
						
							|  |  |  |             if buff == '': | 
					
						
							|  |  |  |                 # end connection | 
					
						
							|  |  |  |                 self.pollend() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             # read auth response | 
					
						
							|  |  |  |             if buff is None or len(buff) != 2: | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |             version, method = struct.unpack('!BB', buff[:2]) | 
					
						
							|  |  |  |             if version != 0x05 or method == 0xff: | 
					
						
							|  |  |  |                 self.pollend() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             data = self._get_request_buff(self._get_sha1_auth()) | 
					
						
							|  |  |  |             self.send_raw(data) | 
					
						
							|  |  |  |             self.state += 1 | 
					
						
							|  |  |  |             log.debug('Host authenticating to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |         elif self.state == 3: | 
					
						
							|  |  |  |             log.debug('Host authenticated to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |             self.on_success() | 
					
						
							|  |  |  |             self.disconnect() | 
					
						
							|  |  |  |             self.state += 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             assert False, 'unexpected state: %d' % self.state | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def do_connect(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self._sock.connect((self.host, self.port)) | 
					
						
							|  |  |  |             self._sock.setblocking(False) | 
					
						
							|  |  |  |             log.debug('Host Connecting to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |             self._send = self._sock.send | 
					
						
							|  |  |  |             self._recv = self._sock.recv | 
					
						
							| 
									
										
										
										
											2013-01-01 23:18:36 +01:00
										 |  |  |         except Exception as ee: | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |             errnum = ee[0] | 
					
						
							|  |  |  |             # 56 is for freebsd | 
					
						
							|  |  |  |             if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): | 
					
						
							|  |  |  |                 # still trying to connect | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             # win32 needs this | 
					
						
							|  |  |  |             if errnum not in (0, 10056, errno.EISCONN): | 
					
						
							|  |  |  |                 # connection failed | 
					
						
							|  |  |  |                 self.on_failure() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             # socket is already connected | 
					
						
							|  |  |  |             self._sock.setblocking(False) | 
					
						
							|  |  |  |             self._send = self._sock.send | 
					
						
							|  |  |  |             self._recv = self._sock.recv | 
					
						
							|  |  |  |         self.buff = '' | 
					
						
							|  |  |  |         self.state = 1 # connected | 
					
						
							|  |  |  |         log.debug('Host connected to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |         self.idlequeue.plug_idle(self, True, False) | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2008-08-27 13:11:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ReceiverTester(Socks5, IdleObject): | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Fake proxy tester | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Try to establish and auth to proxy at (host, port) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Call on_success, or on_failure according to the result. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.host = host | 
					
						
							|  |  |  |         self.port = port | 
					
						
							|  |  |  |         self.jid = jid | 
					
						
							|  |  |  |         self.on_success = on_success | 
					
						
							|  |  |  |         self.on_failure = on_failure | 
					
						
							|  |  |  |         self._sock = None | 
					
						
							| 
									
										
										
										
											2012-06-14 12:27:23 -04:00
										 |  |  |         self.file_props = FilesProp.getNewFileProp(jid, sid) | 
					
						
							|  |  |  |         self.file_props.is_a_proxy = True | 
					
						
							|  |  |  |         self.file_props.proxy_sender = sender_jid | 
					
						
							|  |  |  |         self.file_props.proxy_receiver = 'test@gajim.org/test2' | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |         Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None) | 
					
						
							|  |  |  |         self.sid = sid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def connect(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Create the socket and plug it to the idlequeue | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.host is None: | 
					
						
							|  |  |  |             self.on_failure() | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | 
					
						
							|  |  |  |         self._sock.setblocking(False) | 
					
						
							|  |  |  |         self.fd = self._sock.fileno() | 
					
						
							|  |  |  |         self.state = 0 # about to be connected | 
					
						
							|  |  |  |         gajim.idlequeue.plug_idle(self, True, False) | 
					
						
							|  |  |  |         self.do_connect() | 
					
						
							|  |  |  |         self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def read_timeout(self): | 
					
						
							|  |  |  |         self.idlequeue.remove_timeout(self.fd) | 
					
						
							|  |  |  |         self.pollend() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pollend(self): | 
					
						
							|  |  |  |         self.disconnect() | 
					
						
							|  |  |  |         self.on_failure() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pollout(self): | 
					
						
							|  |  |  |         self.idlequeue.remove_timeout(self.fd) | 
					
						
							|  |  |  |         if self.state == 0: | 
					
						
							|  |  |  |             self.do_connect() | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         elif self.state == 1: # send initially: version and auth types | 
					
						
							|  |  |  |             data = self._get_auth_buff() | 
					
						
							|  |  |  |             self.send_raw(data) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.state += 1 | 
					
						
							|  |  |  |         # unplug and plug for reading | 
					
						
							|  |  |  |         gajim.idlequeue.plug_idle(self, False, True) | 
					
						
							|  |  |  |         gajim.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pollin(self): | 
					
						
							|  |  |  |         self.idlequeue.remove_timeout(self.fd) | 
					
						
							|  |  |  |         if self.state in (2, 3): | 
					
						
							|  |  |  |             self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) | 
					
						
							|  |  |  |             # begin negotiation. on success 'address' != 0 | 
					
						
							|  |  |  |             buff = self.receive() | 
					
						
							|  |  |  |             if buff == '': | 
					
						
							|  |  |  |                 # end connection | 
					
						
							|  |  |  |                 self.pollend() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |         if self.state == 2: | 
					
						
							|  |  |  |             # read auth response | 
					
						
							|  |  |  |             if buff is None or len(buff) != 2: | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |             version, method = struct.unpack('!BB', buff[:2]) | 
					
						
							|  |  |  |             if version != 0x05 or method == 0xff: | 
					
						
							|  |  |  |                 self.pollend() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             log.debug('Receiver authenticating to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |             data = self._get_request_buff(self._get_sha1_auth()) | 
					
						
							|  |  |  |             self.send_raw(data) | 
					
						
							|  |  |  |             self.state += 1 | 
					
						
							|  |  |  |         elif self.state == 3: | 
					
						
							|  |  |  |             # read connect response | 
					
						
							|  |  |  |             if buff is None or len(buff) < 2: | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |             version, reply = struct.unpack('!BB', buff[:2]) | 
					
						
							|  |  |  |             if version != 0x05 or reply != 0x00: | 
					
						
							|  |  |  |                 self.pollend() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             log.debug('Receiver authenticated to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |             self.on_success() | 
					
						
							|  |  |  |             self.disconnect() | 
					
						
							|  |  |  |             self.state += 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             assert False, 'unexpected state: %d' % self.state | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def do_connect(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self._sock.setblocking(False) | 
					
						
							|  |  |  |             self._sock.connect((self.host, self.port)) | 
					
						
							|  |  |  |             log.debug('Receiver Connecting to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |             self._send = self._sock.send | 
					
						
							|  |  |  |             self._recv = self._sock.recv | 
					
						
							| 
									
										
										
										
											2013-01-01 23:18:36 +01:00
										 |  |  |         except Exception as ee: | 
					
						
							| 
									
										
										
										
											2010-02-08 15:08:40 +01:00
										 |  |  |             errnum = ee[0] | 
					
						
							|  |  |  |             # 56 is for freebsd | 
					
						
							|  |  |  |             if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): | 
					
						
							|  |  |  |                 # still trying to connect | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             # win32 needs this | 
					
						
							|  |  |  |             if errnum not in (0, 10056, errno.EISCONN): | 
					
						
							|  |  |  |                 # connection failed | 
					
						
							|  |  |  |                 self.on_failure() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             # socket is already connected | 
					
						
							|  |  |  |             self._sock.setblocking(False) | 
					
						
							|  |  |  |             self._send = self._sock.send | 
					
						
							|  |  |  |             self._recv = self._sock.recv | 
					
						
							|  |  |  |         self.buff = '' | 
					
						
							|  |  |  |         self.state = 1 # connected | 
					
						
							|  |  |  |         log.debug('Receiver connected to %s:%s' % (self.host, self.port)) | 
					
						
							|  |  |  |         self.idlequeue.plug_idle(self, True, False) |