/Lib/socket.py
Python | 1923 lines | 1762 code | 93 blank | 68 comment | 88 complexity | a078b219f931826a6be23f9d533fce2f MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
- """
- This is an updated socket module for use on JVMs >= 1.5; it is derived from the old jython socket module.
- It is documented, along with known issues and workarounds, on the jython wiki.
- http://wiki.python.org/jython/NewSocketModule
- """
- _defaulttimeout = None
- import errno
- import jarray
- import string
- import struct
- import sys
- import threading
- import time
- import types
- # Java.io classes
- import java.io.BufferedInputStream
- import java.io.BufferedOutputStream
- # Java.io exceptions
- import java.io.InterruptedIOException
- import java.io.IOException
- # Java.lang classes
- import java.lang.String
- # Java.lang exceptions
- import java.lang.Exception
- # Java.net classes
- import java.net.DatagramPacket
- import java.net.InetAddress
- import java.net.InetSocketAddress
- import java.net.Socket
- # Java.net exceptions
- import java.net.BindException
- import java.net.ConnectException
- import java.net.NoRouteToHostException
- import java.net.PortUnreachableException
- import java.net.ProtocolException
- import java.net.SocketException
- import java.net.SocketTimeoutException
- import java.net.UnknownHostException
- # Java.nio classes
- import java.nio.ByteBuffer
- import java.nio.channels.DatagramChannel
- import java.nio.channels.ServerSocketChannel
- import java.nio.channels.SocketChannel
- # Java.nio exceptions
- import java.nio.channels.AlreadyConnectedException
- import java.nio.channels.AsynchronousCloseException
- import java.nio.channels.CancelledKeyException
- import java.nio.channels.ClosedByInterruptException
- import java.nio.channels.ClosedChannelException
- import java.nio.channels.ClosedSelectorException
- import java.nio.channels.ConnectionPendingException
- import java.nio.channels.IllegalBlockingModeException
- import java.nio.channels.IllegalSelectorException
- import java.nio.channels.NoConnectionPendingException
- import java.nio.channels.NonReadableChannelException
- import java.nio.channels.NonWritableChannelException
- import java.nio.channels.NotYetBoundException
- import java.nio.channels.NotYetConnectedException
- import java.nio.channels.UnresolvedAddressException
- import java.nio.channels.UnsupportedAddressTypeException
- # Javax.net.ssl classes
- import javax.net.ssl.SSLSocketFactory
- # Javax.net.ssl exceptions
- javax.net.ssl.SSLException
- javax.net.ssl.SSLHandshakeException
- javax.net.ssl.SSLKeyException
- javax.net.ssl.SSLPeerUnverifiedException
- javax.net.ssl.SSLProtocolException
- import org.python.core.io.DatagramSocketIO
- import org.python.core.io.ServerSocketIO
- import org.python.core.io.SocketIO
- from org.python.core.Py import newString as asPyString
- class error(IOError): pass
- class herror(error): pass
- class gaierror(error): pass
- class timeout(error): pass
- class sslerror(error): pass
- def _add_exception_attrs(exc):
- setattr(exc, 'errno', exc[0])
- setattr(exc, 'strerror', exc[1])
- return exc
- def _unmapped_exception(exc):
- return _add_exception_attrs(error(-1, 'Unmapped exception: %s' % exc))
- def java_net_socketexception_handler(exc):
- if exc.message.startswith("Address family not supported by protocol family"):
- return _add_exception_attrs(error(errno.EAFNOSUPPORT,
- 'Address family not supported by protocol family: See http://wiki.python.org/jython/NewSocketModule#IPV6_address_support'))
- return _unmapped_exception(exc)
- def would_block_error(exc=None):
- return _add_exception_attrs(error(errno.EWOULDBLOCK, 'The socket operation could not complete without blocking'))
- ALL = None
- _ssl_message = ": Differences between the SSL socket behaviour of cpython vs. jython are explained on the wiki: http://wiki.python.org/jython/NewSocketModule#SSL_Support"
- _exception_map = {
- # (<javaexception>, <circumstance>) : callable that raises the python equivalent exception, or None to stub out as unmapped
- (java.io.IOException, ALL) : lambda x: error(errno.ECONNRESET, 'Software caused connection abort'),
- (java.io.InterruptedIOException, ALL) : lambda x: timeout(None, 'timed out'),
- (java.net.BindException, ALL) : lambda x: error(errno.EADDRINUSE, 'Address already in use'),
- (java.net.ConnectException, ALL) : lambda x: error(errno.ECONNREFUSED, 'Connection refused'),
- (java.net.NoRouteToHostException, ALL) : lambda x: error(errno.EHOSTUNREACH, 'No route to host'),
- (java.net.PortUnreachableException, ALL) : None,
- (java.net.ProtocolException, ALL) : None,
- (java.net.SocketException, ALL) : java_net_socketexception_handler,
- (java.net.SocketTimeoutException, ALL) : lambda x: timeout(None, 'timed out'),
- (java.net.UnknownHostException, ALL) : lambda x: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'),
- (java.nio.channels.AlreadyConnectedException, ALL) : lambda x: error(errno.EISCONN, 'Socket is already connected'),
- (java.nio.channels.AsynchronousCloseException, ALL) : None,
- (java.nio.channels.CancelledKeyException, ALL) : None,
- (java.nio.channels.ClosedByInterruptException, ALL) : None,
- (java.nio.channels.ClosedChannelException, ALL) : lambda x: error(errno.EPIPE, 'Socket closed'),
- (java.nio.channels.ClosedSelectorException, ALL) : None,
- (java.nio.channels.ConnectionPendingException, ALL) : None,
- (java.nio.channels.IllegalBlockingModeException, ALL) : None,
- (java.nio.channels.IllegalSelectorException, ALL) : None,
- (java.nio.channels.NoConnectionPendingException, ALL) : None,
- (java.nio.channels.NonReadableChannelException, ALL) : None,
- (java.nio.channels.NonWritableChannelException, ALL) : None,
- (java.nio.channels.NotYetBoundException, ALL) : None,
- (java.nio.channels.NotYetConnectedException, ALL) : None,
- (java.nio.channels.UnresolvedAddressException, ALL) : lambda x: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'),
- (java.nio.channels.UnsupportedAddressTypeException, ALL) : None,
- # These error codes are currently wrong: getting them correct is going to require
- # some investigation. Cpython 2.6 introduced extensive SSL support.
- (javax.net.ssl.SSLException, ALL) : lambda x: sslerror(-1, 'SSL exception'+_ssl_message),
- (javax.net.ssl.SSLHandshakeException, ALL) : lambda x: sslerror(-1, 'SSL handshake exception'+_ssl_message),
- (javax.net.ssl.SSLKeyException, ALL) : lambda x: sslerror(-1, 'SSL key exception'+_ssl_message),
- (javax.net.ssl.SSLPeerUnverifiedException, ALL) : lambda x: sslerror(-1, 'SSL peer unverified exception'+_ssl_message),
- (javax.net.ssl.SSLProtocolException, ALL) : lambda x: sslerror(-1, 'SSL protocol exception'+_ssl_message),
- }
- def _map_exception(java_exception, circumstance=ALL):
- mapped_exception = _exception_map.get((java_exception.__class__, circumstance))
- if mapped_exception:
- py_exception = mapped_exception(java_exception)
- else:
- py_exception = error(-1, 'Unmapped exception: %s' % java_exception)
- setattr(py_exception, 'java_exception', java_exception)
- return _add_exception_attrs(py_exception)
- _feature_support_map = {
- 'ipv6': True,
- 'idna': False,
- 'tipc': False,
- }
- def supports(feature, *args):
- if len(args) == 1:
- _feature_support_map[feature] = args[0]
- return _feature_support_map.get(feature, False)
- MODE_BLOCKING = 'block'
- MODE_NONBLOCKING = 'nonblock'
- MODE_TIMEOUT = 'timeout'
- _permitted_modes = (MODE_BLOCKING, MODE_NONBLOCKING, MODE_TIMEOUT)
- SHUT_RD = 0
- SHUT_WR = 1
- SHUT_RDWR = 2
- AF_UNSPEC = 0
- AF_INET = 2
- AF_INET6 = 23
- AI_PASSIVE = 1
- AI_CANONNAME = 2
- AI_NUMERICHOST = 4
- AI_V4MAPPED = 8
- AI_ALL = 16
- AI_ADDRCONFIG = 32
- AI_NUMERICSERV = 1024
- EAI_NONAME = -2
- EAI_SERVICE = -8
- EAI_ADDRFAMILY = -9
- NI_NUMERICHOST = 1
- NI_NUMERICSERV = 2
- NI_NOFQDN = 4
- NI_NAMEREQD = 8
- NI_DGRAM = 16
- NI_MAXSERV = 32
- NI_IDN = 64
- NI_IDN_ALLOW_UNASSIGNED = 128
- NI_IDN_USE_STD3_ASCII_RULES = 256
- NI_MAXHOST = 1025
- # For some reason, probably historical, SOCK_DGRAM and SOCK_STREAM are opposite values of what they are on cpython.
- # I.E. The following is the way they are on cpython
- # SOCK_STREAM = 1
- # SOCK_DGRAM = 2
- # At some point, we should probably switch them around, which *should* not affect anybody
- SOCK_DGRAM = 1
- SOCK_STREAM = 2
- SOCK_RAW = 3 # not supported
- SOCK_RDM = 4 # not supported
- SOCK_SEQPACKET = 5 # not supported
- SOL_SOCKET = 0xFFFF
- IPPROTO_AH = 51 # not supported
- IPPROTO_DSTOPTS = 60 # not supported
- IPPROTO_ESP = 50 # not supported
- IPPROTO_FRAGMENT = 44 # not supported
- IPPROTO_GGP = 3 # not supported
- IPPROTO_HOPOPTS = 0 # not supported
- IPPROTO_ICMP = 1 # not supported
- IPPROTO_ICMPV6 = 58 # not supported
- IPPROTO_IDP = 22 # not supported
- IPPROTO_IGMP = 2 # not supported
- IPPROTO_IP = 0
- IPPROTO_IPV4 = 4 # not supported
- IPPROTO_IPV6 = 41 # not supported
- IPPROTO_MAX = 256 # not supported
- IPPROTO_ND = 77 # not supported
- IPPROTO_NONE = 59 # not supported
- IPPROTO_PUP = 12 # not supported
- IPPROTO_RAW = 255 # not supported
- IPPROTO_ROUTING = 43 # not supported
- IPPROTO_TCP = 6
- IPPROTO_UDP = 17
- SO_ACCEPTCONN = 1
- SO_BROADCAST = 2
- SO_ERROR = 4
- SO_KEEPALIVE = 8
- SO_LINGER = 16
- SO_OOBINLINE = 32
- SO_RCVBUF = 64
- SO_REUSEADDR = 128
- SO_SNDBUF = 256
- SO_TIMEOUT = 512
- SO_TYPE = 1024
- TCP_NODELAY = 2048
- INADDR_ANY = "0.0.0.0"
- INADDR_BROADCAST = "255.255.255.255"
- IN6ADDR_ANY_INIT = "::"
- # Options with negative constants are not supported
- # They are being added here so that code that refers to them
- # will not break with an AttributeError
- SO_DEBUG = -1
- SO_DONTROUTE = -1
- SO_EXCLUSIVEADDRUSE = -8
- SO_RCVLOWAT = -16
- SO_RCVTIMEO = -32
- SO_REUSEPORT = -64
- SO_SNDLOWAT = -128
- SO_SNDTIMEO = -256
- SO_USELOOPBACK = -512
- __all__ = [
- # Families
- 'AF_UNSPEC', 'AF_INET', 'AF_INET6',
- # getaddrinfo and getnameinfo flags
- 'AI_PASSIVE', 'AI_CANONNAME', 'AI_NUMERICHOST', 'AI_V4MAPPED',
- 'AI_ALL', 'AI_ADDRCONFIG', 'AI_NUMERICSERV', 'EAI_NONAME',
- 'EAI_SERVICE', 'EAI_ADDRFAMILY',
- 'NI_NUMERICHOST', 'NI_NUMERICSERV', 'NI_NOFQDN', 'NI_NAMEREQD',
- 'NI_DGRAM', 'NI_MAXSERV', 'NI_IDN', 'NI_IDN_ALLOW_UNASSIGNED',
- 'NI_IDN_USE_STD3_ASCII_RULES', 'NI_MAXHOST',
- # socket types
- 'SOCK_DGRAM', 'SOCK_STREAM', 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET',
- # levels
- 'SOL_SOCKET',
- # protocols
- 'IPPROTO_AH', 'IPPROTO_DSTOPTS', 'IPPROTO_ESP', 'IPPROTO_FRAGMENT',
- 'IPPROTO_GGP', 'IPPROTO_HOPOPTS', 'IPPROTO_ICMP', 'IPPROTO_ICMPV6',
- 'IPPROTO_IDP', 'IPPROTO_IGMP', 'IPPROTO_IP', 'IPPROTO_IPV4',
- 'IPPROTO_IPV6', 'IPPROTO_MAX', 'IPPROTO_ND', 'IPPROTO_NONE',
- 'IPPROTO_PUP', 'IPPROTO_RAW', 'IPPROTO_ROUTING', 'IPPROTO_TCP',
- 'IPPROTO_UDP',
- # Special hostnames
- 'INADDR_ANY', 'INADDR_BROADCAST', 'IN6ADDR_ANY_INIT',
- # support socket options
- 'SO_BROADCAST', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE',
- 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY',
- # unsupported socket options
- 'SO_ACCEPTCONN', 'SO_DEBUG', 'SO_DONTROUTE', 'SO_ERROR',
- 'SO_EXCLUSIVEADDRUSE', 'SO_RCVLOWAT', 'SO_RCVTIMEO', 'SO_REUSEPORT',
- 'SO_SNDLOWAT', 'SO_SNDTIMEO', 'SO_TYPE', 'SO_USELOOPBACK',
- # functions
- 'getfqdn', 'gethostname', 'gethostbyname', 'gethostbyaddr',
- 'getservbyname', 'getservbyport', 'getprotobyname', 'getaddrinfo',
- 'getnameinfo', 'getdefaulttimeout', 'setdefaulttimeout', 'htons',
- 'htonl', 'ntohs', 'ntohl', 'inet_pton', 'inet_ntop', 'inet_aton',
- 'inet_ntoa', 'create_connection', 'socket', 'ssl',
- # exceptions
- 'error', 'herror', 'gaierror', 'timeout', 'sslerror,
- # classes
- 'SocketType',
- # Misc flags
- 'has_ipv6', 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR',
- ]
- def _constant_to_name(const_value, expected_name_starts):
- sock_module = sys.modules['socket']
- try:
- for name in dir(sock_module):
- if getattr(sock_module, name) is const_value:
- for name_start in expected_name_starts:
- if name.startswith(name_start):
- return name
- return "Unknown"
- finally:
- sock_module = None
- import _google_ipaddr_r234
- def _is_ip_address(addr, version=None):
- try:
- _google_ipaddr_r234.IPAddress(addr, version)
- return True
- except ValueError:
- return False
- def is_ipv4_address(addr):
- return _is_ip_address(addr, 4)
- def is_ipv6_address(addr):
- return _is_ip_address(addr, 6)
- def is_ip_address(addr):
- return _is_ip_address(addr)
- class _nio_impl:
- timeout = None
- mode = MODE_BLOCKING
- def config(self, mode, timeout):
- self.mode = mode
- if self.mode == MODE_BLOCKING:
- self.jchannel.configureBlocking(1)
- if self.mode == MODE_NONBLOCKING:
- self.jchannel.configureBlocking(0)
- if self.mode == MODE_TIMEOUT:
- self.jchannel.configureBlocking(1)
- self._timeout_millis = int(timeout*1000)
- self.jsocket.setSoTimeout(self._timeout_millis)
- def getsockopt(self, level, option):
- if (level, option) in self.options:
- result = getattr(self.jsocket, "get%s" % self.options[ (level, option) ])()
- if option == SO_LINGER:
- if result == -1:
- enabled, linger_time = 0, 0
- else:
- enabled, linger_time = 1, result
- return struct.pack('ii', enabled, linger_time)
- return result
- else:
- raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % \
- (_constant_to_name(option, ['SO_', 'TCP_']), _constant_to_name(level, ['SOL_', 'IPPROTO_']), str(self.jsocket)))
- def setsockopt(self, level, option, value):
- if (level, option) in self.options:
- if option == SO_LINGER:
- values = struct.unpack('ii', value)
- self.jsocket.setSoLinger(*values)
- else:
- getattr(self.jsocket, "set%s" % self.options[ (level, option) ])(value)
- else:
- raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % \
- (_constant_to_name(option, ['SO_', 'TCP_']), _constant_to_name(level, ['SOL_', 'IPPROTO_']), str(self.jsocket)))
- def close(self):
- self.jsocket.close()
- def getchannel(self):
- return self.jchannel
- def fileno(self):
- return self.socketio
- class _client_socket_impl(_nio_impl):
- options = {
- (SOL_SOCKET, SO_KEEPALIVE): 'KeepAlive',
- (SOL_SOCKET, SO_LINGER): 'SoLinger',
- (SOL_SOCKET, SO_OOBINLINE): 'OOBInline',
- (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
- (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
- (SOL_SOCKET, SO_SNDBUF): 'SendBufferSize',
- (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
- (IPPROTO_TCP, TCP_NODELAY): 'TcpNoDelay',
- }
- def __init__(self, socket=None, pending_options=None):
- if socket:
- self.jchannel = socket.getChannel()
- else:
- self.jchannel = java.nio.channels.SocketChannel.open()
- self.jsocket = self.jchannel.socket()
- self.socketio = org.python.core.io.SocketIO(self.jchannel, 'rw')
- if pending_options:
- for level, optname in pending_options.keys():
- self.setsockopt(level, optname, pending_options[ (level, optname) ])
- def bind(self, jsockaddr, reuse_addr):
- self.jsocket.setReuseAddress(reuse_addr)
- self.jsocket.bind(jsockaddr)
- def connect(self, jsockaddr):
- if self.mode == MODE_TIMEOUT:
- self.jsocket.connect (jsockaddr, self._timeout_millis)
- else:
- self.jchannel.connect(jsockaddr)
- def finish_connect(self):
- return self.jchannel.finishConnect()
- def _do_read_net(self, buf):
- # Need two separate implementations because the java.nio APIs do not support timeouts
- return self.jsocket.getInputStream().read(buf)
- def _do_read_nio(self, buf):
- bytebuf = java.nio.ByteBuffer.wrap(buf)
- count = self.jchannel.read(bytebuf)
- return count
- def _do_write_net(self, buf):
- self.jsocket.getOutputStream().write(buf)
- return len(buf)
- def _do_write_nio(self, buf):
- bytebuf = java.nio.ByteBuffer.wrap(buf)
- count = self.jchannel.write(bytebuf)
- return count
- def read(self, buf):
- if self.mode == MODE_TIMEOUT:
- return self._do_read_net(buf)
- else:
- return self._do_read_nio(buf)
- def write(self, buf):
- if self.mode == MODE_TIMEOUT:
- return self._do_write_net(buf)
- else:
- return self._do_write_nio(buf)
- def shutdown(self, how):
- if how in (SHUT_RD, SHUT_RDWR):
- self.jsocket.shutdownInput()
- if how in (SHUT_WR, SHUT_RDWR):
- self.jsocket.shutdownOutput()
- def getsockname(self):
- return (self.jsocket.getLocalAddress().getHostAddress(), self.jsocket.getLocalPort())
- def getpeername(self):
- return (self.jsocket.getInetAddress().getHostAddress(), self.jsocket.getPort() )
- class _server_socket_impl(_nio_impl):
- options = {
- (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
- (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
- (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
- }
- def __init__(self, jsockaddr, backlog, reuse_addr):
- self.pending_client_options = {}
- self.jchannel = java.nio.channels.ServerSocketChannel.open()
- self.jsocket = self.jchannel.socket()
- self.jsocket.setReuseAddress(reuse_addr)
- self.jsocket.bind(jsockaddr, backlog)
- self.socketio = org.python.core.io.ServerSocketIO(self.jchannel, 'rw')
- def accept(self):
- if self.mode in (MODE_BLOCKING, MODE_NONBLOCKING):
- new_cli_chan = self.jchannel.accept()
- if new_cli_chan is not None:
- return _client_socket_impl(new_cli_chan.socket(), self.pending_client_options)
- else:
- return None
- else:
- # In timeout mode now
- new_cli_sock = self.jsocket.accept()
- return _client_socket_impl(new_cli_sock, self.pending_client_options)
- def shutdown(self, how):
- # This is no-op on java, for server sockets.
- # What the user wants to achieve is achieved by calling close() on
- # java/jython. But we can't call that here because that would then
- # later cause the user explicit close() call to fail
- pass
- def getsockopt(self, level, option):
- if self.options.has_key( (level, option) ):
- return _nio_impl.getsockopt(self, level, option)
- elif _client_socket_impl.options.has_key( (level, option) ):
- return self.pending_client_options.get( (level, option), None)
- else:
- raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % \
- (_constant_to_name(option, ['SO_', 'TCP_']), _constant_to_name(level, ['SOL_', 'IPPROTO_']), str(self.jsocket)))
- def setsockopt(self, level, option, value):
- if self.options.has_key( (level, option) ):
- _nio_impl.setsockopt(self, level, option, value)
- elif _client_socket_impl.options.has_key( (level, option) ):
- self.pending_client_options[ (level, option) ] = value
- else:
- raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % \
- (_constant_to_name(option, ['SO_', 'TCP_']), _constant_to_name(level, ['SOL_', 'IPPROTO_']), str(self.jsocket)))
- def getsockname(self):
- return (self.jsocket.getInetAddress().getHostAddress(), self.jsocket.getLocalPort())
- def getpeername(self):
- # Not a meaningful operation for server sockets.
- raise error(errno.ENOTCONN, "Socket is not connected")
- class _datagram_socket_impl(_nio_impl):
- options = {
- (SOL_SOCKET, SO_BROADCAST): 'Broadcast',
- (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
- (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
- (SOL_SOCKET, SO_SNDBUF): 'SendBufferSize',
- (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
- }
- def __init__(self, jsockaddr=None, reuse_addr=0):
- self.jchannel = java.nio.channels.DatagramChannel.open()
- self.jsocket = self.jchannel.socket()
- if jsockaddr is not None:
- self.jsocket.setReuseAddress(reuse_addr)
- self.jsocket.bind(jsockaddr)
- self.socketio = org.python.core.io.DatagramSocketIO(self.jchannel, 'rw')
- def connect(self, jsockaddr):
- self.jchannel.connect(jsockaddr)
- def disconnect(self):
- """
- Disconnect the datagram socket.
- cpython appears not to have this operation
- """
- self.jchannel.disconnect()
- def shutdown(self, how):
- # This is no-op on java, for datagram sockets.
- # What the user wants to achieve is achieved by calling close() on
- # java/jython. But we can't call that here because that would then
- # later cause the user explicit close() call to fail
- pass
- def _do_send_net(self, byte_array, socket_address, flags):
- # Need two separate implementations because the java.nio APIs do not support timeouts
- num_bytes = len(byte_array)
- if self.jsocket.isConnected() and socket_address is None:
- packet = java.net.DatagramPacket(byte_array, num_bytes)
- else:
- packet = java.net.DatagramPacket(byte_array, num_bytes, socket_address)
- self.jsocket.send(packet)
- return num_bytes
- def _do_send_nio(self, byte_array, socket_address, flags):
- byte_buf = java.nio.ByteBuffer.wrap(byte_array)
- if self.jchannel.isConnected() and socket_address is None:
- bytes_sent = self.jchannel.write(byte_buf)
- else:
- bytes_sent = self.jchannel.send(byte_buf, socket_address)
- return bytes_sent
- def sendto(self, byte_array, jsockaddr, flags):
- if self.mode == MODE_TIMEOUT:
- return self._do_send_net(byte_array, jsockaddr, flags)
- else:
- return self._do_send_nio(byte_array, jsockaddr, flags)
- def send(self, byte_array, flags):
- if self.mode == MODE_TIMEOUT:
- return self._do_send_net(byte_array, None, flags)
- else:
- return self._do_send_nio(byte_array, None, flags)
- def _do_receive_net(self, return_source_address, num_bytes, flags):
- byte_array = jarray.zeros(num_bytes, 'b')
- packet = java.net.DatagramPacket(byte_array, num_bytes)
- self.jsocket.receive(packet)
- bytes_rcvd = packet.getLength()
- if bytes_rcvd < num_bytes:
- byte_array = byte_array[:bytes_rcvd]
- return_data = byte_array.tostring()
- if return_source_address:
- host = None
- if packet.getAddress():
- host = packet.getAddress().getHostAddress()
- port = packet.getPort()
- return return_data, (host, port)
- else:
- return return_data
- def _do_receive_nio(self, return_source_address, num_bytes, flags):
- byte_array = jarray.zeros(num_bytes, 'b')
- byte_buf = java.nio.ByteBuffer.wrap(byte_array)
- source_address = self.jchannel.receive(byte_buf)
- if source_address is None and not self.jchannel.isBlocking():
- raise would_block_error()
- byte_buf.flip() ; bytes_read = byte_buf.remaining()
- if bytes_read < num_bytes:
- byte_array = byte_array[:bytes_read]
- return_data = byte_array.tostring()
- if return_source_address:
- return return_data, (source_address.getAddress().getHostAddress(), source_address.getPort())
- else:
- return return_data
- def recvfrom(self, num_bytes, flags):
- if self.mode == MODE_TIMEOUT:
- return self._do_receive_net(1, num_bytes, flags)
- else:
- return self._do_receive_nio(1, num_bytes, flags)
- def recv(self, num_bytes, flags):
- if self.mode == MODE_TIMEOUT:
- return self._do_receive_net(0, num_bytes, flags)
- else:
- return self._do_receive_nio(0, num_bytes, flags)
- def getsockname(self):
- return (self.jsocket.getLocalAddress().getHostAddress(), self.jsocket.getLocalPort())
- def getpeername(self):
- peer_address = self.jsocket.getInetAddress()
- if peer_address is None:
- raise error(errno.ENOTCONN, "Socket is not connected")
- return (peer_address.getHostAddress(), self.jsocket.getPort() )
- has_ipv6 = True # IPV6 FTW!
- # Name and address functions
- def _gethostbyaddr(name):
- # This is as close as I can get; at least the types are correct...
- addresses = java.net.InetAddress.getAllByName(gethostbyname(name))
- names = []
- addrs = []
- for addr in addresses:
- names.append(asPyString(addr.getHostName()))
- addrs.append(asPyString(addr.getHostAddress()))
- return (names, addrs)
- def getfqdn(name=None):
- """
- Return a fully qualified domain name for name. If name is omitted or empty
- it is interpreted as the local host. To find the fully qualified name,
- the hostname returned by gethostbyaddr() is checked, then aliases for the
- host, if available. The first name which includes a period is selected.
- In case no fully qualified domain name is available, the hostname is retur
- New in version 2.0.
- """
- if not name:
- name = gethostname()
- names, addrs = _gethostbyaddr(name)
- for a in names:
- if a.find(".") >= 0:
- return a
- return name
- def gethostname():
- try:
- return asPyString(java.net.InetAddress.getLocalHost().getHostName())
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def gethostbyname(name):
- try:
- return asPyString(java.net.InetAddress.getByName(name).getHostAddress())
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def gethostbyaddr(name):
- names, addrs = _gethostbyaddr(name)
- return (names[0], names, addrs)
- def getservbyname(service_name, protocol_name=None):
- try:
- from jnr.netdb import Service
- except ImportError:
- return None
- service = Service.getServiceByName(service_name, protocol_name)
- if service is None:
- raise error('service/proto not found')
- return service.getPort()
- def getservbyport(port, protocol_name=None):
- try:
- from jnr.netdb import Service
- except ImportError:
- return None
- service = Service.getServiceByPort(port, protocol_name)
- if service is None:
- raise error('port/proto not found')
- return service.getName()
- def getprotobyname(protocol_name=None):
- try:
- from jnr.netdb import Protocol
- except ImportError:
- return None
- proto = Protocol.getProtocolByName(protocol_name)
- if proto is None:
- raise error('protocol not found')
- return proto.getProto()
- def _realsocket(family = AF_INET, sock_type = SOCK_STREAM, protocol=0):
- assert family in (AF_INET, AF_INET6), "Only AF_INET and AF_INET6 sockets are currently supported on jython"
- assert sock_type in (SOCK_DGRAM, SOCK_STREAM), "Only SOCK_STREAM and SOCK_DGRAM sockets are currently supported on jython"
- if sock_type == SOCK_STREAM:
- if protocol != 0:
- assert protocol == IPPROTO_TCP, "Only IPPROTO_TCP supported on SOCK_STREAM sockets"
- else:
- protocol = IPPROTO_TCP
- result = _tcpsocket()
- else:
- if protocol != 0:
- assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets"
- else:
- protocol = IPPROTO_UDP
- result = _udpsocket()
- setattr(result, "family", family)
- setattr(result, "type", sock_type)
- setattr(result, "proto", protocol)
- return result
- #
- # Attempt to provide IDNA (RFC 3490) support.
- #
- # Try java.net.IDN, built into java 6
- #
- idna_libraries = [
- ('java.net.IDN', 'toASCII', 'toUnicode',
- 'ALLOW_UNASSIGNED', 'USE_STD3_ASCII_RULES',
- java.lang.IllegalArgumentException)
- ]
-
- for idna_lib, efn, dfn, au, usar, exc in idna_libraries:
- try:
- m = __import__(idna_lib, globals(), locals(), [efn, dfn, au, usar])
- encode_fn = getattr(m, efn)
- def _encode_idna(name):
- try:
- return encode_fn(name)
- except exc:
- raise UnicodeEncodeError(name)
- decode_fn = getattr(m, dfn)
- def _decode_idna(name, flags=0):
- try:
- jflags = 0
- if flags & NI_IDN_ALLOW_UNASSIGNED:
- jflags |= au
- if flags & NI_IDN_USE_STD3_ASCII_RULES:
- jflags |= usar
- return decode_fn(name, jflags)
- except Exception, x:
- raise UnicodeDecodeError(name)
- supports('idna', True)
- break
- except (AttributeError, ImportError), e:
- pass
- else:
- _encode_idna = lambda x: x.encode("ascii")
- _decode_idna = lambda x, y=0: x.decode("ascii")
- #
- # Define data structures to support IPV4 and IPV6.
- #
- class _ip_address_t: pass
- class _ipv4_address_t(_ip_address_t):
- def __init__(self, sockaddr, port, jaddress):
- self.sockaddr = sockaddr
- self.port = port
- self.jaddress = jaddress
- def __getitem__(self, index):
- if 0 == index:
- return self.sockaddr
- elif 1 == index:
- return self.port
- else:
- raise IndexError()
- def __len__(self):
- return 2
- def __str__(self):
- return "('%s', %d)" % (self.sockaddr, self.port)
- __repr__ = __str__
- class _ipv6_address_t(_ip_address_t):
- def __init__(self, sockaddr, port, jaddress):
- self.sockaddr = sockaddr
- self.port = port
- self.jaddress = jaddress
- def __getitem__(self, index):
- if 0 == index:
- return self.sockaddr
- elif 1 == index:
- return self.port
- elif 2 == index:
- return 0
- elif 3 == index:
- return self.jaddress.scopeId
- else:
- raise IndexError()
- def __len__(self):
- return 4
- def __str__(self):
- return "('%s', %d, 0, %d)" % (self.sockaddr, self.port, self.jaddress.scopeId)
- __repr__ = __str__
- def _get_jsockaddr(address_object, family, sock_type, proto, flags):
- # Is this an object that was returned from getaddrinfo? If so, it already contains an InetAddress
- if isinstance(address_object, _ip_address_t):
- return java.net.InetSocketAddress(address_object.jaddress, address_object[1])
- # The user passed an address tuple, not an object returned from getaddrinfo
- # So we must call getaddrinfo, after some translations and checking
- if address_object is None:
- address_object = ("", 0)
- error_message = "Address must be a 2-tuple (ipv4: (host, port)) or a 4-tuple (ipv6: (host, port, flow, scope))"
- if not isinstance(address_object, tuple) or \
- ((family == AF_INET and len(address_object) != 2) or (family == AF_INET6 and len(address_object) not in [2,4] )) or \
- not isinstance(address_object[0], (basestring, types.NoneType)) or \
- not isinstance(address_object[1], (int, long)):
- raise TypeError(error_message)
- if len(address_object) == 4 and not isinstance(address_object[3], (int, long)):
- raise TypeError(error_message)
- hostname = address_object[0]
- if hostname is not None:
- hostname = hostname.strip()
- port = address_object[1]
- if family == AF_INET and sock_type == SOCK_DGRAM and hostname == "<broadcast>":
- hostname = INADDR_BROADCAST
- if hostname in ["", None]:
- if flags & AI_PASSIVE:
- hostname = {AF_INET: INADDR_ANY, AF_INET6: IN6ADDR_ANY_INIT}[family]
- else:
- hostname = "localhost"
- if isinstance(hostname, unicode):
- hostname = _encode_idna(hostname)
- addresses = getaddrinfo(hostname, port, family, sock_type, proto, flags)
- if len(addresses) == 0:
- raise gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed')
- return java.net.InetSocketAddress(addresses[0][4].jaddress, port)
- # Workaround for this (predominantly windows) issue
- # http://wiki.python.org/jython/NewSocketModule#IPV6_address_support
- _ipv4_addresses_only = False
- def _use_ipv4_addresses_only(value):
- global _ipv4_addresses_only
- _ipv4_addresses_only = value
- def _getaddrinfo_get_host(host, family, flags):
- if not isinstance(host, basestring) and host is not None:
- raise TypeError("getaddrinfo() argument 1 must be string or None")
- if flags & AI_NUMERICHOST:
- if not is_ip_address(host):
- raise gaierror(EAI_NONAME, "Name or service not known")
- if family == AF_INET and not is_ipv4_address(host):
- raise gaierror(EAI_ADDRFAMILY, "Address family for hostname not supported")
- if family == AF_INET6 and not is_ipv6_address(host):
- raise gaierror(EAI_ADDRFAMILY, "Address family for hostname not supported")
- if isinstance(host, unicode):
- host = _encode_idna(host)
- return host
- def _getaddrinfo_get_port(port, flags):
- if isinstance(port, basestring):
- try:
- int_port = int(port)
- except ValueError:
- if flags & AI_NUMERICSERV:
- raise gaierror(EAI_NONAME, "Name or service not known")
- # Lookup the service by name
- try:
- int_port = getservbyname(port)
- except error:
- raise gaierror(EAI_SERVICE, "Servname not supported for ai_socktype")
- elif port is None:
- int_port = 0
- elif not isinstance(port, (int, long)):
- raise error("Int or String expected")
- else:
- int_port = int(port)
- return int_port % 65536
- def getaddrinfo(host, port, family=AF_UNSPEC, socktype=0, proto=0, flags=0):
- try:
- if _ipv4_addresses_only:
- family = AF_INET
- if not family in [AF_INET, AF_INET6, AF_UNSPEC]:
- raise gaierror(errno.EIO, 'ai_family not supported')
- host = _getaddrinfo_get_host(host, family, flags)
- port = _getaddrinfo_get_port(port, flags)
- if socktype not in [0, SOCK_DGRAM, SOCK_STREAM]:
- raise error(errno.ESOCKTNOSUPPORT, "Socket type %s is not supported" % _constant_to_name(socktype, ['SOCK_']))
- filter_fns = []
- filter_fns.append({
- AF_INET: lambda x: isinstance(x, java.net.Inet4Address),
- AF_INET6: lambda x: isinstance(x, java.net.Inet6Address),
- AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress),
- }[family])
- if host in [None, ""]:
- if flags & AI_PASSIVE:
- hosts = {AF_INET: [INADDR_ANY], AF_INET6: [IN6ADDR_ANY_INIT], AF_UNSPEC: [INADDR_ANY, IN6ADDR_ANY_INIT]}[family]
- else:
- hosts = ["localhost"]
- else:
- hosts = [host]
- results = []
- for h in hosts:
- for a in java.net.InetAddress.getAllByName(h):
- if len([f for f in filter_fns if f(a)]):
- family = {java.net.Inet4Address: AF_INET, java.net.Inet6Address: AF_INET6}[a.getClass()]
- if flags & AI_CANONNAME:
- canonname = asPyString(a.getCanonicalHostName())
- else:
- canonname = ""
- sockaddr = asPyString(a.getHostAddress())
- # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses
- sock_tuple = {AF_INET : _ipv4_address_t, AF_INET6 : _ipv6_address_t}[family](sockaddr, port, a)
- if socktype == 0:
- socktypes = [SOCK_DGRAM, SOCK_STREAM]
- else:
- socktypes = [socktype]
- for result_socktype in socktypes:
- result_proto = {SOCK_DGRAM: IPPROTO_UDP, SOCK_STREAM: IPPROTO_TCP}[result_socktype]
- if proto in [0, result_proto]:
- # The returned socket will only support the result_proto
- # If this does not match the requested proto, don't return it
- results.append((family, result_socktype, result_proto, canonname, sock_tuple))
- return results
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def _getnameinfo_get_host(address, flags):
- if not isinstance(address, basestring):
- raise TypeError("getnameinfo() address 1 must be string, not None")
- if isinstance(address, unicode):
- address = _encode_idna(address)
- jia = java.net.InetAddress.getByName(address)
- result = jia.getCanonicalHostName()
- if flags & NI_NAMEREQD:
- if is_ip_address(result):
- raise gaierror(EAI_NONAME, "Name or service not known")
- elif flags & NI_NUMERICHOST:
- result = jia.getHostAddress()
- # Ignoring NI_NOFQDN for now
- if flags & NI_IDN:
- result = _decode_idna(result, flags)
- return result
- def _getnameinfo_get_port(port, flags):
- if not isinstance(port, (int, long)):
- raise TypeError("getnameinfo() port number must be an integer")
- if flags & NI_NUMERICSERV:
- return port
- proto = None
- if flags & NI_DGRAM:
- proto = "udp"
- return getservbyport(port, proto)
- def getnameinfo(sock_addr, flags):
- if not isinstance(sock_addr, tuple) or len(sock_addr) < 2:
- raise TypeError("getnameinfo() argument 1 must be a tuple")
- host = _getnameinfo_get_host(sock_addr[0], flags)
- port = _getnameinfo_get_port(sock_addr[1], flags)
- return (host, port)
- def getdefaulttimeout():
- return _defaulttimeout
- def _calctimeoutvalue(value):
- if value is None:
- return None
- try:
- floatvalue = float(value)
- except:
- raise TypeError('Socket timeout value must be a number or None')
- if floatvalue < 0.0:
- raise ValueError("Socket timeout value cannot be negative")
- if floatvalue < 0.000001:
- return 0.0
- return floatvalue
- def setdefaulttimeout(timeout):
- global _defaulttimeout
- try:
- _defaulttimeout = _calctimeoutvalue(timeout)
- finally:
- _nonblocking_api_mixin.timeout = _defaulttimeout
- def htons(x): return x
- def htonl(x): return x
- def ntohs(x): return x
- def ntohl(x): return x
- def inet_pton(family, ip_string):
- try:
- if family == AF_INET:
- if not is_ipv4_address(ip_string):
- raise error("illegal IP address string passed to inet_pton")
- elif family == AF_INET6:
- if not is_ipv6_address(ip_string):
- raise error("illegal IP address string passed to inet_pton")
- else:
- raise error(errno.EAFNOSUPPORT, "Address family not supported by protocol")
- ia = java.net.InetAddress.getByName(ip_string)
- bytes = []
- for byte in ia.getAddress():
- if byte < 0:
- bytes.append(byte+256)
- else:
- bytes.append(byte)
- return "".join([chr(byte) for byte in bytes])
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def inet_ntop(family, packed_ip):
- try:
- jByteArray = jarray.array(packed_ip, 'b')
- if family == AF_INET:
- if len(jByteArray) != 4:
- raise ValueError("invalid length of packed IP address string")
- elif family == AF_INET6:
- if len(jByteArray) != 16:
- raise ValueError("invalid length of packed IP address string")
- else:
- raise ValueError("unknown address family %s" % family)
- ia = java.net.InetAddress.getByAddress(jByteArray)
- return ia.getHostAddress()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def inet_aton(ip_string):
- return inet_pton(AF_INET, ip_string)
- def inet_ntoa(packed_ip):
- return inet_ntop(AF_INET, packed_ip)
- from functools import wraps
- def raises_error(method):
- @wraps(method)
- def set_last_error(obj, *args, **kwargs):
- try:
- setattr(obj, '_last_error', 0)
- return method(obj, *args, **kwargs)
- except error, e:
- setattr(obj, '_last_error', e[0])
- raise
- return set_last_error
- class _nonblocking_api_mixin:
- mode = MODE_BLOCKING
- reference_count = 0
- close_lock = threading.Lock()
- def __init__(self):
- self.timeout = _defaulttimeout
- if self.timeout is not None:
- self.mode = MODE_TIMEOUT
- self.pending_options = {
- (SOL_SOCKET, SO_REUSEADDR): 0,
- }
- def gettimeout(self):
- return self.timeout
- def settimeout(self, timeout):
- self.timeout = _calctimeoutvalue(timeout)
- if self.timeout is None:
- self.mode = MODE_BLOCKING
- elif self.timeout < 0.000001:
- self.mode = MODE_NONBLOCKING
- else:
- self.mode = MODE_TIMEOUT
- self._config()
- def setblocking(self, flag):
- if flag:
- self.mode = MODE_BLOCKING
- self.timeout = None
- else:
- self.mode = MODE_NONBLOCKING
- self.timeout = 0.0
- self._config()
- def getblocking(self):
- return self.mode == MODE_BLOCKING
- @raises_error
- def setsockopt(self, level, optname, value):
- try:
- if self.sock_impl:
- self.sock_impl.setsockopt(level, optname, value)
- else:
- self.pending_options[ (level, optname) ] = value
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def getsockopt(self, level, optname):
- # Handle "pseudo" options first
- if level == SOL_SOCKET and optname == SO_TYPE:
- return getattr(self, "type")
- if level == SOL_SOCKET and optname == SO_ERROR:
- return_value = self._last_error
- self._last_error = 0
- return return_value
- # Now handle "real" options
- try:
- if self.sock_impl:
- return self.sock_impl.getsockopt(level, optname)
- else:
- return self.pending_options.get( (level, optname), None)
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def shutdown(self, how):
- assert how in (SHUT_RD, SHUT_WR, SHUT_RDWR)
- if not self.sock_impl:
- raise error(errno.ENOTCONN, "Transport endpoint is not connected")
- try:
- self.sock_impl.shutdown(how)
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def close(self):
- try:
- if self.sock_impl:
- self.sock_impl.close()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def getsockname(self):
- try:
- if self.sock_impl is None:
- # If the user has already bound an address, return that
- if self.local_addr:
- return self.local_addr
- # The user has not bound, connected or listened
- # This is what cpython raises in this scenario
- raise error(errno.EINVAL, "Invalid argument")
- return self.sock_impl.getsockname()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def getpeername(self):
- try:
- if self.sock_impl is None:
- raise error(errno.ENOTCONN, "Socket is not connected")
- return self.sock_impl.getpeername()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def _config(self):
- assert self.mode in _permitted_modes
- if self.sock_impl:
- self.sock_impl.config(self.mode, self.timeout)
- for level, optname in self.pending_options.keys():
- if optname != SO_REUSEADDR:
- self.sock_impl.setsockopt(level, optname, self.pending_options[ (level, optname) ])
- def getchannel(self):
- if not self.sock_impl:
- return None
- return self.sock_impl.getchannel()
- def fileno(self):
- if not self.sock_impl:
- return None
- return self.sock_impl.fileno()
- def _get_jsocket(self):
- return self.sock_impl.jsocket
- class _tcpsocket(_nonblocking_api_mixin):
- sock_impl = None
- istream = None
- ostream = None
- local_addr = None
- server = 0
- _last_error = 0
- def __init__(self):
- _nonblocking_api_mixin.__init__(self)
- def getsockopt(self, level, optname):
- if level == SOL_SOCKET and optname == SO_ACCEPTCONN:
- return self.server
- return _nonblocking_api_mixin.getsockopt(self, level, optname)
- @raises_error
- def bind(self, addr):
- assert not self.sock_impl
- assert not self.local_addr
- # Do the address format check
- _get_jsockaddr(addr, self.family, self.type, self.proto, AI_PASSIVE)
- self.local_addr = addr
- @raises_error
- def listen(self, backlog):
- "This signifies a server socket"
- try:
- assert not self.sock_impl
- self.server = 1
- self.sock_impl = _server_socket_impl(_get_jsockaddr(self.local_addr, self.family, self.type, self.proto, AI_PASSIVE),
- backlog, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
- self._config()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def accept(self):
- "This signifies a server socket"
- try:
- if not self.sock_impl:
- self.listen()
- assert self.server
- new_sock = self.sock_impl.accept()
- if not new_sock:
- raise would_block_error()
- cliconn = _tcpsocket()
- cliconn.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ] = new_sock.jsocket.getReuseAddress()
- cliconn.sock_impl = new_sock
- cliconn._setup()
- return cliconn, new_sock.getpeername()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def _do_connect(self, addr):
- try:
- assert not self.sock_impl
- self.sock_impl = _client_socket_impl()
- if self.local_addr: # Has the socket been bound to a local address?
- self.sock_impl.bind(_get_jsockaddr(self.local_addr, self.family, self.type, self.proto, 0),
- self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
- self._config() # Configure timeouts, etc, now that the socket exists
- self.sock_impl.connect(_get_jsockaddr(addr, self.family, self.type, self.proto, 0))
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def connect(self, addr):
- "This signifies a client socket"
- self._do_connect(addr)
- self._setup()
- def connect_ex(self, addr):
- "This signifies a client socket"
- if not self.sock_impl:
- self._do_connect(addr)
- if self.sock_impl.finish_connect():
- self._setup()
- if self.mode == MODE_NONBLOCKING:
- return errno.EISCONN
- return 0
- return errno.EINPROGRESS
- def _setup(self):
- if self.mode != MODE_NONBLOCKING:
- self.istream = self.sock_impl.jsocket.getInputStream()
- self.ostream = self.sock_impl.jsocket.getOutputStream()
- @raises_error
- def recv(self, n):
- try:
- if not self.sock_impl: raise error(errno.ENOTCONN, 'Socket is not connected')
- if self.sock_impl.jchannel.isConnectionPending():
- self.sock_impl.jchannel.finishConnect()
- data = jarray.zeros(n, 'b')
- m = self.sock_impl.read(data)
- if m == -1:#indicates EOF has been reached, so we just return the empty string
- return ""
- elif m <= 0:
- if self.mode == MODE_NONBLOCKING:
- raise would_block_error()
- return ""
- if m < n:
- data = data[:m]
- return data.tostring()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def recvfrom(self, n):
- return self.recv(n), None
- @raises_error
- def send(self, s):
- try:
- if not self.sock_impl: raise error(errno.ENOTCONN, 'Socket is not connected')
- if self.sock_impl.jchannel.isConnectionPending():
- self.sock_impl.jchannel.finishConnect()
- numwritten = self.sock_impl.write(s)
- if numwritten == 0 and self.mode == MODE_NONBLOCKING:
- raise would_block_error()
- return numwritten
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- sendall = send
- @raises_error
- def close(self):
- try:
- if self.istream:
- self.istream.close()
- if self.ostream:
- self.ostream.close()
- if self.sock_impl:
- self.sock_impl.close()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- class _udpsocket(_nonblocking_api_mixin):
- sock_impl = None
- connected = False
- local_addr = None
- _last_error = 0
- def __init__(self):
- _nonblocking_api_mixin.__init__(self)
- @raises_error
- def bind(self, addr):
- try:
- assert not self.sock_impl
- assert not self.local_addr
- # Do the address format check
- _get_jsockaddr(addr, self.family, self.type, self.proto, AI_PASSIVE)
- self.local_addr = addr
- self.sock_impl = _datagram_socket_impl(_get_jsockaddr(self.local_addr, self.family, self.type, self.proto, AI_PASSIVE),
- self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
- self._config()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def _do_connect(self, addr):
- try:
- assert not self.connected, "Datagram Socket is already connected"
- if not self.sock_impl:
- self.sock_impl = _datagram_socket_impl()
- self._config()
- self.sock_impl.connect(_get_jsockaddr(addr, self.family, self.type, self.proto, 0))
- self.connected = True
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def connect(self, addr):
- self._do_connect(addr)
- def connect_ex(self, addr):
- if not self.sock_impl:
- self._do_connect(addr)
- return 0
- @raises_error
- def sendto(self, data, p1, p2=None):
- try:
- if not p2:
- flags, addr = 0, p1
- else:
- flags, addr = 0, p2
- if not self.sock_impl:
- self.sock_impl = _datagram_socket_impl()
- self._config()
- byte_array = java.lang.String(data).getBytes('iso-8859-1')
- result = self.sock_impl.sendto(byte_array, _get_jsockaddr(addr, self.family, self.type, self.proto, 0), flags)
- return result
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def send(self, data, flags=None):
- if not self.connected: raise error(errno.ENOTCONN, "Socket is not connected")
- byte_array = java.lang.String(data).getBytes('iso-8859-1')
- return self.sock_impl.send(byte_array, flags)
- @raises_error
- def recvfrom(self, num_bytes, flags=None):
- """
- There is some disagreement as to what the behaviour should be if
- a recvfrom operation is requested on an unbound socket.
- See the following links for more information
- http://bugs.jython.org/issue1005
- http://bugs.sun.com/view_bug.do?bug_id=6621689
- """
- try:
- # This is the old 2.1 behaviour
- #assert self.sock_impl
- # This is amak's preferred interpretation
- #raise error(errno.ENOTCONN, "Recvfrom on unbound udp socket meaningless operation")
- # And this is the option for cpython compatibility
- if not self.sock_impl:
- self.sock_impl = _datagram_socket_impl()
- self._config()
- return self.sock_impl.recvfrom(num_bytes, flags)
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- @raises_error
- def recv(self, num_bytes, flags=None):
- if not self.sock_impl: raise error(errno.ENOTCONN, "Socket is not connected")
- try:
- return self.sock_impl.recv(num_bytes, flags)
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def __del__(self):
- self.close()
- _socketmethods = (
- 'bind', 'connect', 'connect_ex', 'fileno', 'listen',
- 'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
- 'sendall', 'setblocking',
- 'settimeout', 'gettimeout', 'shutdown', 'getchannel')
- # All the method names that must be delegated to either the real socket
- # object or the _closedsocket object.
- _delegate_methods = ("recv", "recvfrom", "recv_into", "recvfrom_into",
- "send", "sendto")
- class _closedsocket(object):
- __slots__ = []
- def _dummy(*args):
- raise error(errno.EBADF, 'Bad file descriptor')
- # All _delegate_methods must also be initialized here.
- send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy
- __getattr__ = _dummy
- _active_sockets = set()
- def _closeActiveSockets():
- for socket in _active_sockets.copy():
- try:
- socket.close()
- except error:
- msg = 'Problem closing socket: %s: %r' % (socket, sys.exc_info())
- print >> sys.stderr, msg
- class _socketobject(object):
- __doc__ = _realsocket.__doc__
- __slots__ = ["_sock", "__weakref__"] + list(_delegate_methods)
- def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
- if _sock is None:
- _sock = _realsocket(family, type, proto)
- _sock.reference_count += 1
- elif isinstance(_sock, _nonblocking_api_mixin):
- _sock.reference_count += 1
- self._sock = _sock
- for method in _delegate_methods:
- meth = getattr(_sock, method, None)
- if meth:
- setattr(self, method, meth)
- _active_sockets.add(self)
- def close(self):
- try:
- _active_sockets.remove(self)
- except KeyError:
- pass
- _sock = self._sock
- if isinstance(_sock, _nonblocking_api_mixin):
- _sock.close_lock.acquire()
- try:
- _sock.reference_count -=1
- if not _sock.reference_count:
- _sock.close()
- self._sock = _closedsocket()
- dummy = self._sock._dummy
- for method in _delegate_methods:
- setattr(self, method, dummy)
- self.send = self.recv = self.sendto = self.recvfrom = \
- self._sock._dummy
- finally:
- _sock.close_lock.release()
- #close.__doc__ = _realsocket.close.__doc__
- def accept(self):
- sock, addr = self._sock.accept()
- return _socketobject(_sock=sock), addr
- #accept.__doc__ = _realsocket.accept.__doc__
- def dup(self):
- """dup() -> socket object
- Return a new socket object connected to the same system resource."""
- _sock = self._sock
- if not isinstance(_sock, _nonblocking_api_mixin):
- return _socketobject(_sock=_sock)
- _sock.close_lock.acquire()
- try:
- duped = _socketobject(_sock=_sock)
- finally:
- _sock.close_lock.release()
- return duped
- def makefile(self, mode='r', bufsize=-1):
- """makefile([mode[, bufsize]]) -> file object
- Return a regular file object corresponding to the socket. The mode
- and bufsize arguments are as for the built-in open() function."""
- _sock = self._sock
- if not isinstance(_sock, _nonblocking_api_mixin):
- return _fileobject(_sock, mode, bufsize)
- _sock.close_lock.acquire()
- try:
- fileobject = _fileobject(_sock, mode, bufsize)
- finally:
- _sock.close_lock.release()
- return fileobject
- family = property(lambda self: self._sock.family, doc="the socket family")
- type = property(lambda self: self._sock.type, doc="the socket type")
- proto = property(lambda self: self._sock.proto, doc="the socket protocol")
- _s = ("def %s(self, *args): return self._sock.%s(*args)\n\n"
- #"%s.__doc__ = _realsocket.%s.__doc__\n")
- )
- for _m in _socketmethods:
- #exec _s % (_m, _m, _m, _m)
- exec _s % (_m, _m)
- del _m, _s
- socket = SocketType = _socketobject
- class _fileobject(object):
- """Faux file object attached to a socket object."""
- default_bufsize = 8192
- name = "<socket>"
- __slots__ = ["mode", "bufsize", "softspace",
- # "closed" is a property, see below
- "_sock", "_rbufsize", "_wbufsize", "_rbuf", "_wbuf",
- "_close"]
- def __init__(self, sock, mode='rb', bufsize=-1, close=False):
- self._sock = sock
- if isinstance(sock, _nonblocking_api_mixin):
- sock.reference_count += 1
- self.mode = mode # Not actually used in this version
- if bufsize < 0:
- bufsize = self.default_bufsize
- self.bufsize = bufsize
- self.softspace = False
- if bufsize == 0:
- self._rbufsize = 1
- elif bufsize == 1:
- self._rbufsize = self.default_bufsize
- else:
- self._rbufsize = bufsize
- self._wbufsize = bufsize
- self._rbuf = "" # A string
- self._wbuf = [] # A list of strings
- self._close = close
- def _getclosed(self):
- return self._sock is None
- closed = property(_getclosed, doc="True if the file is closed")
- def close(self):
- try:
- if self._sock:
- self.flush()
- finally:
- if self._sock:
- if isinstance(self._sock, _nonblocking_api_mixin):
- self._sock.reference_count -= 1
- if not self._sock.reference_count or self._close:
- self._sock.close()
- elif self._close:
- self._sock.close()
- self._sock = None
- def __del__(self):
- try:
- self.close()
- except:
- # close() may fail if __init__ didn't complete
- pass
- def flush(self):
- if self._wbuf:
- buffer = "".join(self._wbuf)
- self._wbuf = []
- self._sock.sendall(buffer)
- def fileno(self):
- return self._sock.fileno()
- def write(self, data):
- data = str(data) # XXX Should really reject non-string non-buffers
- if not data:
- return
- self._wbuf.append(data)
- if (self._wbufsize == 0 or
- self._wbufsize == 1 and '\n' in data or
- self._get_wbuf_len() >= self._wbufsize):
- self.flush()
- def writelines(self, list):
- # XXX We could do better here for very long lists
- # XXX Should really reject non-string non-buffers
- self._wbuf.extend(filter(None, map(str, list)))
- if (self._wbufsize <= 1 or
- self._get_wbuf_len() >= self._wbufsize):
- self.flush()
- def _get_wbuf_len(self):
- buf_len = 0
- for x in self._wbuf:
- buf_len += len(x)
- return buf_len
- def read(self, size=-1):
- data = self._rbuf
- if size < 0:
- # Read until EOF
- buffers = []
- if data:
- buffers.append(data)
- self._rbuf = ""
- if self._rbufsize <= 1:
- recv_size = self.default_bufsize
- else:
- recv_size = self._rbufsize
- while True:
- data = self._sock.recv(recv_size)
- if not data:
- break
- buffers.append(data)
- return "".join(buffers)
- else:
- # Read until size bytes or EOF seen, whichever comes first
- buf_len = len(data)
- if buf_len >= size:
- self._rbuf = data[size:]
- return data[:size]
- buffers = []
- if data:
- buffers.append(data)
- self._rbuf = ""
- while True:
- left = size - buf_len
- recv_size = max(self._rbufsize, left)
- data = self._sock.recv(recv_size)
- if not data:
- break
- buffers.append(data)
- n = len(data)
- if n >= left:
- self._rbuf = data[left:]
- buffers[-1] = data[:left]
- break
- buf_len += n
- return "".join(buffers)
- def readline(self, size=-1):
- data = self._rbuf
- if size < 0:
- # Read until \n or EOF, whichever comes first
- if self._rbufsize <= 1:
- # Speed up unbuffered case
- assert data == ""
- buffers = []
- recv = self._sock.recv
- while data != "\n":
- data = recv(1)
- if not data:
- break
- buffers.append(data)
- return "".join(buffers)
- nl = data.find('\n')
- if nl >= 0:
- nl += 1
- self._rbuf = data[nl:]
- return data[:nl]
- buffers = []
- if data:
- buffers.append(data)
- self._rbuf = ""
- while True:
- data = self._sock.recv(self._rbufsize)
- if not data:
- break
- buffers.append(data)
- nl = data.find('\n')
- if nl >= 0:
- nl += 1
- self._rbuf = data[nl:]
- buffers[-1] = data[:nl]
- break
- return "".join(buffers)
- else:
- # Read until size bytes or \n or EOF seen, whichever comes first
- nl = data.find('\n', 0, size)
- if nl >= 0:
- nl += 1
- self._rbuf = data[nl:]
- return data[:nl]
- buf_len = len(data)
- if buf_len >= size:
- self._rbuf = data[size:]
- return data[:size]
- buffers = []
- if data:
- buffers.append(data)
- self._rbuf = ""
- while True:
- data = self._sock.recv(self._rbufsize)
- if not data:
- break
- buffers.append(data)
- left = size - buf_len
- nl = data.find('\n', 0, left)
- if nl >= 0:
- nl += 1
- self._rbuf = data[nl:]
- buffers[-1] = data[:nl]
- break
- n = len(data)
- if n >= left:
- self._rbuf = data[left:]
- buffers[-1] = data[:left]
- break
- buf_len += n
- return "".join(buffers)
- def readlines(self, sizehint=0):
- total = 0
- list = []
- while True:
- line = self.readline()
- if not line:
- break
- list.append(line)
- total += len(line)
- if sizehint and total >= sizehint:
- break
- return list
- # Iterator protocols
- def __iter__(self):
- return self
- def next(self):
- line = self.readline()
- if not line:
- raise StopIteration
- return line
- _GLOBAL_DEFAULT_TIMEOUT = object()
- def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
- source_address=None):
- """Connect to *address* and return the socket object.
- Convenience function. Connect to *address* (a 2-tuple ``(host,
- port)``) and return the socket object. Passing the optional
- *timeout* parameter will set the timeout on the socket instance
- before attempting to connect. If no *timeout* is supplied, the
- global default timeout setting returned by :func:`getdefaulttimeout`
- is used. If *source_address* is set it must be a tuple of (host, port)
- for the socket to bind as a source address before making the connection.
- An host of '' or port 0 tells the OS to use the default.
- """
- host, port = address
- err = None
- for res in getaddrinfo(host, port, 0, SOCK_STREAM):
- af, socktype, proto, canonname, sa = res
- sock = None
- try:
- sock = socket(af, socktype, proto)
- if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
- sock.settimeout(timeout)
- if source_address:
- sock.bind(source_address)
- sock.connect(sa)
- return sock
- except error as _:
- err = _
- if sock is not None:
- sock.close()
- if err is not None:
- raise err
- else:
- raise error("getaddrinfo returns an empty list")
- # Define the SSL support
- class ssl:
- def __init__(self, plain_sock, keyfile=None, certfile=None):
- try:
- self.ssl_sock = self._make_ssl_socket(plain_sock)
- self._in_buf = java.io.BufferedInputStream(self.ssl_sock.getInputStream())
- self._out_buf = java.io.BufferedOutputStream(self.ssl_sock.getOutputStream())
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def _make_ssl_socket(self, plain_socket, auto_close=0):
- java_net_socket = plain_socket._get_jsocket()
- assert isinstance(java_net_socket, java.net.Socket)
- host = java_net_socket.getInetAddress().getHostAddress()
- port = java_net_socket.getPort()
- factory = javax.net.ssl.SSLSocketFactory.getDefault();
- ssl_socket = factory.createSocket(java_net_socket, host, port, auto_close)
- ssl_socket.setEnabledCipherSuites(ssl_socket.getSupportedCipherSuites())
- ssl_socket.startHandshake()
- return ssl_socket
- def read(self, n=4096):
- try:
- data = jarray.zeros(n, 'b')
- m = self._in_buf.read(data, 0, n)
- if m <= 0:
- return ""
- if m < n:
- data = data[:m]
- return data.tostring()
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def write(self, s):
- try:
- self._out_buf.write(s)
- self._out_buf.flush()
- return len(s)
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def _get_server_cert(self):
- try:
- return self.ssl_sock.getSession().getPeerCertificates()[0]
- except java.lang.Exception, jlx:
- raise _map_exception(jlx)
- def server(self):
- cert = self._get_server_cert()
- return cert.getSubjectDN().toString()
- def issuer(self):
- cert = self._get_server_cert()
- return cert.getIssuerDN().toString()
- _realssl = ssl
- def ssl(sock, keyfile=None, certfile=None):
- if hasattr(sock, "_sock"):
- sock = sock._sock
- return _realssl(sock, keyfile, certfile)
- def test():
- s = socket(AF_INET, SOCK_STREAM)
- s.connect(("", 80))
- s.send("GET / HTTP/1.0\r\n\r\n")
- while 1:
- data = s.recv(2000)
- print data
- if not data:
- break
- if __name__ == '__main__':
- test()