def set_attacher(self, attacher, myreactor): """ Provide an :class:`txtorcon.interface.IStreamAttacher` to associate streams to circuits. This won't get turned on until after bootstrapping is completed. ('__LeaveStreamsUnattached' needs to be set to '1' and the existing circuits list needs to be populated). """ react = IReactorCore(myreactor) if attacher: self.attacher = IStreamAttacher(attacher) else: self.attacher = None if self.attacher is None: self.undo_attacher() if self.cleanup: react.removeSystemEventTrigger(self.cleanup) self.cleanup = None else: self.protocol.set_conf("__LeaveStreamsUnattached", "1") self.cleanup = react.addSystemEventTrigger('before', 'shutdown', self.undo_attacher) return None
def _maybe_attach(self, stream): """ If we've got a custom stream-attachment instance (see set_attacher) this will ask it for the appropriate circuit. Note that we ignore .exit URIs and let Tor deal with those (by passing circuit ID 0). The stream attacher is allowed to return a Deferred which will callback with the desired circuit. You may return the special object DO_NOT_ATTACH which will cause the circuit attacher to simply ignore the stream (neither attaching it, nor telling Tor to attach it). """ if self.attacher: if stream.target_host is not None and '.exit' in stream.target_host: ## we want to totally ignore .exit URIs as these are ## used to specify a particular exit node, and trying ## to do STREAMATTACH on them will fail with an error ## from Tor anyway. txtorlog.msg("ignore attacher:", stream) return circ = IStreamAttacher(self.attacher).attach_stream( stream, self.circuits) if circ is self.DO_NOT_ATTACH: return if circ is None: self.protocol.queue_command("ATTACHSTREAM %d 0" % stream.id) else: if isinstance(circ, defer.Deferred): class IssueStreamAttach: def __init__(self, state, streamid): self.stream_id = streamid self.state = state def __call__(self, arg): circid = arg.id self.state.protocol.queue_command( "ATTACHSTREAM %d %d" % (self.stream_id, circid)) circ.addCallback(IssueStreamAttach( self, stream.id)).addErrback(log.err) else: if circ.id not in self.circuits: raise RuntimeError( "Attacher returned a circuit unknown to me.") if circ.state != 'BUILT': raise RuntimeError( "Can only attach to BUILT circuits; %d is in %s." % (circ.id, circ.state)) self.protocol.queue_command("ATTACHSTREAM %d %d" % (stream.id, circ.id))
def set_attacher(self, attacher, myreactor): """ Provide an :class:`txtorcon.interface.IStreamAttacher` to associate streams to circuits. You are Strongly Encouraged to **not** use this API directly, and instead use :meth:`txtorcon.Circuit.stream_via` or :meth:`txtorcon.Circuit.web_agent` instead. If you do need to use this API, it's an error if you call either of the other two methods. This won't get turned on until after bootstrapping is completed. ('__LeaveStreamsUnattached' needs to be set to '1' and the existing circuits list needs to be populated). """ react = IReactorCore(myreactor) if attacher: if self._attacher is attacher: return if self._attacher is not None: raise RuntimeError( "set_attacher called but we already have an attacher") self._attacher = IStreamAttacher(attacher) else: self._attacher = None if self._attacher is None: d = self.undo_attacher() if self._cleanup: react.removeSystemEventTrigger(self._cleanup) self._cleanup = None else: d = self.protocol.set_conf("__LeaveStreamsUnattached", "1") self._cleanup = react.addSystemEventTrigger( 'before', 'shutdown', self.undo_attacher, ) return d