summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xexamples/echo_client.py2
-rwxr-xr-xexamples/ping.py2
-rw-r--r--sleekxmpp/plugins/xep_0065/proxy.py13
-rw-r--r--sleekxmpp/stanza/iq.py15
-rw-r--r--sleekxmpp/test/sleektest.py3
-rw-r--r--sleekxmpp/xmlstream/matcher/__init__.py1
-rw-r--r--sleekxmpp/xmlstream/matcher/idsender.py47
-rw-r--r--sleekxmpp/xmlstream/resolver.py70
-rw-r--r--sleekxmpp/xmlstream/xmlstream.py44
9 files changed, 121 insertions, 76 deletions
diff --git a/examples/echo_client.py b/examples/echo_client.py
index 18125a0d..f2d38847 100755
--- a/examples/echo_client.py
+++ b/examples/echo_client.py
@@ -151,7 +151,7 @@ if __name__ == '__main__':
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
- xmpp.process(block=False)
+ xmpp.process(block=True)
print("Done")
else:
print("Unable to connect.")
diff --git a/examples/ping.py b/examples/ping.py
index 8fbb5655..1a1c2e94 100755
--- a/examples/ping.py
+++ b/examples/ping.py
@@ -37,7 +37,7 @@ class PingTest(sleekxmpp.ClientXMPP):
def __init__(self, jid, password, pingjid):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
if pingjid is None:
- pingjid = self.jid
+ pingjid = self.boundjid.bare
self.pingjid = pingjid
# The session_start event will be triggered when
diff --git a/sleekxmpp/plugins/xep_0065/proxy.py b/sleekxmpp/plugins/xep_0065/proxy.py
index 265d3030..fdd9f97e 100644
--- a/sleekxmpp/plugins/xep_0065/proxy.py
+++ b/sleekxmpp/plugins/xep_0065/proxy.py
@@ -88,8 +88,9 @@ class XEP_0065(base_plugin):
# Request that the proxy activate the session with the target.
self.activate(proxy, sid, to, timeout=timeout)
- self.xmpp.event('stream:%s:%s' % (sid, conn.peer_jid), conn)
- return self.get_socket(sid)
+ socket = self.get_socket(sid)
+ self.xmpp.event('stream:%s:%s' % (sid, to), socket)
+ return socket
def request_stream(self, to, sid=None, ifrom=None, block=True, timeout=None, callback=None):
if sid is None:
@@ -198,11 +199,16 @@ class XEP_0065(base_plugin):
sock = self._sessions.get(sid)
if sock:
try:
+ # sock.close() will also delete sid from self._sessions (see _connect_proxy)
sock.close()
except socket.error:
pass
+ # Though this should not be neccessary remove the closed session anyway
with self._sessions_lock:
- del self._sessions[sid]
+ if sid in self._sessions:
+ log.warn(('SOCKS5 session with sid = "%s" was not ' +
+ 'removed from _sessions by sock.close()') % sid)
+ del self._sessions[sid]
def close(self):
"""Closes all proxy sockets."""
@@ -250,6 +256,7 @@ class XEP_0065(base_plugin):
if sid in self._sessions:
del self._sessions[sid]
_close()
+ log.info('Socket closed.')
sock.close = close
sock.peer_jid = peer
diff --git a/sleekxmpp/stanza/iq.py b/sleekxmpp/stanza/iq.py
index ba945e08..e377b82f 100644
--- a/sleekxmpp/stanza/iq.py
+++ b/sleekxmpp/stanza/iq.py
@@ -9,7 +9,7 @@
from sleekxmpp.stanza.rootstanza import RootStanza
from sleekxmpp.xmlstream import StanzaBase, ET
from sleekxmpp.xmlstream.handler import Waiter, Callback
-from sleekxmpp.xmlstream.matcher import MatcherId
+from sleekxmpp.xmlstream.matcher import MatchIDSender
from sleekxmpp.exceptions import IqTimeout, IqError
@@ -193,6 +193,13 @@ class Iq(RootStanza):
"""
if timeout is None:
timeout = self.stream.response_timeout
+
+ criteria = {
+ 'id': self['id'],
+ 'self': self.stream.boundjid,
+ 'peer': self['to']
+ }
+
if callback is not None and self['type'] in ('get', 'set'):
handler_name = 'IqCallback_%s' % self['id']
if timeout_callback:
@@ -203,19 +210,19 @@ class Iq(RootStanza):
self._fire_timeout,
repeat=False)
handler = Callback(handler_name,
- MatcherId(self['id']),
+ MatchIDSender(criteria),
self._handle_result,
once=True)
else:
handler = Callback(handler_name,
- MatcherId(self['id']),
+ MatchIDSender(criteria),
callback,
once=True)
self.stream.register_handler(handler)
StanzaBase.send(self, now=now)
return handler_name
elif block and self['type'] in ('get', 'set'):
- waitfor = Waiter('IqWait_%s' % self['id'], MatcherId(self['id']))
+ waitfor = Waiter('IqWait_%s' % self['id'], MatchIDSender(criteria))
self.stream.register_handler(waitfor)
StanzaBase.send(self, now=now)
result = waitfor.wait(timeout)
diff --git a/sleekxmpp/test/sleektest.py b/sleekxmpp/test/sleektest.py
index 04fb106d..51cda3ee 100644
--- a/sleekxmpp/test/sleektest.py
+++ b/sleekxmpp/test/sleektest.py
@@ -16,7 +16,7 @@ from sleekxmpp.test import TestSocket, TestLiveSocket
from sleekxmpp.xmlstream import ET
from sleekxmpp.xmlstream import ElementBase
from sleekxmpp.xmlstream.tostring import tostring
-from sleekxmpp.xmlstream.matcher import StanzaPath, MatcherId
+from sleekxmpp.xmlstream.matcher import StanzaPath, MatcherId, MatchIDSender
from sleekxmpp.xmlstream.matcher import MatchXMLMask, MatchXPath
@@ -212,6 +212,7 @@ class SleekTest(unittest.TestCase):
matchers = {'stanzapath': StanzaPath,
'xpath': MatchXPath,
'mask': MatchXMLMask,
+ 'idsender': MatchIDSender,
'id': MatcherId}
Matcher = matchers.get(method, None)
if Matcher is None:
diff --git a/sleekxmpp/xmlstream/matcher/__init__.py b/sleekxmpp/xmlstream/matcher/__init__.py
index 1038d1bd..aa74c434 100644
--- a/sleekxmpp/xmlstream/matcher/__init__.py
+++ b/sleekxmpp/xmlstream/matcher/__init__.py
@@ -7,6 +7,7 @@
"""
from sleekxmpp.xmlstream.matcher.id import MatcherId
+from sleekxmpp.xmlstream.matcher.idsender import MatchIDSender
from sleekxmpp.xmlstream.matcher.many import MatchMany
from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath
from sleekxmpp.xmlstream.matcher.xmlmask import MatchXMLMask
diff --git a/sleekxmpp/xmlstream/matcher/idsender.py b/sleekxmpp/xmlstream/matcher/idsender.py
new file mode 100644
index 00000000..5c2c1f51
--- /dev/null
+++ b/sleekxmpp/xmlstream/matcher/idsender.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+"""
+ sleekxmpp.xmlstream.matcher.id
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Part of SleekXMPP: The Sleek XMPP Library
+
+ :copyright: (c) 2011 Nathanael C. Fritz
+ :license: MIT, see LICENSE for more details
+"""
+
+from sleekxmpp.xmlstream.matcher.base import MatcherBase
+
+
+class MatchIDSender(MatcherBase):
+
+ """
+ The IDSender matcher selects stanzas that have the same stanza 'id'
+ interface value as the desired ID, and that the 'from' value is one
+ of a set of approved entities that can respond to a request.
+ """
+
+ def match(self, xml):
+ """Compare the given stanza's ``'id'`` attribute to the stored
+ ``id`` value, and verify the sender's JID.
+
+ :param xml: The :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase`
+ stanza to compare against.
+ """
+
+ selfjid = self._criteria['self']
+ peerjid = self._criteria['peer']
+
+ allowed = {}
+ allowed[''] = True
+ allowed[selfjid.bare] = True
+ allowed[selfjid.host] = True
+ allowed[peerjid.full] = True
+ allowed[peerjid.bare] = True
+ allowed[peerjid.host] = True
+
+ _from = xml['from']
+
+ try:
+ return xml['id'] == self._criteria['id'] and allowed[_from]
+ except KeyError:
+ return False
diff --git a/sleekxmpp/xmlstream/resolver.py b/sleekxmpp/xmlstream/resolver.py
index 6f26797f..e82bfdb7 100644
--- a/sleekxmpp/xmlstream/resolver.py
+++ b/sleekxmpp/xmlstream/resolver.py
@@ -131,16 +131,16 @@ def resolve(host, port=None, service=None, proto='tcp',
results.append((host, '::1', port))
results.append((host, '127.0.0.1', port))
if use_ipv6:
- for address in get_AAAA(host, resolver=resolver):
+ for address in get_AAAA(host):
results.append((host, address, port))
- for address in get_A(host, resolver=resolver):
+ for address in get_A(host):
results.append((host, address, port))
for host, address, port in results:
yield host, address, port
-def get_A(host, resolver=None):
+def get_A(host):
"""Lookup DNS A records for a given host.
If ``resolver`` is not provided, or is ``None``, then resolution will
@@ -158,32 +158,15 @@ def get_A(host, resolver=None):
# If not using dnspython, attempt lookup using the OS level
# getaddrinfo() method.
- if resolver is None:
- try:
- recs = socket.getaddrinfo(host, None, socket.AF_INET,
- socket.SOCK_STREAM)
- return [rec[4][0] for rec in recs]
- except socket.gaierror:
- log.debug("DNS: Error retreiving A address info for %s." % host)
- return []
-
- # Using dnspython:
try:
- recs = resolver.query(host, dns.rdatatype.A)
- return [rec.to_text() for rec in recs]
- except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
- log.debug("DNS: No A records for %s" % host)
- return []
- except dns.exception.Timeout:
- log.debug("DNS: A record resolution timed out for %s" % host)
- return []
- except dns.exception.DNSException as e:
- log.debug("DNS: Error querying A records for %s" % host)
- log.exception(e)
+ recs = socket.getaddrinfo(host, None, socket.AF_INET,
+ socket.SOCK_STREAM)
+ return [rec[4][0] for rec in recs]
+ except socket.gaierror:
+ log.debug("DNS: Error retreiving A address info for %s." % host)
return []
-
-def get_AAAA(host, resolver=None):
+def get_AAAA(host):
"""Lookup DNS AAAA records for a given host.
If ``resolver`` is not provided, or is ``None``, then resolution will
@@ -201,35 +184,18 @@ def get_AAAA(host, resolver=None):
# If not using dnspython, attempt lookup using the OS level
# getaddrinfo() method.
- if resolver is None:
- if not socket.has_ipv6:
- log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host)
- return []
- try:
- recs = socket.getaddrinfo(host, None, socket.AF_INET6,
- socket.SOCK_STREAM)
- return [rec[4][0] for rec in recs]
- except (OSError, socket.gaierror):
- log.debug("DNS: Error retreiving AAAA address " + \
- "info for %s." % host)
- return []
-
- # Using dnspython:
- try:
- recs = resolver.query(host, dns.rdatatype.AAAA)
- return [rec.to_text() for rec in recs]
- except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
- log.debug("DNS: No AAAA records for %s" % host)
- return []
- except dns.exception.Timeout:
- log.debug("DNS: AAAA record resolution timed out for %s" % host)
+ if not socket.has_ipv6:
+ log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host)
return []
- except dns.exception.DNSException as e:
- log.debug("DNS: Error querying AAAA records for %s" % host)
- log.exception(e)
+ try:
+ recs = socket.getaddrinfo(host, None, socket.AF_INET6,
+ socket.SOCK_STREAM)
+ return [rec[4][0] for rec in recs]
+ except (OSError, socket.gaierror):
+ log.debug("DNS: Error retreiving AAAA address " + \
+ "info for %s." % host)
return []
-
def get_SRV(host, port, service, proto='tcp', resolver=None):
"""Perform SRV record resolution for a given host.
diff --git a/sleekxmpp/xmlstream/xmlstream.py b/sleekxmpp/xmlstream/xmlstream.py
index c503cdd2..3bc1f652 100644
--- a/sleekxmpp/xmlstream/xmlstream.py
+++ b/sleekxmpp/xmlstream/xmlstream.py
@@ -123,6 +123,11 @@ class XMLStream(object):
#: xmpp.ssl_version = ssl.PROTOCOL_SSLv23
self.ssl_version = ssl.PROTOCOL_TLSv1
+ #: The list of accepted ciphers, in OpenSSL Format.
+ #: It might be useful to override it for improved security
+ #: over the python defaults.
+ self.ciphers = None
+
#: Path to a file containing certificates for verifying the
#: server SSL certificate. A non-``None`` value will trigger
#: certificate checking.
@@ -508,12 +513,18 @@ class XMLStream(object):
else:
cert_policy = ssl.CERT_REQUIRED
- ssl_socket = ssl.wrap_socket(self.socket,
- certfile=self.certfile,
- keyfile=self.keyfile,
- ca_certs=self.ca_certs,
- cert_reqs=cert_policy,
- do_handshake_on_connect=False)
+ ssl_args = {
+ 'certfile': self.certfile,
+ 'keyfile': self.keyfile,
+ 'ca_certs': self.ca_certs,
+ 'cert_reqs': cert_policy,
+ 'do_handshake_on_connect': False,
+ }
+
+ if sys.version_info >= (2, 7):
+ ssl_args['ciphers'] = self.ciphers
+
+ ssl_socket = ssl.wrap_socket(self.socket, **ssl_args)
if hasattr(self.socket, 'socket'):
# We are using a testing socket, so preserve the top
@@ -826,13 +837,18 @@ class XMLStream(object):
else:
cert_policy = ssl.CERT_REQUIRED
- ssl_socket = ssl.wrap_socket(self.socket,
- certfile=self.certfile,
- keyfile=self.keyfile,
- ssl_version=self.ssl_version,
- do_handshake_on_connect=False,
- ca_certs=self.ca_certs,
- cert_reqs=cert_policy)
+ ssl_args = {
+ 'certfile': self.certfile,
+ 'keyfile': self.keyfile,
+ 'ca_certs': self.ca_certs,
+ 'cert_reqs': cert_policy,
+ 'do_handshake_on_connect': False,
+ }
+
+ if sys.version_info >= (2, 7):
+ ssl_args['ciphers'] = self.ciphers
+
+ ssl_socket = ssl.wrap_socket(self.socket, **ssl_args);
if hasattr(self.socket, 'socket'):
# We are using a testing socket, so preserve the top
@@ -1327,12 +1343,12 @@ class XMLStream(object):
return True
def _start_thread(self, name, target, track=True):
- self.__active_threads.add(name)
self.__thread[name] = threading.Thread(name=name, target=target)
self.__thread[name].daemon = self._use_daemons
self.__thread[name].start()
if track:
+ self.__active_threads.add(name)
with self.__thread_cond:
self.__thread_count += 1