def _connectWithContextFactory(ctxFactory, workbench): """Connect using the given context factory. Notifications go to the given workbench. """ endpoint = SSL4ClientEndpoint(reactor, "localhost", 4430, ctxFactory) splash = _Splash(u"Connecting", u"Connecting...") workbench.display(splash) d = endpoint.connect(Factory(workbench)) @d.addBoth def closeSplash(returnValue): workbench.undisplay() return returnValue @d.addErrback def notifyFailure(f): f.trap(ConnectError) d = alert( workbench, u"Couldn't connect", u"Connection failed! " "Check internet connection, or try again later.\n" "Error: {!r}".format(f.value)) return d.addCallback(lambda _result: reactor.stop()) return d
def connect(self): if (self.destination_ == None): return addressparts_ = self.destination_.split(":") self.log("Establishing socket destination '%s'" % (addressparts_)) try: sslcontext_ = None if (self.certificate_): file_ = ("%s/%s" % (self.certroot_, self.certificate_)) if (os.path.exists(file_)): sslcontext_ = tSSL.DefaultOpenSSLContextFactory(file_, file_, sslmethod=SSL.TLSv1_2_METHOD) context_ = sslcontext_.getContext() context_.set_options(SSL.TLSv1_2_METHOD | SSL.OP_NO_COMPRESSION | SSL.OP_CIPHER_SERVER_PREFERENCE) context_.set_cipher_list(SSL_CIPHERS) if (sslcontext_ != None): self.endpoint_ = SSL4ClientEndpoint(reactor, addressparts_[0], int(addressparts_[1]), sslcontext_, timeout=2) else: self.endpoint_ = TCP4ClientEndpoint(reactor, addressparts_[0], int(addressparts_[1]), timeout=2) reactor.callFromThread(myConnectProtocol, self.endpoint_, SocketProtocol(self), self.serviceConnected, self.serviceFailed) except Exception as inst: self.logException(inst) self.disconnected(self.protocol_)
def subEndpoint(self, reactor, host, port, contextFactory): """ Create an endpoint to connect to based on a single address result from L{getaddrinfo}. @param reactor: the reactor to connect to @type reactor: L{IReactorTCP} @param host: The IP address of the host to connect to, in presentation format. @type host: L{str} @param port: The numeric port number to connect to. @type port: L{int} @param contextFactory: If not L{None}, the OpenSSL context factory to use to produce client connections. @return: a stream client endpoint that will connect to the given host and port via the given reactor. @rtype: L{IStreamClientEndpoint} """ if contextFactory is None: return TCP4ClientEndpoint(reactor, host, port) else: return SSL4ClientEndpoint(reactor, host, port, contextFactory)
def setUp(self): # Initialize resource tree root = self._init_resource() self.site = Site(root, timeout=None) # Start server for testing self.hostname = 'localhost' context_factory = ssl_context_factory(self.key_file, self.certificate_file) server_endpoint = SSL4ServerEndpoint(reactor, 0, context_factory, interface=self.hostname) self.server = yield server_endpoint.listen(self.site) self.port_number = self.server.getHost().port # Connect H2 client with server self.client_certificate = get_client_certificate(self.key_file, self.certificate_file) client_options = optionsForClientTLS( hostname=self.hostname, trustRoot=self.client_certificate, acceptableProtocols=[b'h2'] ) uri = URI.fromBytes(bytes(self.get_url('/'), 'utf-8')) self.conn_closed_deferred = Deferred() from scrapy.core.http2.protocol import H2ClientFactory h2_client_factory = H2ClientFactory(uri, Settings(), self.conn_closed_deferred) client_endpoint = SSL4ClientEndpoint(reactor, self.hostname, self.port_number, client_options) self.client = yield client_endpoint.connect(h2_client_factory)
def add_connection(self): """ Convenience function to connect and store the resulting connector. """ host, port = self.endpoint.resolve() if self.ssl_context or self.ssl_options: # Can't use optionsForClientTLS here because it *forces* hostname verification. # Cool they enforce strong security, but we have to be able to turn it off self._check_pyopenssl() ssl_connection_creator = _SSLCreator( self.endpoint, self.ssl_context if self.ssl_context else None, self.ssl_options, self._check_hostname, self.connect_timeout, ) endpoint = SSL4ClientEndpoint( reactor, host, port, sslContextFactory=ssl_connection_creator, timeout=self.connect_timeout, ) else: endpoint = TCP4ClientEndpoint( reactor, host, port, timeout=self.connect_timeout ) connectProtocol(endpoint, TwistedConnectionProtocol(self))
def _handshake(self, credential): """ Run a TLS handshake between a client and server, one of which is using the validation logic and the other the given credential. :param credential: The high-level credential to use. :return ``Deferred``: Fires when handshake succeeded or failed. """ peer_context_factory = PeerContextFactory(credential.credential) port = find_free_port()[1] validating_context_factory = context_factory_fixture( port, self.good_ca) if validator_is_client: client_context_factory = validating_context_factory server_context_factory = peer_context_factory else: server_context_factory = validating_context_factory client_context_factory = peer_context_factory result = start_tls_server(self, port, server_context_factory) validating_endpoint = SSL4ClientEndpoint(reactor, "127.0.0.1", port, client_context_factory) client_protocol = ReceivingProtocol() result.addCallback(lambda _: connectProtocol( validating_endpoint, client_protocol)) result.addCallback(lambda _: client_protocol.result) return result
def on_connetcion_btn_toggled(self, widget): if widget.get_active(): if (not self._validate_files() or not self._validate_conference() or not self._load_media_keys()): widget.set_active(False) return self.buttons['connection'].set_label("Connecting...") self.media_tx = ClientMediaProtocol() factory = ClientFactory(self.media_tx) factory.on_connection_lost.addBoth(self.connection_lost) keys = self.settings['keys'] ctx_factory = ClientCtxFactory(keys['private_key'], keys['certificate']) c_id = self.settings['conferences_info']['current'] c_info = self.settings['conferences_info']['conferences'][c_id] name, host, port = c_info endpoint = SSL4ClientEndpoint(reactor, host, port, ctx_factory) endpoint.connect(factory).addCallbacks( self.endpoint_done, self.endpoint_failed).addCallbacks(self.connection_done, self.connection_failed) elif self.client: self.client.transport.loseConnection()
def get_endpoint(target_host, target_port, target_ssl, socks_config=None): # Imports go here to allow mocking for tests from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint from txsocksx.client import SOCKS5ClientEndpoint from txsocksx.tls import TLSWrapClientEndpoint from twisted.internet.interfaces import IOpenSSLClientConnectionCreator if socks_config is not None: sock_host = socks_config['host'] sock_port = int(socks_config['port']) methods = {'anonymous': ()} if 'username' in socks_config and 'password' in socks_config: methods['login'] = (socks_config['username'], socks_config['password']) tcp_endpoint = TCP4ClientEndpoint(reactor, sock_host, sock_port) socks_endpoint = SOCKS5ClientEndpoint(target_host, target_port, tcp_endpoint, methods=methods) if target_ssl: endpoint = TLSWrapClientEndpoint(ClientTLSContext(), socks_endpoint) else: endpoint = socks_endpoint else: if target_ssl: endpoint = SSL4ClientEndpoint(reactor, target_host, target_port, ClientTLSContext()) else: endpoint = TCP4ClientEndpoint(reactor, target_host, target_port) return endpoint
def connect_ws(self, data): from autobahn.websocket.protocol import parseWsUrl (isSecure, host, port, resource, path, params) = parseWsUrl(data['url']) endpoint = SSL4ClientEndpoint(self.clock, host, port, ssl.ClientContextFactory()) return endpoint.connect(RelayFactory(self, data, debug=self.debug))
def connectWithIP(ip, Port): print('Connect with Ip: %s:%s' % (ip, Port)) endpoint = SSL4ClientEndpoint(reactor, ip, int(Port), globals.AetherClientContextFactory()) endpoint.connect(aetherProtocolFactoryInstance)\ .addCallback(lambda p: p.initiateHandshake())\ .addErrback(printError, 'Connection failed because node at the address %s is not responding.'%ip)
def clientEndpoint(self, reactor, serverAddress): """ Create an SSL client endpoint which will connect localhost on the port given by C{serverAddress}. @type serverAddress: L{IPv4Address} """ return SSL4ClientEndpoint(reactor, '127.0.0.1', serverAddress.port, ClientContextFactory())
def make_proxied_connection(protocol_factory, target_host, target_port, use_ssl, socks_config=None, log_id=None, http_error_transport=None): from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint from txsocksx.client import SOCKS5ClientEndpoint from txsocksx.tls import TLSWrapClientEndpoint from pappyproxy.pappy import session if socks_config is not None: log("Connecting to socks proxy", id=log_id) sock_host = socks_config['host'] sock_port = int(socks_config['port']) methods = {'anonymous': ()} if 'username' in socks_config and 'password' in socks_config: methods['login'] = (socks_config['username'], socks_config['password']) tcp_endpoint = TCP4ClientEndpoint(reactor, sock_host, sock_port) socks_endpoint = SOCKS5ClientEndpoint(target_host, target_port, tcp_endpoint, methods=methods) if use_ssl: log("Using SSL over proxy to connect to %s:%d ssl=%s" % (target_host, target_port, use_ssl), id=log_id) endpoint = TLSWrapClientEndpoint(ssl.ClientContextFactory(), socks_endpoint) else: log("Using TCP over proxy to connect to %s:%d ssl=%s" % (target_host, target_port, use_ssl), id=log_id) endpoint = socks_endpoint else: log("Connecting directly to host", id=log_id) if use_ssl: log("Using SSL to connect to %s:%d ssl=%s" % (target_host, target_port, use_ssl), id=log_id) #context = BrowserLikePolicyForHTTPS().creatorForNetloc(target_host, target_port) context = ssl.ClientContextFactory() endpoint = SSL4ClientEndpoint(reactor, target_host, target_port, context) else: log("Using TCP to connect to %s:%d ssl=%s" % (target_host, target_port, use_ssl), id=log_id) endpoint = TCP4ClientEndpoint(reactor, target_host, target_port) connection_deferred = endpoint.connect(protocol_factory) if http_error_transport: connection_deferred.addErrback(connection_error_http_response, http_error_transport, log_id)
def main(reactor): pem = generate_certs.and_generate() caPem = FilePath(b"ca-private-cert.pem").getContent() clientEndpoint = SSL4ClientEndpoint( reactor, u"localhost", 4321, optionsForClientTLS(u"the-authority", Certificate.loadPEM(caPem), PrivateCertificate.loadPEM(pem)), ) clientEndpoint = SSL4ClientEndpoint( reactor, u"localhost", 4321, optionsForClientTLS(u"the-authority", Certificate.loadPEM(caPem), PrivateCertificate.loadPEM(pem)), ) proto = yield clientEndpoint.connect(Factory.forProtocol(SendAnyData)) yield proto.deferred
def _makeEndpoint(reactor): """Creates a suitable endpoint with the given reactor. Uses clarent to create a context factory using the default data path, and then creates a SSL client endpoint with that context factory. """ ctxFactory = certificate.getContextFactory(path.getDataPath()) return SSL4ClientEndpoint(reactor, "localhost", 4430, ctxFactory)
def connectWithNode(node): ip = node['LastConnectedIP'] if node['LastConnectedIP'] != None else node[ 'LastRetrievedIP'] port = node['LastConnectedPort'] if node[ 'LastConnectedPort'] != None else node['LastRetrievedPort'] endpoint = SSL4ClientEndpoint(reactor, ip, int(port), globals.aetherClientContextFactoryInstance) endpoint.connect(aetherProtocolFactoryInstance)\ .addCallback(lambda p: p.initiateHandshake())\ .addErrback(printError, 'Connection failed because node at the address %s is not responding.'%ip)
def connectWithIP(IP, Port): cprint('CONNECT WITH IP IS CALLED FOR THE ADDRESS %s:%s' % (IP, Port), 'white', 'on_red') endpoint = SSL4ClientEndpoint(reactor, IP, Port, globals.AetherClientContextFactory()) endpoint.connect(AetherProtocolFactory())\ .addCallback(lambda p: p.initiateHandshake())\ .addErrback(printError, 'Connection failed because node at the address %s:%s is not responding to or actively ' 'refusing the connection request. It can be offline or permanently dead.' %(IP, Port))
def test_no_tcp(): from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint from txsocksx.client import SOCKS5ClientEndpoint from txsocksx.tls import TLSWrapClientEndpoint with pytest.raises(NotImplementedError): SSL4ClientEndpoint('aasdfasdf.sdfwerqwer') with pytest.raises(NotImplementedError): TCP4ClientEndpoint('aasdfasdf.sdfwerqwer') with pytest.raises(NotImplementedError): SOCKS5ClientEndpoint('aasdfasdf.sdfwerqwer') with pytest.raises(NotImplementedError): TLSWrapClientEndpoint('asdf.2341')
def connectTo(self, host, port, timeout, callbackObject, useSSL=False): """ Connects to a remote server using its arguments @attention: This is a blocking operation. The calling thread will be blocked until the connection is established or until a timeout error is detected. Args: host: host IP address port: the port where the host is listenning timeout: timeout in seconds. callbackObject: the callback object that will process all the incoming packages received through this connection. Returns: Nothing Raises: NetworkManagerException: If no answer is received after timeout seconds, the connection process will be aborted and a NetworkManagerException will be raised. """ if self.__connectionPool.has_key((host, port)): raise NetworkManagerException("The port " + str(port) + " is already in use") # The port is free => proceed # Allocate the connection resources (queue, thread) = self.__allocateConnectionResources(callbackObject) # Create and configure the endpoint factory = _CygnusCloudProtocolFactory(queue) if (not useSSL): endpoint = TCP4ClientEndpoint(reactor, host, port, timeout, None) else: keyPath = self.__certificatesDirectory + "/" + "server.key" certificatePath = self.__certificatesDirectory + "/" + "server.crt" try: endpoint = SSL4ClientEndpoint( reactor, host, port, ssl.DefaultOpenSSLContextFactory(keyPath, certificatePath)) except Exception: raise NetworkManagerException( "The key, the certificate or both were not found") endpoint.connect(factory) # Wait until the connection is ready time = 0 while factory.isDisconnected() and time <= timeout: sleep(0.01) time += 0.01 if factory.isDisconnected(): raise NetworkManagerException("The host " + host + ":" + str(port) + " seems to be unreachable") # Create the new connection connection = _NetworkConnection(False, host, port, factory, queue, thread, callbackObject) # Add the new connection to the connection pool self.__connectionPool[(host, port)] = connection
def connectWithNode(node): ip = node['LastConnectedIP'] if node['LastConnectedIP'] != None else node[ 'LastRetrievedIP'] port = node['LastConnectedPort'] if node[ 'LastConnectedPort'] != None else node['LastRetrievedPort'] endpoint = SSL4ClientEndpoint(reactor, ip, port, globals.AetherClientContextFactory()) endpoint.connect(AetherProtocolFactory())\ .addCallback(lambda p: p.initiateHandshake())\ .addErrback(printError, 'Connection failed because node %s at the address %s:%s is not responding to or actively ' 'refusing the connection request. It can be offline or permanently dead.' %(node['NodeId'], ip, port))
def get_endpoint(target_host, target_port, target_ssl, socks_config=None, use_http_proxy=False, debugid=None): # Imports go here to allow mocking for tests from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint from txsocksx.client import SOCKS5ClientEndpoint from txsocksx.tls import TLSWrapClientEndpoint from pappyproxy.pappy import session log("Getting endpoint for host '%s' on port %d ssl=%s, socks_config=%s, use_http_proxy=%s" % (target_host, target_port, target_ssl, str(socks_config), use_http_proxy), id=debugid, verbosity_level=3) if session.config.http_proxy and use_http_proxy: target_host = session.config.http_proxy['host'] target_port = session.config.http_proxy['port'] target_ssl = False # We turn on ssl after CONNECT request if needed log("Connecting to http proxy at %s:%d" % (target_host, target_port), id=debugid, verbosity_level=3) if socks_config is not None: sock_host = socks_config['host'] sock_port = int(socks_config['port']) methods = {'anonymous': ()} if 'username' in socks_config and 'password' in socks_config: methods['login'] = (socks_config['username'], socks_config['password']) tcp_endpoint = TCP4ClientEndpoint(reactor, sock_host, sock_port) socks_endpoint = SOCKS5ClientEndpoint(target_host, target_port, tcp_endpoint, methods=methods) if target_ssl: endpoint = TLSWrapClientEndpoint(ssl.ClientContextFactory(), socks_endpoint) else: endpoint = socks_endpoint else: if target_ssl: endpoint = SSL4ClientEndpoint(reactor, target_host, target_port, ssl.ClientContextFactory()) else: endpoint = TCP4ClientEndpoint(reactor, target_host, target_port) return endpoint
def _getEndpoint(self, scheme, host, port): kwargs = {} if self._connectTimeout is not None: kwargs['timeout'] = self._connectTimeout kwargs['bindAddress'] = self._bindAddress if scheme == 'http': return TCP4ClientEndpoint(self._reactor, host, port, **kwargs) elif scheme == 'shttp': return SOCKS5ClientEndpoint(self._reactor, self._sockhost, self._sockport, host, port, config.socksoptimisticdata, **kwargs) elif scheme == 'https': return SSL4ClientEndpoint(self._reactor, host, port, self._wrapContextFactory(host, port), **kwargs) else: raise SchemeNotSupported("Unsupported scheme: %r" % (scheme,))
def cbListening(port): client = Client( reactor, SSL4ClientEndpoint(reactor, interface, port.getHost().port, contextFactory, bindAddress=(interface, 0))) d = client.run(concurrency, duration) def cleanup(passthrough): d = port.stopListening() d.addCallback(lambda ignored: passthrough) return d d.addCallback(cleanup) return d
def SSLClientEndpointFactory(broker, config, timeout=None): """ :param broker: :type broker: stompest.protocol.broker.Broker :param config: :type config: stompest.config.StompConfig :param timeout: :type timeout: int :return: :rtype: twisted.internet.endpoints.SSL4ClientEndpoint """ return SSL4ClientEndpoint(reactor, host=broker.host, port=broker.port, sslContextFactory=asyncContextFactory(config), timeout=timeout)
def connect(self): """ Asks the client to connect the control protocol Returns a deferred which will callback when the connection suceeds. This can also be accessed via the controlConnected attribute. Note that this only indicates a TCP connection, which might, if the client supplies incorrect authentication details, be immediately closed. The clientConnected attribute is a Deferred which will return when the login phase is complete. :return: A Deferred """ self.point=SSL4ClientEndpoint(reactor, self.settings.host, self.settings.port,self.settings.SSLOptions) self.controlConnected = self.point.connect(_ControlFactory(self)) return self.controlConnected
def main(reactor, duration): chunkSize = 16384 server = ServerFactory() server.protocol = Echo port = reactor.listenSSL(0, server, cert.options()) client = Client( reactor, SSL4ClientEndpoint( reactor, '127.0.0.1', port.getHost().port, CertificateOptions( verify=True, requireCertificate=True, caCerts=[cert.original]))) d = client.run(duration, chunkSize) def cleanup(passthrough): d = port.stopListening() d.addCallback(lambda ignored: passthrough) return d d.addCallback(cleanup) return d
def establish(self, timeout=None): """ Tries to establish a client connection. Args: timeout: the timeout in seconds Returns: True if the connection was established, and False if it wasn't. """ Connection.establish(self, timeout) # Create and configure the endpoint if (not self._useSSL): endpoint = TCP4ClientEndpoint(reactor, self.__host, self._port, timeout, None) else: keyPath = self._certificatesDirectory + "/" + "server.key" certificatePath = self._certificatesDirectory + "/" + "server.crt" try: endpoint = SSL4ClientEndpoint( reactor, self.__host, self._port, ssl.DefaultOpenSSLContextFactory(keyPath, certificatePath), timeout) except Exception: raise ConnectionException( "The key, the certificate or both were not found") # Establish the connection self._deferred = endpoint.connect(self._factory) self.__working = True def _handleError(error): self.__working = False self._setError(Connection._prettyPrintTwistedError(error)) def _handleConnection(error): self.__working = False self._deferred.addCallback(_handleConnection) self._deferred.addErrback(_handleError) # Wait until it's ready while (self.__working): sleep(0.1) return self._error == None
options = optionsForClientTLS( hostname=AUTHORITY, acceptableProtocols=[b'h2'], trustRoot=certificate, ) class ShowCertificate(Protocol): def connectionMade(self): self.transport.write(b"GET / HTTP/1.0\r\n\r\n") self.done = defer.Deferred() def dataReceived(self, data): certificate = Certificate(self.transport.getPeerCertificate()) print("OK:", certificate) self.transport.abortConnection() def connectionLost(self, reason): print("Lost.") if not reason.check(error.ConnectionClosed): print("BAD:", reason.value) self.done.callback(None) connectProtocol( SSL4ClientEndpoint(reactor, AUTHORITY, 8445, options), #ShowCertificate(), H2Protocol(), ) reactor.run()
def _create_transport_endpoint(reactor, endpoint_config): """ Create a Twisted client endpoint for a WAMP-over-XXX transport. """ if IStreamClientEndpoint.providedBy(endpoint_config): endpoint = IStreamClientEndpoint(endpoint_config) else: # create a connecting TCP socket if endpoint_config['type'] == 'tcp': version = int(endpoint_config.get('version', 4)) host = str(endpoint_config['host']) port = int(endpoint_config['port']) timeout = int(endpoint_config.get('timeout', 10)) # in seconds tls = endpoint_config.get('tls', None) # create a TLS enabled connecting TCP socket if tls: if not _TLS: raise RuntimeError( 'TLS configured in transport, but TLS support is not installed (eg OpenSSL?)' ) # FIXME: create TLS context from configuration if IOpenSSLClientConnectionCreator.providedBy(tls): # eg created from twisted.internet.ssl.optionsForClientTLS() context = IOpenSSLClientConnectionCreator(tls) elif isinstance(tls, CertificateOptions): context = tls elif tls is True: context = optionsForClientTLS(host) else: raise RuntimeError( 'unknown type {} for "tls" configuration in transport'. format(type(tls))) if version == 4: endpoint = SSL4ClientEndpoint(reactor, host, port, context, timeout=timeout) elif version == 6: # there is no SSL6ClientEndpoint! raise RuntimeError('TLS on IPv6 not implemented') else: assert (False), 'should not arrive here' # create a non-TLS connecting TCP socket else: if version == 4: endpoint = TCP4ClientEndpoint(reactor, host, port, timeout=timeout) elif version == 6: try: from twisted.internet.endpoints import TCP6ClientEndpoint except ImportError: raise RuntimeError( 'IPv6 is not supported (please upgrade Twisted)') endpoint = TCP6ClientEndpoint(reactor, host, port, timeout=timeout) else: assert (False), 'should not arrive here' # create a connecting Unix domain socket elif endpoint_config['type'] == 'unix': path = endpoint_config['path'] timeout = int(endpoint_config.get('timeout', 10)) # in seconds endpoint = UNIXClientEndpoint(reactor, path, timeout=timeout) else: assert (False), 'should not arrive here' return endpoint
def run(self, make, start_reactor=True, auto_reconnect=False, log_level='info', endpoint=None, reactor=None): """ Run the application component. :param make: A factory that produces instances of :class:`autobahn.twisted.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :type make: callable :param start_reactor: When ``True`` (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ self.log.debug('{klass}.run()', klass=self.__class__.__name__) if start_reactor: # only select framework, set loop and start logging when we are asked # start the reactor - otherwise we are running in a program that likely # already tool care of all this. from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor txaio.start_logging(level=log_level) if callable(make): # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra, runner=self) try: session = make(cfg) except Exception: self.log.failure('ApplicationSession could not be instantiated: {log_failure.value}') if start_reactor and reactor.running: reactor.stop() raise else: return session else: create = make if self.url.startswith(u'rs'): # try to parse RawSocket URL .. isSecure, host, port = parse_rs_url(self.url) # use the first configured serializer if any (which means, auto-choose "best") serializer = self.serializers[0] if self.serializers else None # create a WAMP-over-RawSocket transport client factory transport_factory = WampRawSocketClientFactory(create, serializer=serializer) else: # try to parse WebSocket URL .. isSecure, host, port, resource, path, params = parse_ws_url(self.url) # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers) # client WebSocket settings - similar to: # - http://crossbar.io/docs/WebSocket-Compression/#production-settings # - http://crossbar.io/docs/WebSocket-Options/#production-settings # The permessage-deflate extensions offered to the server .. offers = [PerMessageDeflateOffer()] # Function to accept permessage_delate responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) # set WebSocket options for all client connections transport_factory.setProtocolOptions(maxFramePayloadSize=1048576, maxMessagePayloadSize=1048576, autoFragmentSize=65536, failByDrop=False, openHandshakeTimeout=2.5, closeHandshakeTimeout=1., tcpNoDelay=True, autoPingInterval=10., autoPingTimeout=5., autoPingSize=4, perMessageCompressionOffers=offers, perMessageCompressionAccept=accept) # supress pointless log noise transport_factory.noisy = False if endpoint: client = endpoint else: # if user passed ssl= but isn't using isSecure, we'll never # use the ssl argument which makes no sense. context_factory = None if self.ssl is not None: if not isSecure: raise RuntimeError( 'ssl= argument value passed to %s conflicts with the "ws:" ' 'prefix of the url argument. Did you mean to use "wss:"?' % self.__class__.__name__) context_factory = self.ssl elif isSecure: from twisted.internet.ssl import optionsForClientTLS context_factory = optionsForClientTLS(host) from twisted.internet import reactor if self.proxy is not None: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, self.proxy['host'], self.proxy['port']) transport_factory.contextFactory = context_factory elif isSecure: from twisted.internet.endpoints import SSL4ClientEndpoint assert context_factory is not None client = SSL4ClientEndpoint(reactor, host, port, context_factory) else: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, host, port) # as the reactor shuts down, we wish to wait until we've sent # out our "Goodbye" message; leave() returns a Deferred that # fires when the transport gets to STATE_CLOSED def cleanup(proto): if hasattr(proto, '_session') and proto._session is not None: if proto._session.is_attached(): return proto._session.leave() elif proto._session.is_connected(): return proto._session.disconnect() # when our proto was created and connected, make sure it's cleaned # up properly later on when the reactor shuts down for whatever reason def init_proto(proto): self._connect_successes += 1 reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto) return proto use_service = False if auto_reconnect: try: # since Twisted 16.1.0 from twisted.application.internet import ClientService from twisted.application.internet import backoffPolicy use_service = True except ImportError: use_service = False if use_service: # this code path is automatically reconnecting .. self.log.debug('using t.a.i.ClientService') if self.max_retries or self.initial_retry_delay or self.max_retry_delay or self.retry_delay_growth or self.retry_delay_jitter: kwargs = {} for key, val in [('initialDelay', self.initial_retry_delay), ('maxDelay', self.max_retry_delay), ('factor', self.retry_delay_growth), ('jitter', lambda: random.random() * self.retry_delay_jitter)]: if val: kwargs[key] = val # retry policy that will only try to reconnect if we connected # successfully at least once before (so it fails on host unreachable etc ..) def retry(failed_attempts): if self._connect_successes > 0 and (self.max_retries == -1 or failed_attempts < self.max_retries): return backoffPolicy(**kwargs)(failed_attempts) else: print('hit stop') self.stop() return 100000000000000 else: retry = backoffPolicy() self._client_service = ClientService(client, transport_factory, retryPolicy=retry) self._client_service.startService() d = self._client_service.whenConnected() else: # this code path is only connecting once! self.log.debug('using t.i.e.connect()') d = client.connect(transport_factory) # if we connect successfully, the arg is a WampWebSocketClientProtocol d.addCallback(init_proto) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
def create_connecting_endpoint_from_config(config, cbdir, reactor, log): """ Create a Twisted stream client endpoint from a Crossbar.io transport configuration. See: https://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IStreamClientEndpoint.html :param config: The transport configuration. :type config: dict :param cbdir: Crossbar.io node directory (we need this for Unix domain socket paths and TLS key/certificates). :type cbdir: str :param reactor: The reactor to use for endpoint creation. :type reactor: obj :returns obj -- An instance implementing IStreamClientEndpoint """ endpoint = None # a TCP endpoint # if config['type'] == 'tcp': # the TCP protocol version (v4 or v6) # version = int(config.get('version', 4)) # the host to connect to # host = str(config['host']) # the port to connect to # port = int(config['port']) # connection timeout in seconds # timeout = int(config.get('timeout', 10)) if 'tls' in config: # create a TLS client endpoint # if _HAS_TLS: # TLS client context context = _create_tls_client_context(config['tls'], cbdir, log) if version == 4: endpoint = SSL4ClientEndpoint( reactor, host, port, context, timeout=timeout, ) elif version == 6: raise Exception("TLS on IPv6 not implemented") else: raise Exception( "invalid TCP protocol version {}".format(version)) else: raise Exception( "TLS transport requested, but TLS packages not available:\n{}" .format(_LACKS_TLS_MSG)) else: # create a non-TLS client endpoint # if version == 4: endpoint = TCP4ClientEndpoint(reactor, host, port, timeout=timeout) elif version == 6: endpoint = TCP6ClientEndpoint(reactor, host, port, timeout=timeout) else: raise Exception( "invalid TCP protocol version {}".format(version)) # a Unix Domain Socket endpoint # elif config['type'] == 'unix': # the path # path = abspath(join(cbdir, config['path'])) # connection timeout in seconds # timeout = int(config.get('timeout', 10)) # create the endpoint # endpoint = UNIXClientEndpoint(reactor, path, timeout=timeout) elif config['type'] == 'twisted': endpoint = clientFromString(reactor, config['client_string']) elif config['type'] == 'tor': host = config['host'] port = config['port'] socks_port = config['tor_socks_port'] tls = config.get('tls', False) if not tls and not host.endswith('.onion'): log.warn( "Non-TLS connection traversing Tor network; end-to-end encryption advised" ) socks_endpoint = TCP4ClientEndpoint( reactor, "127.0.0.1", socks_port, ) endpoint = txtorcon.TorClientEndpoint( host, port, socks_endpoint=socks_endpoint, reactor=reactor, use_tls=tls, ) else: raise Exception("invalid endpoint type '{}'".format(config['type'])) return endpoint