Changeset 9867
- Timestamp:
- 06/30/08 02:02:32 (5 months ago)
- Location:
- branches/bosh_support
- Files:
-
- 1 removed
- 12 modified
-
data/glade/manage_proxies_window.glade (modified) (1 diff)
-
src/common/connection.py (modified) (9 diffs)
-
src/common/xmpp/auth_nb.py (modified) (1 diff)
-
src/common/xmpp/client_nb.py (modified) (8 diffs)
-
src/common/xmpp/debug.py (modified) (1 diff)
-
src/common/xmpp/dispatcher_nb.py (modified) (8 diffs)
-
src/common/xmpp/idlequeue.py (modified) (1 diff)
-
src/common/xmpp/protocol.py (modified) (2 diffs)
-
src/common/xmpp/transports_nb.py (modified) (15 diffs)
-
src/common/xmpp/transports_new.py (deleted)
-
src/config.py (modified) (2 diffs)
-
test/test_client_nb.py (modified) (11 diffs)
-
test/test_nonblockingtcp.py (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/bosh_support/data/glade/manage_proxies_window.glade
r9543 r9867 212 212 <property name="visible">True</property> 213 213 <property name="items" translatable="yes">HTTP Connect 214 SOCKS5</property> 214 SOCKS5 215 BOSH</property> 215 216 <property name="add_tearoffs">False</property> 216 217 <property name="focus_on_click">True</property> -
branches/bosh_support/src/common/connection.py
r9776 r9867 56 56 import logging 57 57 log = logging.getLogger('gajim.c.connection') 58 log.setLevel(logging.DEBUG) 58 59 59 60 ssl_error = { … … 208 209 def _disconnectedReconnCB(self): 209 210 '''Called when we are disconnected''' 210 log. debug('disconnectedReconnCB')211 log.error('disconnectedReconnCB') 211 212 if gajim.account_is_connected(self.name): 212 213 # we cannot change our status to offline or connecting … … 468 469 else: 469 470 proxy = None 470 471 471 h = hostname 472 472 p = 5222 … … 505 505 506 506 def on_proxy_failure(self, reason): 507 log. debug('Connection to proxy failed')507 log.error('Connection to proxy failed: %s' % reason) 508 508 self.time_to_reconnect = None 509 509 self.on_connect_failure = None … … 520 520 self.last_connection = None 521 521 self.connection = None 522 if gajim.verbose:523 con = common.xmpp.NonBlockingClient(self._hostname, caller = self,524 on_connect = self.on_connect_success,525 on_proxy_failure = self.on_proxy_failure,526 on_connect_failure = self.connect_to_next_type)527 else:528 con = common.xmpp.NonBlockingClient(self._hostname, debug = [],529 caller = self, on_connect = self.on_connect_success,530 on_proxy_failure = self.on_proxy_failure,531 on_connect_failure = self.connect_to_next_type)532 self.last_connection = con533 # increase default timeout for server responses534 common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = self.try_connecting_for_foo_secs535 con.set_idlequeue(gajim.idlequeue)536 # FIXME: this is a hack; need a better way537 if self.on_connect_success == self._on_new_account:538 con.RegisterDisconnectHandler(self._on_new_account)539 522 540 523 if self._current_type == 'ssl': … … 547 530 else: 548 531 secur = None 532 533 if self._proxy and self._proxy['type'] == 'bosh': 534 clientClass = common.xmpp.BOSHClient 535 else: 536 clientClass = common.xmpp.NonBlockingClient 537 538 if gajim.verbose: 539 con = common.xmpp.NonBlockingClient( 540 hostname=self._current_host['host'], 541 port=port, 542 caller=self, 543 idlequeue=gajim.idlequeue) 544 else: 545 con = common.xmpp.NonBlockingClient( 546 hostname=self._current_host['host'], 547 debug=[], 548 port=port, 549 caller=self, 550 idlequeue=gajim.idlequeue) 551 552 self.last_connection = con 553 # increase default timeout for server responses 554 common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = self.try_connecting_for_foo_secs 555 # FIXME: this is a hack; need a better way 556 if self.on_connect_success == self._on_new_account: 557 con.RegisterDisconnectHandler(self._on_new_account) 558 549 559 log.info('Connecting to %s: [%s:%d]', self.name, 550 560 self._current_host['host'], port) 551 con.connect((self._current_host['host'], port), proxy=self._proxy, 561 con.connect( 562 on_connect=self.on_connect_success, 563 on_proxy_failure=self.on_proxy_failure, 564 on_connect_failure=self.connect_to_next_type, 565 proxy=self._proxy, 552 566 secure = secur) 553 567 else: … … 562 576 else: 563 577 self._connection_types = ['tls', 'ssl', 'plain'] 578 579 # FIXME: remove after tls and ssl will be degubbed 580 #self._connection_types = ['plain'] 564 581 host = self.select_next_host(self._hosts) 565 582 self._current_host = host … … 976 993 self.remove_all_transfers() 977 994 self.time_to_reconnect = None 978 self.connection.start_disconnect(p, self._on_disconnected) 995 996 self.connection.RegisterDisconnectHandler(self._on_disconnected) 997 self.connection.send(p) 998 self.connection.StreamTerminate() 999 #self.connection.start_disconnect(p, self._on_disconnected) 979 1000 else: 980 1001 self.time_to_reconnect = None … … 1011 1032 ''' called when a disconnect request has completed successfully''' 1012 1033 self.dispatch('STATUS', 'offline') 1013 self.disconnect( )1034 self.disconnect(on_purpose=True) 1014 1035 1015 1036 def get_status(self): -
branches/bosh_support/src/common/xmpp/auth_nb.py
r9776 r9867 170 170 self.DEBUG('Successfully authenticated with remote server.', 'ok') 171 171 handlers=self._owner.Dispatcher.dumpHandlers() 172 print '6' * 79 173 print handlers 174 print '6' * 79 172 175 self._owner.Dispatcher.PlugOut() 173 176 dispatcher_nb.Dispatcher().PlugIn(self._owner) -
branches/bosh_support/src/common/xmpp/client_nb.py
r9776 r9867 18 18 19 19 ''' 20 Provides PlugIn class functionality to develop extentions for xmpppy. 21 Also provides Client and Component classes implementations as the 22 examples of xmpppy structures usage. 20 Provides Client classes implementations as examples of xmpppy structures usage. 23 21 These classes can be used for simple applications "AS IS" though. 24 22 ''' … … 26 24 import socket 27 25 import debug 28 29 import transports_nb, dispatcher_nb, auth_nb, roster_nb 26 import random 27 28 import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol 30 29 from client import * 30 31 import logging 32 log = logging.getLogger('gajim.c.x.client_nb') 33 34 consoleloghandler = logging.StreamHandler() 35 consoleloghandler.setLevel(logging.DEBUG) 36 consoleloghandler.setFormatter( 37 logging.Formatter('%(levelname)s: %(message)s') 38 ) 39 log.setLevel(logging.DEBUG) 40 log.addHandler(consoleloghandler) 41 log.propagate = False 42 31 43 32 44 class NBCommonClient: 33 45 ''' Base for Client and Component classes.''' 34 def __init__(self, server, port=5222, debug=['always', 'nodebuilder'], caller=None, 35 on_connect=None, on_proxy_failure=None, on_connect_failure=None): 36 ''' Caches server name and (optionally) port to connect to. "debug" parameter specifies 37 the debug IDs that will go into debug output. You can either specifiy an "include" 38 or "exclude" list. The latter is done via adding "always" pseudo-ID to the list. 39 Full list: ['nodebuilder', 'dispatcher', 'gen_auth', 'SASL_auth', 'bind', 'socket', 40 'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb'] . ''' 41 42 if isinstance(self, NonBlockingClient): 43 self.Namespace, self.DBG = 'jabber:client', DBG_CLIENT 44 elif isinstance(self, NBCommonClient): 45 self.Namespace, self.DBG = dispatcher_nb.NS_COMPONENT_ACCEPT, DBG_COMPONENT 46 46 def __init__(self, hostname, idlequeue, port=5222, debug=['always', 'nodebuilder'], caller=None): 47 48 ''' Caches connection data: 49 :param hostname: hostname of machine where the XMPP server is running (from Account 50 of from SRV request) and port to connect to. 51 :param idlequeue: processing idlequeue 52 :param port: port of listening XMPP server 53 :param debug: specifies the debug IDs that will go into debug output. You can either 54 specifiy an "include" or "exclude" list. The latter is done via adding "always" 55 pseudo-ID to the list. Full list: ['nodebuilder', 'dispatcher', 'gen_auth', 56 'SASL_auth', 'bind', 'socket', 'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb']. 57 TODO: get rid of debug.py using 58 :param caller: calling object - it has to implement certain methods (necessary?) 59 60 ''' 61 62 self.DBG = DBG_CLIENT 63 64 self.Namespace = protocol.NS_CLIENT 65 66 self.idlequeue = idlequeue 47 67 self.defaultNamespace = self.Namespace 48 68 self.disconnect_handlers = [] 49 self.Server = server 69 70 # XMPP server and port from account or SRV 71 self.Server = hostname 50 72 self.Port = port 51 73 52 # Who initiated this client 53 # Used to register the EventDispatcher 74 # caller is who initiated this client, it is sed to register the EventDispatcher 54 75 self._caller = caller 55 76 if debug and type(debug) != list: … … 63 84 self.connected = '' 64 85 self._component=0 65 self.idlequeue = None66 86 self.socket = None 67 self.on_connect = on_connect 68 self.on_proxy_failure = on_proxy_failure 69 self.on_connect_failure = on_connect_failure 70 71 def set_idlequeue(self, idlequeue): 72 self.idlequeue = idlequeue 87 self.on_connect = None 88 self.on_proxy_failure = None 89 self.on_connect_failure = None 90 self.proxy = None 91 73 92 74 def disconnected(self): 75 ''' Called on disconnection. Calls disconnect handlers and cleans things up. ''' 93 def on_disconnect(self): 94 ''' 95 Called on disconnection - when connect failure occurs on running connection 96 (after stream is successfully opened). 97 Calls disconnect handlers and cleans things up. 98 ''' 99 76 100 self.connected='' 77 101 self.DEBUG(self.DBG,'Disconnect detected','stop') 78 102 for i in reversed(self.disconnect_handlers): 103 self.DEBUG(self.DBG, 'Calling disc handler %s' % i, 'stop') 79 104 i() 80 105 if self.__dict__.has_key('NonBlockingRoster'): … … 95 120 self.NonBlockingTcp.PlugOut() 96 121 97 def reconnectAndReauth(self): 98 ''' Just disconnect. We do reconnecting in connection.py ''' 99 self.disconnect() 100 return '' 101 102 def connect(self,server=None,proxy=None, ssl=None, on_stream_start = None): 103 ''' Make a tcp/ip connection, protect it with tls/ssl if possible and start XMPP stream. ''' 104 if not server: 105 server = (self.Server, self.Port) 106 self._Server, self._Proxy, self._Ssl = server , proxy, ssl 107 self.on_stream_start = on_stream_start 122 123 def send(self, stanza, is_message = False, now = False): 124 ''' interface for putting stanzas on wire. Puts ID to stanza if needed and 125 sends it via socket wrapper''' 126 (id, stanza_to_send) = self.Dispatcher.assign_id(stanza) 127 128 if is_message: 129 # somehow zeroconf-specific 130 self.Connection.send(stanza_to_send, True, now = now) 131 else: 132 self.Connection.send(stanza_to_send, now = now) 133 return id 134 135 136 137 def connect(self, on_connect, on_connect_failure, on_proxy_failure=None, proxy=None, secure=None): 138 ''' 139 Open XMPP connection (open streams in both directions). 140 :param on_connect: called after stream is successfully opened 141 :param on_connect_failure: called when error occures during connection 142 :param on_proxy_failure: called if error occurres during TCP connection to 143 proxy server or during connection to the proxy 144 :param proxy: dictionary with proxy data. It should contain at least values 145 for keys 'host' and 'port' - connection details for proxy server and 146 optionally keys 'user' and 'pass' as proxy credentials 147 :param secure: 148 ''' 149 150 self.on_connect = on_connect 151 self.on_connect_failure=on_connect_failure 152 self.on_proxy_failure = on_proxy_failure 153 self._secure = secure 154 self.Connection = None 155 108 156 if proxy: 157 # with proxies, client connects to proxy instead of directly to 158 # XMPP server from __init__. 159 # tcp_server is hostname used for socket connecting 160 tcp_server=proxy['host'] 161 tcp_port=proxy['port'] 162 self._on_tcp_failure = self.on_proxy_failure 109 163 if proxy.has_key('type'): 164 if proxy.has_key('user') and proxy.has_key('pass'): 165 proxy_creds=(proxy['user'],proxy['pass']) 166 else: 167 proxy_creds=(None, None) 168 110 169 type_ = proxy['type'] 111 170 if type_ == 'socks5': 112 self.socket = transports_nb.NBSOCKS5PROXYsocket( 113 self._on_connected, self._on_proxy_failure, 114 self._on_connected_failure, proxy, server) 171 self.socket = transports_nb.NBSOCKS5ProxySocket( 172 on_disconnect=self.on_disconnect, 173 proxy_creds=proxy_creds, 174 xmpp_server=(self.Server, self.Port)) 115 175 elif type_ == 'http': 116 self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected, 117 self._on_proxy_failure, self._on_connected_failure, proxy, 118 server) 176 self.socket = transports_nb.NBHTTPProxySocket( 177 on_disconnect=self.on_disconnect, 178 proxy_creds=proxy_creds, 179 xmpp_server=(self.Server, self.Port)) 180 elif type_ == 'bosh': 181 tcp_server = transports_nb.urisplit(tcp_server)[1] 182 self.socket = transports_nb.NonBlockingHttpBOSH( 183 on_disconnect=self.on_disconnect, 184 bosh_uri = proxy['host'], 185 bosh_port = tcp_port) 119 186 else: 120 self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected, 121 self._on_proxy_failure, self._on_connected_failure, proxy, 122 server) 187 self.socket = transports_nb.NBHTTPProxySocket( 188 on_disconnect=self.on_disconnect, 189 proxy_creds=(None, None), 190 xmpp_server=(self.Server, self.Port)) 123 191 else: 124 self.connected = 'tcp' 125 self.socket = transports_nb.NonBlockingTcp(self._on_connected, 126 self._on_connected_failure, server) 192 self._on_tcp_failure = self._on_connect_failure 193 tcp_server=self.Server 194 tcp_port=self.Port 195 self.socket = transports_nb.NonBlockingTcp(on_disconnect = self.on_disconnect) 196 127 197 self.socket.PlugIn(self) 128 return True 198 199 self._resolve_hostname( 200 hostname=tcp_server, 201 port=tcp_port, 202 on_success=self._try_next_ip, 203 on_failure=self._on_tcp_failure) 204 205 206 207 def _resolve_hostname(self, hostname, port, on_success, on_failure): 208 ''' wrapper of getaddinfo call. FIXME: getaddinfo blocks''' 209 try: 210 self.ip_addresses = socket.getaddrinfo(hostname,port, 211 socket.AF_UNSPEC,socket.SOCK_STREAM) 212 except socket.gaierror, (errnum, errstr): 213 on_failure(err_message='Lookup failure for %s:%s - %s %s' % 214 (self.Server, self.Port, errnum, errstr)) 215 else: 216 on_success() 217 218 129 219 130 def get_attrs(self, on_stream_start): 131 self.on_stream_start = on_stream_start 132 self.onreceive(self._on_receive_document_attrs) 133 134 def _on_proxy_failure(self, reason): 135 if self.on_proxy_failure: 136 self.on_proxy_failure(reason) 137 138 def _on_connected_failure(self, retry = None): 220 def _try_next_ip(self, err_message=None): 221 '''iterates over IP addresses from getaddinfo''' 222 if err_message: 223 self.DEBUG(self.DBG,err_message,'connect') 224 if self.ip_addresses == []: 225 self._on_tcp_failure(err_message='Run out of hosts for name %s:%s' % 226 (self.Server, self.Port)) 227 else: 228 self.current_ip = self.ip_addresses.pop(0) 229 self.socket.connect( 230 conn_5tuple=self.current_ip, 231 on_connect=lambda: self._xmpp_connect(socket_type='tcp'), 232 on_connect_failure=self._try_next_ip) 233 234 235 def incoming_stream_version(self): 236 ''' gets version of xml stream''' 237 if self.Dispatcher.Stream._document_attrs.has_key('version'): 238 return self.Dispatcher.Stream._document_attrs['version'] 239 else: 240 return None 241 242 def _xmpp_connect(self, socket_type): 243 self.connected = socket_type 244 self._xmpp_connect_machine() 245 246 247 def _xmpp_connect_machine(self, mode=None, data=None): 248 ''' 249 Finite automaton called after TCP connecting. Takes care of stream opening 250 and features tag handling. Calls _on_stream_start when stream is 251 started, and _on_connect_failure on failure. 252 ''' 253 #FIXME: use RegisterHandlerOnce instead of onreceive 254 log.info('=============xmpp_connect_machine() >> mode: %s, data: %s' % (mode,data)) 255 256 def on_next_receive(mode): 257 if mode is None: 258 self.onreceive(None) 259 else: 260 self.onreceive(lambda data:self._xmpp_connect_machine(mode, data)) 261 262 if not mode: 263 dispatcher_nb.Dispatcher().PlugIn(self) 264 on_next_receive('RECEIVE_DOCUMENT_ATTRIBUTES') 265 266 elif mode == 'FAILURE': 267 self._on_connect_failure(err_message='During XMPP connect: %s' % data) 268 269 elif mode == 'RECEIVE_DOCUMENT_ATTRIBUTES': 270 if data: 271 self.Dispatcher.ProcessNonBlocking(data) 272 if not hasattr(self, 'Dispatcher') or \ 273 self.Dispatcher.Stream._document_attrs is None: 274 self._xmpp_connect_machine( 275 mode='FAILURE', 276 data='Error on stream open') 277 if self.incoming_stream_version() == '1.0': 278 if not self.Dispatcher.Stream.features: 279 on_next_receive('RECEIVE_STREAM_FEATURES') 280 else: 281 self._xmpp_connect_machine(mode='STREAM_STARTED') 282 283 else: 284 self._xmpp_connect_machine(mode='STREAM_STARTED') 285 286 elif mode == 'RECEIVE_STREAM_FEATURES': 287 if data: 288 # sometimes <features> are received together with document 289 # attributes and sometimes on next receive... 290 self.Dispatcher.ProcessNonBlocking(data) 291 if not self.Dispatcher.Stream.features: 292 self._xmpp_connect_machine( 293 mode='FAILURE', 294 data='Missing <features> in 1.0 stream') 295 else: 296 self._xmpp_connect_machine(mode='STREAM_STARTED') 297 298 elif mode == 'STREAM_STARTED': 299 self._on_stream_start() 300 301 def _on_stream_start(self): 302 '''Called when stream is opened. To be overriden in derived classes.''' 303 304 def _on_connect_failure(self, retry=None, err_message=None): 305 self.connected = None 306 if err_message: 307 self.DEBUG(self.DBG, err_message, 'connecting') 139 308 if self.socket: 140 309 self.socket.disconnect() 141 if self.on_connect_failure: 142 self.on_connect_failure(retry) 143 144 def _on_connected(self): 145 # FIXME: why was this needed? Please note that we're working 146 # in nonblocking mode, and this handler is actually called 147 # as soon as connection is initiated, NOT when connection 148 # succeeds, as the name suggests. 149 # # connect succeeded, so no need of this callback anymore 150 # self.on_connect_failure = None 151 self.connected = 'tcp' 152 if self._Ssl: 153 transports_nb.NonBlockingTLS().PlugIn(self, now=1) 154 if not self.Connection: # ssl error, stream is closed 155 return 156 self.connected = 'ssl' 157 self.onreceive(self._on_receive_document_attrs) 158 dispatcher_nb.Dispatcher().PlugIn(self) 159 160 def _on_receive_document_attrs(self, data): 161 if data: 162 self.Dispatcher.ProcessNonBlocking(data) 163 if not hasattr(self, 'Dispatcher') or \ 164 self.Dispatcher.Stream._document_attrs is None: 165 return 310 self.on_connect_failure(retry) 311 312 def _on_connect(self): 166 313 self.onreceive(None) 167 if self.Dispatcher.Stream._document_attrs.has_key('version') and \ 168 self.Dispatcher.Stream._document_attrs['version'] == '1.0': 169 self.onreceive(self._on_receive_stream_features) 170 return 171 if self.on_stream_start: 172 self.on_stream_start() 173 self.on_stream_start = None 174 return True 175 176 def _on_receive_stream_features(self, data): 177
