Mercurial > libervia-backend
diff src/plugins/plugin_xep_0065.py @ 1570:37d4be4a9fed
plugins XEP-0260, XEP-0065: proxy handling:
- XEP-0065: Candidate.activate launch proxy activation
- XEP-0065: a candidate is individually connected with connectCandidate
- transport-info action handling can now manage candidate and proxy infos
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 08 Nov 2015 14:44:33 +0100 |
parents | 44854fb5d3b2 |
children | d5f59ba166fe |
line wrap: on
line diff
--- a/src/plugins/plugin_xep_0065.py Sun Nov 08 14:44:33 2015 +0100 +++ b/src/plugins/plugin_xep_0065.py Sun Nov 08 14:44:33 2015 +0100 @@ -257,6 +257,23 @@ raise exceptions.InternalError(u"Unknown {} type !".format(self.type)) return 2**16 * multiplier + self._local_priority + def activate(self, sid, peer_jid, client): + """Activate the proxy candidate + + Send activation request as explained in XEP-0065 § 6.3.5 + Must only be used with proxy candidates + @param sid(unicode): session id (same as for getSessionHash) + @param peer_jid(jid.JID): jid of the other peer + @return (D(domish.Element)): IQ result (or error) + """ + assert self.type == XEP_0065.TYPE_PROXY + iq_elt = client.IQ() + iq_elt['to'] = self.jid.full() + query_elt = iq_elt.addElement((NS_BS, 'query')) + query_elt['sid'] = sid + query_elt.addElement('activate', content=peer_jid.full()) + return iq_elt.send() + def startTransfer(self, session_hash=None): self.factory.startTransfer(session_hash) @@ -280,7 +297,6 @@ @param session_hash(str): hash of the session must only be used in client mode """ - log.debug(_("Protocol init")) self.connection = defer.Deferred() # called when connection/auth is done if session_hash is not None: self.server_mode = False @@ -313,7 +329,6 @@ self.transport.write(struct.pack('!3B', SOCKS5_VER, 1, AUTHMECH_ANON)) def _parseNegotiation(self): - log.debug("_parseNegotiation") try: # Parse out data ver, nmethod = struct.unpack('!BB', self.buf[:2]) @@ -348,7 +363,6 @@ pass def _parseUserPass(self): - log.debug("_parseUserPass") try: # Parse out data ver, ulen = struct.unpack('BB', self.buf[:2]) @@ -370,14 +384,12 @@ pass def sendErrorReply(self, errorcode): - log.debug("sendErrorReply") # Any other address types are not supported result = struct.pack('!BBBBIH', SOCKS5_VER, errorcode, 0, 1, 0, 0) self.transport.write(result) self.transport.loseConnection() def _parseRequest(self): - log.debug("_parseRequest") try: # Parse out data and trim buffer accordingly ver, cmd, rsvd, self.addressType = struct.unpack('!BBBB', self.buf[:4]) @@ -420,7 +432,6 @@ return None def _makeRequest(self): - log.debug("_makeRequest") # sha1 = getSessionHash(self.data["from"], self.data["to"], self.sid) hash_ = self._session_hash request = struct.pack('!5B%dsH' % len(hash_), SOCKS5_VER, CMD_CONNECT, 0, ADDR_DOMAINNAME, len(hash_), hash_, 0) @@ -428,7 +439,6 @@ self.state = STATE_CLIENT_REQUEST def _parseRequestReply(self): - log.debug("_parseRequestReply") try: ver, rep, rsvd, self.addressType = struct.unpack('!BBBB', self.buf[:4]) # Ensure we actually support the requested address type @@ -472,8 +482,6 @@ self._startNegotiation() def connectRequested(self, addr, port): - log.debug("connectRequested") - # Check that this session is expected if not self.factory.addToSession(addr, self): self.sendErrorReply(REPLY_CONN_REFUSED) @@ -497,7 +505,6 @@ self.transport.loseConnection() def connectCompleted(self, remotehost, remoteport): - log.debug("connectCompleted") if self.addressType == ADDR_IPV4: result = struct.pack('!BBBBIH', SOCKS5_VER, REPLY_SUCCESS, 0, 1, remotehost, remoteport) elif self.addressType == ADDR_DOMAINNAME: @@ -871,18 +878,36 @@ candidate.factory.connector = connector return candidate.factory.connection + def connectCandidate(self, candidate, session_hash, delay=None, profile=C.PROF_KEY_NONE): + """"Connect to a candidate + + Connection will be done with a Socks5ClientFactory + + @param candidate(Candidate): candidate to connect to + @param session_hash(unicode): hash of the session + hash is the same as hostname computer in XEP-0065 § 5.3.2 #1 + @param delay(None, float): optional delay to wait before connection, in seconds + @param profile: %(doc_profile)s + @return (D): Deferred launched when TCP connection + Socks5 connection is done + """ + factory = Socks5ClientFactory(self, session_hash, profile) + candidate.factory = factory + if delay is None: + d = defer.succeed(candidate.host) + else: + d = sat_defer.DelayedDeferred(delay, candidate.host) + d.addCallback(reactor.connectTCP, candidate.port, factory) + d.addCallback(self._addConnector, candidate) + return d + def tryCandidates(self, candidates, session_hash, connection_cb=None, connection_eb=None, profile=C.PROF_KEY_NONE): defers_list = [] for candidate in candidates: - factory = Socks5ClientFactory(self, session_hash, profile) - candidate.factory = factory delay = CANDIDATE_DELAY * len(defers_list) if candidate.type == XEP_0065.TYPE_PROXY: delay += CANDIDATE_DELAY_PROXY - d = sat_defer.DelayedDeferred(delay, candidate.host) - d.addCallback(reactor.connectTCP, candidate.port, factory) - d.addCallback(self._addConnector, candidate) + d = self.connectCandidate(candidate, session_hash, delay, profile) if connection_cb is not None: d.addCallback(lambda dummy, candidate=candidate, profile=profile: connection_cb(candidate, profile)) if connection_eb is not None: