PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sockets.py

https://github.com/Dischi/kaa-base
Python | 757 lines | 535 code | 67 blank | 155 comment | 85 complexity | 411b3d086446cb3889f59e69d0b28ac3 MD5 | raw file
Possible License(s): LGPL-2.1
  1. # -*- coding: iso-8859-1 -*-
  2. # -----------------------------------------------------------------------------
  3. # sockets.py - TCP/Unix Socket for the Kaa Framework
  4. # -----------------------------------------------------------------------------
  5. # kaa.base - The Kaa Application Framework
  6. # Copyright 2005-2012 Dirk Meyer, Jason Tackaberry, et al.
  7. #
  8. # Please see the file AUTHORS for a complete list of authors.
  9. #
  10. # This library is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU Lesser General Public License version
  12. # 2.1 as published by the Free Software Foundation.
  13. #
  14. # This library is distributed in the hope that it will be useful, but
  15. # WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. # Lesser General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Lesser General Public
  20. # License along with this library; if not, write to the Free Software
  21. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. # 02110-1301 USA
  23. #
  24. # -----------------------------------------------------------------------------
  25. from __future__ import absolute_import
  26. __all__ = [ 'Socket', 'SocketError' ]
  27. import sys
  28. import errno
  29. import os
  30. import re
  31. import socket
  32. import logging
  33. import ctypes.util
  34. import collections
  35. from .errors import SocketError
  36. from .utils import property, tempfile
  37. from .thread import threaded
  38. from .async import InProgress
  39. from .io import IO_READ, IO_WRITE, IOChannel, WeakIOMonitor
  40. # get logging object
  41. log = logging.getLogger('kaa.base.sockets')
  42. TIMEOUT_SENTINEL = getattr(socket, '_GLOBAL_DEFAULT_TIMEOUT', object())
  43. # Implement functions for converting between interface names and indexes.
  44. # Unfortunately these functions are not provided by the standard Python
  45. # socket library, so we must implement them ourselves with ctypes.
  46. def _libc():
  47. """
  48. On-demand loading of libc. Don't do this at initial import as the overhead
  49. is non-trivial.
  50. """
  51. try:
  52. return _libc._lib
  53. except AttributeError:
  54. pass
  55. _libc._lib = None
  56. if ctypes.util.find_library('c'):
  57. # ctypes in python >= 2.6 supports errno.
  58. kwargs = {'use_errno': True} if sys.hexversion >= 0x02060000 else {}
  59. _libc._lib = ctypes.CDLL(ctypes.util.find_library('c'), **kwargs)
  60. return _libc._lib
  61. def if_nametoindex(name):
  62. """
  63. Returns the interface index number for the given interface name.
  64. :param name: name of the interface
  65. :type name: str
  66. :returns: integer of the interface id
  67. :raises: ValueError if the interface name cannot be found;
  68. NotImplementedError on unsupported platforms.
  69. """
  70. try:
  71. idx = _libc().if_nametoindex(name)
  72. except AttributeError:
  73. raise NotImplementedError('Platform does not support if_nametoindex()')
  74. if idx <= 0:
  75. raise ValueError('Interface "%s" not found' % name)
  76. return idx
  77. def if_indextoname(idx):
  78. """
  79. Returns the interface name for the given interface index number.
  80. :param idx: the index for the interface
  81. :type idx: int
  82. :returns: name of the index
  83. :raises: ValueError if the interface index is not found;
  84. NotImplementedError on unsupported platforms.
  85. """
  86. # Array must be at least IF_NAMESIZE, which is 16. Double it for good measure.
  87. name = ctypes.create_string_buffer(32)
  88. try:
  89. ret = _libc().if_indextoname(idx, name)
  90. except AttributeError:
  91. raise NotImplementedError('Platform does not support if_indextoname()')
  92. if not ret:
  93. err = 'Failed to lookup interface index %d' % idx
  94. if hasattr(ctypes, 'get_errno'):
  95. err += ': ' + os.strerror(ctypes.get_errno())
  96. raise ValueError(err)
  97. return name.value
  98. class Socket(IOChannel):
  99. """
  100. Communicate over TCP or Unix sockets, implementing fully asynchronous reads
  101. and writes.
  102. kaa.Socket requires an IPv6-capable stack, and favors IPv6 connectivity
  103. when available. This should generally be completely transparent on
  104. IPv4-only networks. See :meth:`~kaa.Socket.connect` for more information.
  105. """
  106. __kaasignals__ = {
  107. 'new-client-connecting':
  108. '''
  109. Emitted when a new client is attempting to connect to a listening
  110. socket, but before the connection is accepted.
  111. ``def callback(...)``
  112. If :attr:`~kaa.Socket.auto_accept` is True (default), this signal
  113. can be used to prevent the client connection by returning False from
  114. the callback. If False, the callback must explicitly call
  115. :meth:`~kaa.Socket.listen` or the client will not be connected.
  116. ''',
  117. 'new-client':
  118. '''
  119. Emitted when a new client connects to a listening socket.
  120. ``def callback(client, ...)``
  121. :param client: the new client that just connected.
  122. :type client: :class:`~kaa.Socket` object
  123. '''
  124. }
  125. @staticmethod
  126. def normalize_address(addr):
  127. """
  128. Converts supported address formats into a normalized 4-tuple (hostname,
  129. port, flowinfo, scope). See connect() and listen() for supported
  130. formats.
  131. Service names are resolved to port numbers, and interface names are
  132. resolved to scope ids. However, hostnames are not resolved to IPs
  133. since that can block. Unspecified port or interface name will produced
  134. 0 values for those fields.
  135. A non-absolute unix socket name will converted to a full path using
  136. kaa.tempfile().
  137. If we can't make sense of the given address, a ValueError exception will
  138. be raised.
  139. """
  140. if isinstance(addr, int):
  141. # Only port number specified; translate to tuple that can be
  142. # used with socket.bind()
  143. return ('', addr, 0, 0)
  144. elif isinstance(addr, basestring):
  145. m = re.match(r'^(\d+\.\d+\.\d+\.\d+)(?::(\d+))?', addr)
  146. if m:
  147. # It's an IPv4 address.
  148. return (m.group(1), int(m.group(2) or 0), 0, 0)
  149. elif ':' not in addr:
  150. # Treat as unix socket.
  151. return tempfile(addr) if not addr.startswith('/') else addr
  152. # See if it's an IPv6 address
  153. m = re.match(r'^ (\[(?:[\da-fA-F:]+)\] | (?:[^:]+) )? (?::(\w+))? (?:%(\w+))? ', addr, re.X)
  154. if not m:
  155. raise ValueError('Invalid format for address')
  156. addr = m.group(1) or '', m.group(2) or 0, 0, m.group(3) or 0
  157. if addr[0].isdigit():
  158. # Sanity check: happens when given ipv6 address without []
  159. raise ValueError('Invalid hostname: perhaps ipv6 address is not wrapped in []?')
  160. elif not isinstance(addr, (tuple, list)) or len(addr) not in (2, 4):
  161. raise ValueError('Invalid address specification (must be str, or 2- or 4-tuple)')
  162. if len(addr) == 2:
  163. # Coerce to 4-tuple, assume 0 for both scope and flowid.
  164. addr = addr + (0, 0)
  165. host, service, flowinfo, scopeid = addr
  166. # Strip [] from ipv6 addr
  167. if host.startswith('[') and host.endswith(']'):
  168. host = host[1:-1]
  169. # Resolve service name to port number
  170. if isinstance(service, basestring):
  171. service = int(service) if service.isdigit() else socket.getservbyname(service)
  172. # Resolve interface names to index values
  173. if isinstance(scopeid, basestring):
  174. scopeid = int(scopeid) if scopeid.isdigit() else if_nametoindex(scopeid)
  175. return host, service, flowinfo, scopeid
  176. @staticmethod
  177. def create_connection(addr=None, timeout=TIMEOUT_SENTINEL, source_address=None,
  178. overwrite=False, ipv6=True):
  179. addr = Socket.normalize_address(addr) if addr else None
  180. source_address = Socket.normalize_address(source_address) if source_address else None
  181. if isinstance(addr, str) or isinstance(source_address, str):
  182. sockaddr = addr or source_address
  183. if overwrite and os.path.exists(sockaddr):
  184. # Unix socket exists; test to see if it's active.
  185. try:
  186. dummy = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  187. dummy.connect(sockaddr)
  188. except socket.error, (err, msg):
  189. if err == errno.ECONNREFUSED:
  190. # Socket is not active, so we can remove it.
  191. log.debug('Replacing dead unix socket at %s' % sockaddr)
  192. else:
  193. # Reraise unexpected exception
  194. raise
  195. else:
  196. # We were able to connect to the existing socket, so it's
  197. # in use. We won't overwrite it.
  198. raise IOError(errno.EADDRINUSE, 'Address already in use')
  199. os.unlink(sockaddr)
  200. sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  201. if addr:
  202. sock.connect(addr)
  203. else:
  204. sock.bind(source_address)
  205. return sock
  206. # Not a unix socket ...
  207. req_family = socket.AF_UNSPEC if ipv6 else socket.AF_INET
  208. addr_addrinfo = source_addrinfo = None
  209. if source_address:
  210. # If link-local address is specified, make sure the scopeid is given.
  211. if source_address[0].lower().startswith('fe80::'):
  212. if not source_address[3]:
  213. raise ValueError('Binding to a link-local address requires scopeid')
  214. elif not source_address[0]:
  215. source_addrinfo = [(socket.AF_INET, socket.SOCK_STREAM, 0, 0, source_address)]
  216. elif source_address[0] == '::' and ipv6:
  217. source_addrinfo = [(socket.AF_INET6, socket.SOCK_STREAM, 0, 0, source_address)]
  218. else:
  219. source_addrinfo = socket.getaddrinfo(source_address[0], source_address[1],
  220. req_family, socket.SOCK_STREAM)
  221. if not source_addrinfo:
  222. raise socket.error('getaddrinfo returned empty list for source address')
  223. if addr:
  224. addr_addrinfo = socket.getaddrinfo(addr[0], addr[1], req_family, socket.SOCK_STREAM)
  225. if not addr_addrinfo:
  226. raise socket.error('getaddrinfo returned empty list for destination address')
  227. # At least on Linux, returned list is ordered to prefer IPv6 addresses
  228. # provided that a route is available to them. We try all addresses
  229. # until we get a connection, and if all addresses fail, then we raise
  230. # the _first_ exception.
  231. err = sock = None
  232. for res in (source_addrinfo or [(None,) * 5]):
  233. b_af, b_socktype, b_proto, b_cn, b_sa = res
  234. if b_af is not None:
  235. try:
  236. sock = socket.socket(b_af, b_socktype, b_proto)
  237. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  238. b_sa = b_sa[:2] + source_address[2:]
  239. sock.bind(b_sa if b_af == socket.AF_INET6 else b_sa[:2])
  240. except socket.error:
  241. err = sys.exc_info() if not err else err
  242. sock = None
  243. continue
  244. if not addr_addrinfo and sock:
  245. # Nothing to connect to and we bound successfully, so done.
  246. return sock
  247. for (af, socktype, proto, cn, sa) in addr_addrinfo:
  248. if b_af is not None and af != b_af:
  249. # Different address family than socket was bound to.
  250. continue
  251. try:
  252. if not sock:
  253. sock = socket.socket(af, socktype, proto)
  254. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  255. if timeout is not TIMEOUT_SENTINEL:
  256. sock.settimeout(timeout)
  257. sock.connect(sa)
  258. return sock
  259. except socket.error:
  260. err = sys.exc_info() if not err else err
  261. sock = None
  262. else:
  263. if err:
  264. raise err[0], err[1], err[2]
  265. else:
  266. raise socket.error('destination had no addresses in source address family')
  267. def __init__(self, buffer_size=None, chunk_size=1024*1024):
  268. self._connecting = False
  269. self._listening = False
  270. self._buffer_size = buffer_size
  271. # Requested hostname passed to connect()
  272. self._reqhost = None
  273. self._auto_accept = True
  274. # If an InProgress object then there is an accept() call in progress,
  275. # otherwise None.
  276. self._accept_inprogress = None
  277. super(Socket, self).__init__(chunk_size=chunk_size)
  278. def _make_new(self):
  279. return self.__class__()
  280. @IOChannel.fileno.getter
  281. def fileno(self):
  282. # If fileno() is accessed on a closed socket, socket.error is
  283. # railsed. So we override our superclass's implementation to
  284. # handle this case.
  285. try:
  286. return self._channel.fileno()
  287. except (AttributeError, socket.error):
  288. return None
  289. @property
  290. def auto_accept(self):
  291. """
  292. If True (default), automatically accept new clients connecting to
  293. listening sockets.
  294. See :meth:`listen` for more details.
  295. """
  296. return self._auto_accept
  297. @auto_accept.setter
  298. def auto_accept(self, value):
  299. self._auto_accept = value
  300. @property
  301. def address(self):
  302. """
  303. This property is deprecated; use *peer* instead.
  304. """
  305. log.warning('Socket.address is deprecated; use Socket.peer instead')
  306. return self.local[:2]
  307. @property
  308. def local(self):
  309. """
  310. Information about the local side of the socket.
  311. This is either the tuple ``(host, port, flowinfo, scopeid, scope)``
  312. representing the local end of a TCP socket, or the string containing
  313. the name of a Unix socket.
  314. *scope* is the interface name represented by *scopeid*, and is None if
  315. *scopeid* is 0.
  316. On Python 2.6 and later, the returned value is a namedtuple.
  317. """
  318. return self._make_address_tuple(self._channel.getsockname())
  319. @property
  320. def peer(self):
  321. """
  322. Information about the remote side of the socket.
  323. This is a tuple ``(host, port, flowinfo, scopeid, scope, reqhost)``
  324. representing the remote end of the socket.
  325. *scope* is the interface name represented by *scopeid*, and is None if
  326. *scopeid* is 0. *reqhost* is the requested hostname if
  327. :meth:`~kaa.Socket.connect` was called, or None if this is a listening
  328. socket.
  329. On Python 2.6 and later, the returned value is a namedtuple.
  330. """
  331. return self._make_address_tuple(self._channel.getpeername(), self._reqhost)
  332. @property
  333. def listening(self):
  334. """
  335. True if this is a listening socket, and False otherwise.
  336. """
  337. return self._listening
  338. @property
  339. def connecting(self):
  340. """
  341. True if the socket is in the process of establishing a connection
  342. but is not yet connected.
  343. Once the socket is connected, the connecting property will be False,
  344. but the :attr:`connected` property will be True.
  345. """
  346. return self._connecting
  347. @property
  348. def connected(self):
  349. """
  350. True when the socket is currently connected to a peer.
  351. When a socket is in the process of :attr:`connecting`, it is not
  352. considered connected, although it is considered :attr:`alive`.
  353. .. note::
  354. This property will not change until a :meth:`read` or :meth:`write`
  355. is attempted on the socket. Only then can it be determined if
  356. the socket has disconnected.
  357. .. warning::
  358. When you want to read all data from the socket until it closes,
  359. you should use the :attr:`readable` property instead.
  360. """
  361. return self._channel != None and not self._close_inprogress and not self._listening
  362. @property
  363. def alive(self):
  364. """
  365. True if the socket is :attr:`connected`, :attr:`listening`, or
  366. :attr:`connecting`.
  367. """
  368. # Unroll these properties: connected or connecting
  369. return (self._channel != None and not self._close_inprogress) or self._connecting
  370. @IOChannel.readable.getter
  371. def readable(self):
  372. """
  373. True if :meth:`read` may be called.
  374. A socket is considered readable when it is :attr:`alive`, or if it's
  375. closed but there is buffered data to be read.
  376. Because of the presence of a read buffer, you should test this property
  377. to determine if you should :meth:`read`, not the :attr:`connected`
  378. property::
  379. while socket.readable:
  380. data = yield socket.read()
  381. [...]
  382. .. note::
  383. A value of True does not mean there **is** data available, but
  384. rather that there could be and that a :meth:`read` call is possible
  385. (however that :meth:`read` call may return None, in which case the
  386. readable property will subsequently be False because the socket is
  387. disconnected).
  388. """
  389. # Note: this property is used in superclass's _update_read_monitor()
  390. # Unroll these properties: alive or super(readable)
  391. return (self._channel != None and not self._close_inprogress) or \
  392. self._connecting or self._read_queue.tell() > 0
  393. @property
  394. def buffer_size(self):
  395. """
  396. Size of the send and receive socket buffers (SO_SNDBUF and SO_RCVBUF)
  397. in bytes.
  398. Setting this to higher values (say 1M) improves performance when
  399. sending large amounts of data across the socket. Note that the upper
  400. bound may be restricted by the kernel. (Under Linux, this can be tuned
  401. by adjusting /proc/sys/net/core/[rw]mem_max)
  402. """
  403. return self._buffer_size
  404. @buffer_size.setter
  405. def buffer_size(self, size):
  406. self._buffer_size = size
  407. if self._channel and size:
  408. self._set_buffer_size(self._channel, size)
  409. def _set_buffer_size(self, s, size):
  410. """
  411. Sets the send and receive buffers of the given socket s to size.
  412. """
  413. s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, size)
  414. s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, size)
  415. def _make_address_tuple(self, addr, *args):
  416. """
  417. Converts an AF_INET6 socket address to a 5- or 6-tuple for use with the
  418. *local* and *peer* properties. IPv4-mapped IPv6 addresses are
  419. converted to standard IPv4 dotted quads.
  420. On Python 2.6 and later, this returns a namedtuple.
  421. """
  422. if isinstance(addr, basestring):
  423. # Unix socket
  424. return addr
  425. if len(addr) == 2:
  426. addr += (None, None, None)
  427. else:
  428. try:
  429. addr += (if_indextoname(addr[3]),)
  430. except (ValueError, NotImplementedError):
  431. addr += (None,)
  432. # reqhost = args[0] if args else None
  433. addr += (args[0] if args else None,)
  434. # ip = addr[0][7:] if addr[0].lower().startswith('::ffff:') else addr[0]
  435. #addr = (ip,) + addr[1:] + (scope,) + ((reqhost,) if args else ())
  436. if sys.hexversion < 0x02060000:
  437. return addr
  438. fields = 'host port flowinfo scopeid scope' + (' reqhost' if args else '')
  439. return collections.namedtuple('address', fields)(*addr)
  440. def listen(self, addr, backlog=5, ipv6=True):
  441. """
  442. Set the socket to accept incoming connections.
  443. :param addr: Binds the socket to this address. If an int, this
  444. specifies a TCP port that is bound on all interfaces; if a
  445. str, it is either a Unix socket path or represents a TCP
  446. socket when in the form ``[host]:[service][%scope]``.
  447. See below for further details.
  448. :type addr: int, str, or 2- or 4-tuple
  449. :param backlog: the maximum length to which the queue of pending
  450. connections for the socket may grow.
  451. :type backlog: int
  452. :param ipv6: if True, will prefer binding to IPv6 addresses if addr is
  453. a hostname that contains both AAAA and A records. If addr
  454. is specified as an IP address, this argument does nothing.
  455. :type ipv6: bool
  456. :raises: ValueError if *addr* is invalid, or socket.error if the bind fails.
  457. If *addr* is given as a 4-tuple, it is in the form ``(host, service,
  458. flowinfo, scope)``. If passed as a 2-tuple, it is in the form
  459. ``(host, service)``, and in this case, it is assumed that *flowinfo* and
  460. *scope* are both 0. See :meth:`~kaa.Socket.connect` for more
  461. information.
  462. If *host* is given as a string, it is treated as a Unix socket path if it
  463. does not contain ``:``, otherwise it is specified as ``[host]:[service][%scope]``,
  464. where ``[x]`` indicates that ``x`` is optional, and where:
  465. * *host* is a hostname, an IPv4 dotted quad, or an IPv6 address
  466. wrapped in square brackets. e.g. localhost, 192.168.0.1,
  467. [3000::1]. If host is not specified, the socket will listen on
  468. all interfaces.
  469. * *service* is a service name or port number. e.g. http, 80
  470. * *scope* is an interface name or number. e.g. eth0, 2
  471. When binding to a link-local address (``fe80::/16``), *scope* must be
  472. specified. Relative Unix socket names (those not prefixed with
  473. ``/``) are created via kaa.tempfile.
  474. .. warning::
  475. If the bind address supplied is a hostname rather than an IPv4 or
  476. IPv6 address, this function will block in order to resolve the
  477. hostname if the name is not specified in /etc/hosts. (In other words,
  478. ``localhost`` is probably safe.)
  479. Once listening, new connections are automatically accepted, and the
  480. :attr:`~kaa.Socket.signals.new-client` signal is emitted for each new
  481. connection. Callbacks connecting to the signal will receive a new
  482. Socket object representing the client connection.
  483. """
  484. sock = Socket.create_connection(source_address=addr, overwrite=True)
  485. sock.listen(backlog)
  486. self._listening = True
  487. self.wrap(sock, IO_READ | IO_WRITE)
  488. @threaded()
  489. def _connect(self, addr, source_address=None, ipv6=True):
  490. sock = Socket.create_connection(addr, source_address=source_address, ipv6=ipv6)
  491. # Normalize and store hostname
  492. addr = Socket.normalize_address(addr)
  493. if type(addr) == str:
  494. # Unix socket, just connect.
  495. self._reqhost = addr
  496. else:
  497. self._reqhost = addr[0]
  498. try:
  499. self.wrap(sock, IO_READ | IO_WRITE)
  500. finally:
  501. self._connecting = False
  502. def connect(self, addr, source_address=None, ipv6=True):
  503. """
  504. Connects to the host specified in address.
  505. :param addr: Address for a remote host, or a Unix socket. If a str,
  506. it is either a Unix socket path or represents a TCP
  507. socket when in the form ``host:service[%scope]``. See
  508. below for further details.
  509. :type addr: str, or 2- or 4-tuple
  510. :param ipv6: if True, will connect to the remote host using IPv6 if
  511. it is reachable via IPv6. This is perfectly safe for IPv4
  512. only hosts too. Set this to False if the remote host
  513. has a AAAA record and the local host has an IPv6 route to
  514. it, but you want to force IPv4 anyway.
  515. :returns: An :class:`~kaa.InProgress` object.
  516. If *addr* is given as a 4-tuple, it is in the form ``(host, service,
  517. flowinfo, scope)``. If given as a 2-tuple, it is in the form ``(host,
  518. service)``, and in this case the *flowinfo* and *scope* are assumed to
  519. be 0.
  520. The *flowinfo* and *scope* fields are only relevant for IPv6 hosts,
  521. where they represent the ``sin6_flowinfo`` and ``sin6_scope_id``
  522. members in :const:`struct sockaddr_in6` in C. *scope* may be the name
  523. of an interface (e.g. ``eth0``) or an interface id, and is needed when
  524. connecting to link-local addresses (``fe80::/16``).
  525. If *addr* is given as a string, it is treated as a Unix socket path if it
  526. does not contain ``:``, otherwise it is specified as ``host:service[%scope]``,
  527. where ``[x]`` indicates that ``x`` is optional, and where:
  528. * *host* is a hostname, an IPv4 dotted quad, or an IPv6 address
  529. wrapped in square brackets. e.g. freevo.org, 192.168.0.1,
  530. [3000::1]
  531. * *service* is a service name or port number. e.g. http, 80
  532. * *scope* is an interface name or number. e.g. eth0, 2
  533. When connecting to a link-local address (fe80::/16), *scope* must be
  534. specified. Relative Unix socket names (those not prefixed with ``/``)
  535. are created via :func:`kaa.tempfile`.
  536. This function is executed in a thread to avoid blocking. It therefore
  537. returns an InProgress object. If the socket is connected, the InProgress
  538. is finished with no arguments. If the connection cannot be established,
  539. an exception is thrown to the InProgress.
  540. """
  541. if self._connecting:
  542. raise SocketError('connection already in progress')
  543. elif self.connected:
  544. raise SocketError('socket already connected')
  545. self._connecting = True
  546. return self._connect(addr, source_address, ipv6)
  547. def wrap(self, sock, mode=IO_READ|IO_WRITE):
  548. """
  549. Wraps an existing low-level socket object.
  550. addr specifies the 4-tuple address corresponding to the socket.
  551. """
  552. super(Socket, self).wrap(sock, mode)
  553. if sock and self._buffer_size:
  554. self._set_buffer_size(sock, self._buffer_size)
  555. return self
  556. def _is_read_connected(self):
  557. return self._listening or super(Socket, self)._is_read_connected()
  558. def _set_non_blocking(self):
  559. self._channel.setblocking(False)
  560. def _read(self, size):
  561. return self._channel.recv(size)
  562. def _write(self, data):
  563. return self._channel.send(data)
  564. def _accept(self):
  565. """
  566. Accept a new connection and return a new Socket object.
  567. """
  568. sock, addr = self._channel.accept()
  569. # create new Socket from the same class this object is
  570. client_socket = self._make_new()
  571. client_socket.wrap(sock, IO_READ | IO_WRITE)
  572. self.signals['new-client'].emit(client_socket)
  573. if self._accept_inprogress:
  574. accept_inprogress = self._accept_inprogress
  575. self._accept_inprogress = None
  576. accept_inprogress.finish(client_socket)
  577. def accept(self):
  578. if not self._accept_inprogress:
  579. self._accept_inprogress = InProgress()
  580. return self._accept_inprogress
  581. def _handle_read(self):
  582. if self._listening:
  583. # Give callbacks on the new-client-connecting signal the chance to
  584. # abort the autoaccept (if applicable). If we have an explicit
  585. # accept() in progress then it can't be aborted, but we still emit
  586. # anyway for notification purposes.
  587. aborted = self.signals['new-client-connecting'].emit() == False
  588. if (self._auto_accept and not aborted) or self._accept_inprogress:
  589. return self._accept()
  590. return super(Socket, self)._handle_read()
  591. def _close(self):
  592. super(Socket, self)._close()
  593. self._reqhost = None
  594. if self._listening and isinstance(self.local, basestring) and self.local.startswith('/'):
  595. # Remove unix socket if it exists.
  596. try:
  597. os.unlink(self.local)
  598. except OSError:
  599. pass
  600. def steal(self, socket):
  601. if not isinstance(socket, Socket):
  602. raise TypeError('Can only steal from other sockets')
  603. self._buffer_size = socket._buffer_size
  604. return super(Socket, self).steal(socket)