blob: 66bb831256b762187ee2d06c85f043d56e3854ad [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001"""
2This is an updated socket module for use on JVMs > 1.5; it is derived from the old jython socket module.
3It is documented, along with known issues and workarounds, on the jython wiki.
4http://wiki.python.org/jython/NewSocketModule
5"""
6
7_defaulttimeout = None
8
9import errno
10import jarray
11import string
12import struct
13import sys
14import threading
15import time
16import types
17
18# Java.io classes
19import java.io.BufferedInputStream
20import java.io.BufferedOutputStream
21# Java.io exceptions
22import java.io.InterruptedIOException
23import java.io.IOException
24
25# Java.lang classes
26import java.lang.String
27# Java.lang exceptions
28import java.lang.Exception
29
30# Java.net classes
31import java.net.DatagramPacket
32import java.net.InetAddress
33import java.net.InetSocketAddress
34import java.net.Socket
35# Java.net exceptions
36import java.net.BindException
37import java.net.ConnectException
38import java.net.NoRouteToHostException
39import java.net.PortUnreachableException
40import java.net.ProtocolException
41import java.net.SocketException
42import java.net.SocketTimeoutException
43import java.net.UnknownHostException
44
45# Java.nio classes
46import java.nio.ByteBuffer
47import java.nio.channels.DatagramChannel
48import java.nio.channels.ServerSocketChannel
49import java.nio.channels.SocketChannel
50# Java.nio exceptions
51import java.nio.channels.AlreadyConnectedException
52import java.nio.channels.AsynchronousCloseException
53import java.nio.channels.CancelledKeyException
54import java.nio.channels.ClosedByInterruptException
55import java.nio.channels.ClosedChannelException
56import java.nio.channels.ClosedSelectorException
57import java.nio.channels.ConnectionPendingException
58import java.nio.channels.IllegalBlockingModeException
59import java.nio.channels.IllegalSelectorException
60import java.nio.channels.NoConnectionPendingException
61import java.nio.channels.NonReadableChannelException
62import java.nio.channels.NonWritableChannelException
63import java.nio.channels.NotYetBoundException
64import java.nio.channels.NotYetConnectedException
65import java.nio.channels.UnresolvedAddressException
66import java.nio.channels.UnsupportedAddressTypeException
67
68# Javax.net.ssl classes
69import javax.net.ssl.SSLSocketFactory
70# Javax.net.ssl exceptions
71javax.net.ssl.SSLException
72javax.net.ssl.SSLHandshakeException
73javax.net.ssl.SSLKeyException
74javax.net.ssl.SSLPeerUnverifiedException
75javax.net.ssl.SSLProtocolException
76
77import org.python.core.io.DatagramSocketIO
78import org.python.core.io.ServerSocketIO
79import org.python.core.io.SocketIO
80from org.python.core.Py import newString as asPyString
81
82class error(Exception): pass
83class herror(error): pass
84class gaierror(error): pass
85class timeout(error): pass
86class sslerror(error): pass
87
88def _unmapped_exception(exc):
89 return error(-1, 'Unmapped exception: %s' % exc)
90
91def java_net_socketexception_handler(exc):
92 if exc.message.startswith("Address family not supported by protocol family"):
93 return error(errno.EAFNOSUPPORT, 'Address family not supported by protocol family: See http://wiki.python.org/jython/NewSocketModule#IPV6addresssupport')
94 return _unmapped_exception(exc)
95
96def would_block_error(exc=None):
97 return error(errno.EWOULDBLOCK, 'The socket operation could not complete without blocking')
98
99ALL = None
100
101_exception_map = {
102
103# (<javaexception>, <circumstance>) : callable that raises the python equivalent exception, or None to stub out as unmapped
104
105(java.io.IOException, ALL) : lambda x: error(errno.ECONNRESET, 'Software caused connection abort'),
106(java.io.InterruptedIOException, ALL) : lambda x: timeout('timed out'),
107
108(java.net.BindException, ALL) : lambda x: error(errno.EADDRINUSE, 'Address already in use'),
109(java.net.ConnectException, ALL) : lambda x: error(errno.ECONNREFUSED, 'Connection refused'),
110(java.net.NoRouteToHostException, ALL) : None,
111(java.net.PortUnreachableException, ALL) : None,
112(java.net.ProtocolException, ALL) : None,
113(java.net.SocketException, ALL) : java_net_socketexception_handler,
114(java.net.SocketTimeoutException, ALL) : lambda x: timeout('timed out'),
115(java.net.UnknownHostException, ALL) : lambda x: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'),
116
117(java.nio.channels.AlreadyConnectedException, ALL) : lambda x: error(errno.EISCONN, 'Socket is already connected'),
118(java.nio.channels.AsynchronousCloseException, ALL) : None,
119(java.nio.channels.CancelledKeyException, ALL) : None,
120(java.nio.channels.ClosedByInterruptException, ALL) : None,
121(java.nio.channels.ClosedChannelException, ALL) : lambda x: error(errno.EPIPE, 'Socket closed'),
122(java.nio.channels.ClosedSelectorException, ALL) : None,
123(java.nio.channels.ConnectionPendingException, ALL) : None,
124(java.nio.channels.IllegalBlockingModeException, ALL) : None,
125(java.nio.channels.IllegalSelectorException, ALL) : None,
126(java.nio.channels.NoConnectionPendingException, ALL) : None,
127(java.nio.channels.NonReadableChannelException, ALL) : None,
128(java.nio.channels.NonWritableChannelException, ALL) : None,
129(java.nio.channels.NotYetBoundException, ALL) : None,
130(java.nio.channels.NotYetConnectedException, ALL) : None,
131(java.nio.channels.UnresolvedAddressException, ALL) : lambda x: gaierror(errno.EGETADDRINFOFAILED, 'getaddrinfo failed'),
132(java.nio.channels.UnsupportedAddressTypeException, ALL) : None,
133
134# These error codes are currently wrong: getting them correct is going to require
135# some investigation. Cpython 2.6 introduced extensive SSL support.
136
137(javax.net.ssl.SSLException, ALL) : lambda x: sslerror(-1, 'SSL exception'),
138(javax.net.ssl.SSLHandshakeException, ALL) : lambda x: sslerror(-1, 'SSL handshake exception'),
139(javax.net.ssl.SSLKeyException, ALL) : lambda x: sslerror(-1, 'SSL key exception'),
140(javax.net.ssl.SSLPeerUnverifiedException, ALL) : lambda x: sslerror(-1, 'SSL peer unverified exception'),
141(javax.net.ssl.SSLProtocolException, ALL) : lambda x: sslerror(-1, 'SSL protocol exception'),
142
143}
144
145def _map_exception(exc, circumstance=ALL):
146# print "Mapping exception: %s" % exc
147 mapped_exception = _exception_map.get((exc.__class__, circumstance))
148 if mapped_exception:
149 exception = mapped_exception(exc)
150 else:
151 exception = error(-1, 'Unmapped exception: %s' % exc)
152 exception.java_exception = exc
153 return exception
154
155_feature_support_map = {
156 'ipv6': True,
157 'idna': False,
158 'tipc': False,
159}
160
161def supports(feature, *args):
162 if len(args) == 1:
163 _feature_support_map[feature] = args[0]
164 return _feature_support_map.get(feature, False)
165
166MODE_BLOCKING = 'block'
167MODE_NONBLOCKING = 'nonblock'
168MODE_TIMEOUT = 'timeout'
169
170_permitted_modes = (MODE_BLOCKING, MODE_NONBLOCKING, MODE_TIMEOUT)
171
172SHUT_RD = 0
173SHUT_WR = 1
174SHUT_RDWR = 2
175
176AF_UNSPEC = 0
177AF_INET = 2
178AF_INET6 = 23
179
180AI_PASSIVE=1
181AI_CANONNAME=2
182
183# For some reason, probably historical, SOCK_DGRAM and SOCK_STREAM are opposite values of what they are on cpython.
184# I.E. The following is the way they are on cpython
185# SOCK_STREAM = 1
186# SOCK_DGRAM = 2
187# At some point, we should probably switch them around, which *should* not affect anybody
188
189SOCK_DGRAM = 1
190SOCK_STREAM = 2
191SOCK_RAW = 3 # not supported
192SOCK_RDM = 4 # not supported
193SOCK_SEQPACKET = 5 # not supported
194
195SOL_SOCKET = 0xFFFF
196IPPROTO_TCP = 6
197IPPROTO_UDP = 17
198
199SO_BROADCAST = 1
200SO_KEEPALIVE = 2
201SO_LINGER = 4
202SO_OOBINLINE = 8
203SO_RCVBUF = 16
204SO_REUSEADDR = 32
205SO_SNDBUF = 64
206SO_TIMEOUT = 128
207
208TCP_NODELAY = 256
209
210INADDR_ANY = "0.0.0.0"
211INADDR_BROADCAST = "255.255.255.255"
212
213# Options with negative constants are not supported
214# They are being added here so that code that refers to them
215# will not break with an AttributeError
216
217SO_ACCEPTCONN = -1
218SO_DEBUG = -2
219SO_DONTROUTE = -4
220SO_ERROR = -8
221SO_EXCLUSIVEADDRUSE = -16
222SO_RCVLOWAT = -32
223SO_RCVTIMEO = -64
224SO_REUSEPORT = -128
225SO_SNDLOWAT = -256
226SO_SNDTIMEO = -512
227SO_TYPE = -1024
228SO_USELOOPBACK = -2048
229
230__all__ = ['AF_UNSPEC', 'AF_INET', 'AF_INET6', 'AI_PASSIVE', 'SOCK_DGRAM',
231 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM', 'SOL_SOCKET',
232 'SO_BROADCAST', 'SO_ERROR', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE',
233 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY',
234 'INADDR_ANY', 'INADDR_BROADCAST', 'IPPROTO_TCP', 'IPPROTO_UDP',
235 'SocketType', 'error', 'herror', 'gaierror', 'timeout',
236 'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname',
237 'socket', 'getaddrinfo', 'getdefaulttimeout', 'setdefaulttimeout',
238 'has_ipv6', 'htons', 'htonl', 'ntohs', 'ntohl',
239 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR',
240 ]
241
242def _constant_to_name(const_value):
243 sock_module = sys.modules['socket']
244 try:
245 for name in dir(sock_module):
246 if getattr(sock_module, name) is const_value:
247 return name
248 return "Unknown"
249 finally:
250 sock_module = None
251
252class _nio_impl:
253
254 timeout = None
255 mode = MODE_BLOCKING
256
257 def getpeername(self):
258 return (self.jsocket.getInetAddress().getHostAddress(), self.jsocket.getPort() )
259
260 def config(self, mode, timeout):
261 self.mode = mode
262 if self.mode == MODE_BLOCKING:
263 self.jchannel.configureBlocking(1)
264 if self.mode == MODE_NONBLOCKING:
265 self.jchannel.configureBlocking(0)
266 if self.mode == MODE_TIMEOUT:
267 self.jchannel.configureBlocking(1)
268 self._timeout_millis = int(timeout*1000)
269 self.jsocket.setSoTimeout(self._timeout_millis)
270
271 def getsockopt(self, level, option):
272 if (level, option) in self.options:
273 result = getattr(self.jsocket, "get%s" % self.options[ (level, option) ])()
274 if option == SO_LINGER:
275 if result == -1:
276 enabled, linger_time = 0, 0
277 else:
278 enabled, linger_time = 1, result
279 return struct.pack('ii', enabled, linger_time)
280 return result
281 else:
282 raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % (_constant_to_name(option), _constant_to_name(level), str(self.jsocket)))
283
284 def setsockopt(self, level, option, value):
285 if (level, option) in self.options:
286 if option == SO_LINGER:
287 values = struct.unpack('ii', value)
288 self.jsocket.setSoLinger(*values)
289 else:
290 getattr(self.jsocket, "set%s" % self.options[ (level, option) ])(value)
291 else:
292 raise error(errno.ENOPROTOOPT, "Socket option '%s' (level '%s') not supported on socket(%s)" % (_constant_to_name(option), _constant_to_name(level), str(self.jsocket)))
293
294 def close(self):
295 self.jsocket.close()
296
297 def getchannel(self):
298 return self.jchannel
299
300 def fileno(self):
301 return self.socketio
302
303class _client_socket_impl(_nio_impl):
304
305 options = {
306 (SOL_SOCKET, SO_KEEPALIVE): 'KeepAlive',
307 (SOL_SOCKET, SO_LINGER): 'SoLinger',
308 (SOL_SOCKET, SO_OOBINLINE): 'OOBInline',
309 (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
310 (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
311 (SOL_SOCKET, SO_SNDBUF): 'SendBufferSize',
312 (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
313 (IPPROTO_TCP, TCP_NODELAY): 'TcpNoDelay',
314 }
315
316 def __init__(self, socket=None):
317 if socket:
318 self.jchannel = socket.getChannel()
319 else:
320 self.jchannel = java.nio.channels.SocketChannel.open()
321 self.jsocket = self.jchannel.socket()
322 self.socketio = org.python.core.io.SocketIO(self.jchannel, 'rw')
323
324 def bind(self, jsockaddr, reuse_addr):
325 self.jsocket.setReuseAddress(reuse_addr)
326 self.jsocket.bind(jsockaddr)
327
328 def connect(self, jsockaddr):
329 if self.mode == MODE_TIMEOUT:
330 self.jsocket.connect (jsockaddr, self._timeout_millis)
331 else:
332 self.jchannel.connect(jsockaddr)
333
334 def finish_connect(self):
335 return self.jchannel.finishConnect()
336
337 def _do_read_net(self, buf):
338 # Need two separate implementations because the java.nio APIs do not support timeouts
339 return self.jsocket.getInputStream().read(buf)
340
341 def _do_read_nio(self, buf):
342 bytebuf = java.nio.ByteBuffer.wrap(buf)
343 count = self.jchannel.read(bytebuf)
344 return count
345
346 def _do_write_net(self, buf):
347 self.jsocket.getOutputStream().write(buf)
348 return len(buf)
349
350 def _do_write_nio(self, buf):
351 bytebuf = java.nio.ByteBuffer.wrap(buf)
352 count = self.jchannel.write(bytebuf)
353 return count
354
355 def read(self, buf):
356 if self.mode == MODE_TIMEOUT:
357 return self._do_read_net(buf)
358 else:
359 return self._do_read_nio(buf)
360
361 def write(self, buf):
362 if self.mode == MODE_TIMEOUT:
363 return self._do_write_net(buf)
364 else:
365 return self._do_write_nio(buf)
366
367 def shutdown(self, how):
368 if how in (SHUT_RD, SHUT_RDWR):
369 self.jsocket.shutdownInput()
370 if how in (SHUT_WR, SHUT_RDWR):
371 self.jsocket.shutdownOutput()
372
373class _server_socket_impl(_nio_impl):
374
375 options = {
376 (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
377 (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
378 (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
379 }
380
381 def __init__(self, jsockaddr, backlog, reuse_addr):
382 self.jchannel = java.nio.channels.ServerSocketChannel.open()
383 self.jsocket = self.jchannel.socket()
384 self.jsocket.setReuseAddress(reuse_addr)
385 self.jsocket.bind(jsockaddr, backlog)
386 self.socketio = org.python.core.io.ServerSocketIO(self.jchannel, 'rw')
387
388 def accept(self):
389 if self.mode in (MODE_BLOCKING, MODE_NONBLOCKING):
390 new_cli_chan = self.jchannel.accept()
391 if new_cli_chan is not None:
392 return _client_socket_impl(new_cli_chan.socket())
393 else:
394 return None
395 else:
396 # In timeout mode now
397 new_cli_sock = self.jsocket.accept()
398 return _client_socket_impl(new_cli_sock)
399
400 def shutdown(self, how):
401 # This is no-op on java, for server sockets.
402 # What the user wants to achieve is achieved by calling close() on
403 # java/jython. But we can't call that here because that would then
404 # later cause the user explicit close() call to fail
405 pass
406
407class _datagram_socket_impl(_nio_impl):
408
409 options = {
410 (SOL_SOCKET, SO_BROADCAST): 'Broadcast',
411 (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize',
412 (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress',
413 (SOL_SOCKET, SO_SNDBUF): 'SendBufferSize',
414 (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout',
415 }
416
417 def __init__(self, jsockaddr=None, reuse_addr=0):
418 self.jchannel = java.nio.channels.DatagramChannel.open()
419 self.jsocket = self.jchannel.socket()
420 if jsockaddr is not None:
421 self.jsocket.setReuseAddress(reuse_addr)
422 self.jsocket.bind(jsockaddr)
423 self.socketio = org.python.core.io.DatagramSocketIO(self.jchannel, 'rw')
424
425 def connect(self, jsockaddr):
426 self.jchannel.connect(jsockaddr)
427
428 def disconnect(self):
429 """
430 Disconnect the datagram socket.
431 cpython appears not to have this operation
432 """
433 self.jchannel.disconnect()
434
435 def shutdown(self, how):
436 # This is no-op on java, for datagram sockets.
437 # What the user wants to achieve is achieved by calling close() on
438 # java/jython. But we can't call that here because that would then
439 # later cause the user explicit close() call to fail
440 pass
441
442 def _do_send_net(self, byte_array, socket_address, flags):
443 # Need two separate implementations because the java.nio APIs do not support timeouts
444 num_bytes = len(byte_array)
445 if self.jsocket.isConnected() and socket_address is None:
446 packet = java.net.DatagramPacket(byte_array, num_bytes)
447 else:
448 packet = java.net.DatagramPacket(byte_array, num_bytes, socket_address)
449 self.jsocket.send(packet)
450 return num_bytes
451
452 def _do_send_nio(self, byte_array, socket_address, flags):
453 byte_buf = java.nio.ByteBuffer.wrap(byte_array)
454 if self.jchannel.isConnected() and socket_address is None:
455 bytes_sent = self.jchannel.write(byte_buf)
456 else:
457 bytes_sent = self.jchannel.send(byte_buf, socket_address)
458 return bytes_sent
459
460 def sendto(self, byte_array, jsockaddr, flags):
461 if self.mode == MODE_TIMEOUT:
462 return self._do_send_net(byte_array, jsockaddr, flags)
463 else:
464 return self._do_send_nio(byte_array, jsockaddr, flags)
465
466 def send(self, byte_array, flags):
467 if self.mode == MODE_TIMEOUT:
468 return self._do_send_net(byte_array, None, flags)
469 else:
470 return self._do_send_nio(byte_array, None, flags)
471
472 def _do_receive_net(self, return_source_address, num_bytes, flags):
473 byte_array = jarray.zeros(num_bytes, 'b')
474 packet = java.net.DatagramPacket(byte_array, num_bytes)
475 self.jsocket.receive(packet)
476 bytes_rcvd = packet.getLength()
477 if bytes_rcvd < num_bytes:
478 byte_array = byte_array[:bytes_rcvd]
479 return_data = byte_array.tostring()
480 if return_source_address:
481 host = None
482 if packet.getAddress():
483 host = packet.getAddress().getHostAddress()
484 port = packet.getPort()
485 return return_data, (host, port)
486 else:
487 return return_data
488
489 def _do_receive_nio(self, return_source_address, num_bytes, flags):
490 byte_array = jarray.zeros(num_bytes, 'b')
491 byte_buf = java.nio.ByteBuffer.wrap(byte_array)
492 source_address = self.jchannel.receive(byte_buf)
493 if source_address is None and not self.jchannel.isBlocking():
494 raise would_block_error()
495 byte_buf.flip() ; bytes_read = byte_buf.remaining()
496 if bytes_read < num_bytes:
497 byte_array = byte_array[:bytes_read]
498 return_data = byte_array.tostring()
499 if return_source_address:
500 return return_data, (source_address.getAddress().getHostAddress(), source_address.getPort())
501 else:
502 return return_data
503
504 def recvfrom(self, num_bytes, flags):
505 if self.mode == MODE_TIMEOUT:
506 return self._do_receive_net(1, num_bytes, flags)
507 else:
508 return self._do_receive_nio(1, num_bytes, flags)
509
510 def recv(self, num_bytes, flags):
511 if self.mode == MODE_TIMEOUT:
512 return self._do_receive_net(0, num_bytes, flags)
513 else:
514 return self._do_receive_nio(0, num_bytes, flags)
515
516has_ipv6 = True # IPV6 FTW!
517
518# Name and address functions
519
520def _gethostbyaddr(name):
521 # This is as close as I can get; at least the types are correct...
522 addresses = java.net.InetAddress.getAllByName(gethostbyname(name))
523 names = []
524 addrs = []
525 for addr in addresses:
526 names.append(asPyString(addr.getHostName()))
527 addrs.append(asPyString(addr.getHostAddress()))
528 return (names, addrs)
529
530def getfqdn(name=None):
531 """
532 Return a fully qualified domain name for name. If name is omitted or empty
533 it is interpreted as the local host. To find the fully qualified name,
534 the hostname returned by gethostbyaddr() is checked, then aliases for the
535 host, if available. The first name which includes a period is selected.
536 In case no fully qualified domain name is available, the hostname is retur
537 New in version 2.0.
538 """
539 if not name:
540 name = gethostname()
541 names, addrs = _gethostbyaddr(name)
542 for a in names:
543 if a.find(".") >= 0:
544 return a
545 return name
546
547def gethostname():
548 try:
549 return asPyString(java.net.InetAddress.getLocalHost().getHostName())
550 except java.lang.Exception, jlx:
551 raise _map_exception(jlx)
552
553def gethostbyname(name):
554 try:
555 return asPyString(java.net.InetAddress.getByName(name).getHostAddress())
556 except java.lang.Exception, jlx:
557 raise _map_exception(jlx)
558
559def gethostbyaddr(name):
560 names, addrs = _gethostbyaddr(name)
561 return (names[0], names, addrs)
562
563def getservbyname(service_name, protocol_name=None):
564 try:
565 from jnr.netdb import Service
566 except ImportError:
567 return None
568 return Service.getServiceByName(service_name, protocol_name).getPort()
569
570def getservbyport(port, protocol_name=None):
571 try:
572 from jnr.netdb import Service
573 except ImportError:
574 return None
575 return Service.getServiceByPort(port, protocol_name).getName()
576
577def getprotobyname(protocol_name=None):
578 try:
579 from jnr.netdb import Protocol
580 except ImportError:
581 return None
582 return Protocol.getProtocolByName(protocol_name).getProto()
583
584def _realsocket(family = AF_INET, type = SOCK_STREAM, protocol=0):
585 assert family in (AF_INET, AF_INET6), "Only AF_INET and AF_INET6 sockets are currently supported on jython"
586 assert type in (SOCK_DGRAM, SOCK_STREAM), "Only SOCK_STREAM and SOCK_DGRAM sockets are currently supported on jython"
587 if type == SOCK_STREAM:
588 if protocol != 0:
589 assert protocol == IPPROTO_TCP, "Only IPPROTO_TCP supported on SOCK_STREAM sockets"
590 return _tcpsocket()
591 else:
592 if protocol != 0:
593 assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets"
594 return _udpsocket()
595
596#
597# Attempt to provide IDNA (RFC 3490) support.
598#
599# Try java.net.IDN, built into java 6
600#
601
602idna_libraries = [
603 ('java.net.IDN', 'toASCII', java.lang.IllegalArgumentException)
604]
605
606for idna_lib, idna_fn_name, exc in idna_libraries:
607 try:
608 m = __import__(idna_lib, globals(), locals(), [idna_fn_name])
609 idna_fn = getattr(m, idna_fn_name)
610 def _encode_idna(name):
611 try:
612 return idna_fn(name)
613 except exc:
614 raise UnicodeEncodeError(name)
615 supports('idna', True)
616 break
617 except (AttributeError, ImportError), e:
618 pass
619else:
620 _encode_idna = lambda x: x.encode("ascii")
621
622#
623# Define data structures to support IPV4 and IPV6.
624#
625
626class _ip_address_t: pass
627
628class _ipv4_address_t(_ip_address_t):
629
630 def __init__(self, sockaddr, port, jaddress):
631 self.sockaddr = sockaddr
632 self.port = port
633 self.jaddress = jaddress
634
635 def __getitem__(self, index):
636 if 0 == index:
637 return self.sockaddr
638 elif 1 == index:
639 return self.port
640 else:
641 raise IndexError()
642
643 def __len__(self):
644 return 2
645
646 def __str__(self):
647 return "('%s', %d)" % (self.sockaddr, self.port)
648
649 __repr__ = __str__
650
651class _ipv6_address_t(_ip_address_t):
652
653 def __init__(self, sockaddr, port, jaddress):
654 self.sockaddr = sockaddr
655 self.port = port
656 self.jaddress = jaddress
657
658 def __getitem__(self, index):
659 if 0 == index:
660 return self.sockaddr
661 elif 1 == index:
662 return self.port
663 elif 2 == index:
664 return 0
665 elif 3 == index:
666 return self.jaddress.scopeId
667 else:
668 raise IndexError()
669
670 def __len__(self):
671 return 4
672
673 def __str__(self):
674 return "('%s', %d, 0, %d)" % (self.sockaddr, self.port, self.jaddress.scopeId)
675
676 __repr__ = __str__
677
678def _get_jsockaddr(address_object, for_udp=False):
679 if address_object is None:
680 return java.net.InetSocketAddress(0) # Let the system pick an ephemeral port
681 if isinstance(address_object, _ip_address_t):
682 return java.net.InetSocketAddress(address_object.jaddress, address_object[1])
683 error_message = "Address must be a 2-tuple (ipv4: (host, port)) or a 4-tuple (ipv6: (host, port, flow, scope))"
684 if not isinstance(address_object, tuple) or \
685 len(address_object) not in [2,4] or \
686 not isinstance(address_object[0], basestring) or \
687 not isinstance(address_object[1], (int, long)):
688 raise TypeError(error_message)
689 if len(address_object) == 4 and not isinstance(address_object[3], (int, long)):
690 raise TypeError(error_message)
691 hostname, port = address_object[0].strip(), address_object[1]
692 if for_udp:
693 if hostname == "":
694 hostname = INADDR_ANY
695 elif hostname == "<broadcast>":
696 hostname = INADDR_BROADCAST
697 else:
698 if hostname == "":
699 hostname = None
700 if hostname is None:
701 return java.net.InetSocketAddress(port)
702 if isinstance(hostname, unicode):
703 hostname = _encode_idna(hostname)
704 if len(address_object) == 4:
705 # There is no way to get a Inet6Address: Inet6Address.getByName() simply calls
706 # InetAddress.getByName,() which also returns Inet4Address objects
707 # If users want to use IPv6 address, scoped or not,
708 # they should use getaddrinfo(family=AF_INET6)
709 pass
710 return java.net.InetSocketAddress(java.net.InetAddress.getByName(hostname), port)
711
712_ipv4_addresses_only = False
713
714def _use_ipv4_addresses_only(value):
715 global _ipv4_addresses_only
716 _ipv4_addresses_only = value
717
718def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=None):
719 try:
720 if not family in [AF_INET, AF_INET6, AF_UNSPEC]:
721 raise gaierror(errno.EIO, 'ai_family not supported')
722 filter_fns = []
723 if _ipv4_addresses_only:
724 filter_fns.append( lambda x: isinstance(x, java.net.Inet4Address) )
725 else:
726 filter_fns.append({
727 AF_INET: lambda x: isinstance(x, java.net.Inet4Address),
728 AF_INET6: lambda x: isinstance(x, java.net.Inet6Address),
729 AF_UNSPEC: lambda x: isinstance(x, java.net.InetAddress),
730 }[family])
731 if host == "":
732 host = java.net.InetAddress.getLocalHost().getHostName()
733 if isinstance(host, unicode):
734 host = _encode_idna(host)
735 passive_mode = flags is not None and flags & AI_PASSIVE
736 canonname_mode = flags is not None and flags & AI_CANONNAME
737 results = []
738 for a in java.net.InetAddress.getAllByName(host):
739 if len([f for f in filter_fns if f(a)]):
740 family = {java.net.Inet4Address: AF_INET, java.net.Inet6Address: AF_INET6}[a.getClass()]
741 if passive_mode and not canonname_mode:
742 canonname = ""
743 else:
744 canonname = asPyString(a.getCanonicalHostName())
745 if host is None and passive_mode and not canonname_mode:
746 sockaddr = INADDR_ANY
747 else:
748 sockaddr = asPyString(a.getHostAddress())
749 # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses
750 sock_tuple = {AF_INET : _ipv4_address_t, AF_INET6 : _ipv6_address_t}[family](sockaddr, port, a)
751 results.append((family, socktype, proto, canonname, sock_tuple))
752 return results
753 except java.lang.Exception, jlx:
754 raise _map_exception(jlx)
755
756def getnameinfo(sock_addr, flags):
757 raise NotImplementedError("getnameinfo not yet supported on jython.")
758
759def getdefaulttimeout():
760 return _defaulttimeout
761
762def _calctimeoutvalue(value):
763 if value is None:
764 return None
765 try:
766 floatvalue = float(value)
767 except:
768 raise TypeError('Socket timeout value must be a number or None')
769 if floatvalue < 0.0:
770 raise ValueError("Socket timeout value cannot be negative")
771 if floatvalue < 0.000001:
772 return 0.0
773 return floatvalue
774
775def setdefaulttimeout(timeout):
776 global _defaulttimeout
777 try:
778 _defaulttimeout = _calctimeoutvalue(timeout)
779 finally:
780 _nonblocking_api_mixin.timeout = _defaulttimeout
781
782def htons(x): return x
783def htonl(x): return x
784def ntohs(x): return x
785def ntohl(x): return x
786
787def inet_pton(family, ip_string):
788 try:
789 ia = java.net.InetAddress.getByName(ip_string)
790 bytes = []
791 for byte in ia.getAddress():
792 if byte < 0:
793 bytes.append(byte+256)
794 else:
795 bytes.append(byte)
796 return "".join([chr(byte) for byte in bytes])
797 except java.lang.Exception, jlx:
798 raise _map_exception(jlx)
799
800def inet_ntop(family, packed_ip):
801 try:
802 jByteArray = jarray.array(packed_ip, 'b')
803 ia = java.net.InetAddress.getByAddress(jByteArray)
804 return ia.getHostAddress()
805 except java.lang.Exception, jlx:
806 raise _map_exception(jlx)
807
808def inet_aton(ip_string):
809 return inet_pton(AF_INET, ip_string)
810
811def inet_ntoa(packed_ip):
812 return inet_ntop(AF_INET, packed_ip)
813
814class _nonblocking_api_mixin:
815
816 mode = MODE_BLOCKING
817 reference_count = 0
818 close_lock = threading.Lock()
819
820 def __init__(self):
821 self.timeout = _defaulttimeout
822 if self.timeout is not None:
823 self.mode = MODE_TIMEOUT
824 self.pending_options = {
825 (SOL_SOCKET, SO_REUSEADDR): 0,
826 }
827
828 def gettimeout(self):
829 return self.timeout
830
831 def settimeout(self, timeout):
832 self.timeout = _calctimeoutvalue(timeout)
833 if self.timeout is None:
834 self.mode = MODE_BLOCKING
835 elif self.timeout < 0.000001:
836 self.mode = MODE_NONBLOCKING
837 else:
838 self.mode = MODE_TIMEOUT
839 self._config()
840
841 def setblocking(self, flag):
842 if flag:
843 self.mode = MODE_BLOCKING
844 self.timeout = None
845 else:
846 self.mode = MODE_NONBLOCKING
847 self.timeout = 0.0
848 self._config()
849
850 def getblocking(self):
851 return self.mode == MODE_BLOCKING
852
853 def setsockopt(self, level, optname, value):
854 try:
855 if self.sock_impl:
856 self.sock_impl.setsockopt(level, optname, value)
857 else:
858 self.pending_options[ (level, optname) ] = value
859 except java.lang.Exception, jlx:
860 raise _map_exception(jlx)
861
862 def getsockopt(self, level, optname):
863 try:
864 if self.sock_impl:
865 return self.sock_impl.getsockopt(level, optname)
866 else:
867 return self.pending_options.get( (level, optname), None)
868 except java.lang.Exception, jlx:
869 raise _map_exception(jlx)
870
871 def shutdown(self, how):
872 assert how in (SHUT_RD, SHUT_WR, SHUT_RDWR)
873 if not self.sock_impl:
874 raise error(errno.ENOTCONN, "Transport endpoint is not connected")
875 try:
876 self.sock_impl.shutdown(how)
877 except java.lang.Exception, jlx:
878 raise _map_exception(jlx)
879
880 def close(self):
881 try:
882 if self.sock_impl:
883 self.sock_impl.close()
884 except java.lang.Exception, jlx:
885 raise _map_exception(jlx)
886
887 def _config(self):
888 assert self.mode in _permitted_modes
889 if self.sock_impl:
890 self.sock_impl.config(self.mode, self.timeout)
891 for level, optname in self.pending_options.keys():
892 if optname != SO_REUSEADDR:
893 self.sock_impl.setsockopt(level, optname, self.pending_options[ (level, optname) ])
894
895 def getchannel(self):
896 if not self.sock_impl:
897 return None
898 return self.sock_impl.getchannel()
899
900 def fileno(self):
901 if not self.sock_impl:
902 return None
903 return self.sock_impl.fileno()
904
905 def _get_jsocket(self):
906 return self.sock_impl.jsocket
907
908class _tcpsocket(_nonblocking_api_mixin):
909
910 sock_impl = None
911 istream = None
912 ostream = None
913 local_addr = None
914 server = 0
915
916 def __init__(self):
917 _nonblocking_api_mixin.__init__(self)
918
919 def bind(self, addr):
920 assert not self.sock_impl
921 assert not self.local_addr
922 # Do the address format check
923 _get_jsockaddr(addr)
924 self.local_addr = addr
925
926 def listen(self, backlog):
927 "This signifies a server socket"
928 try:
929 assert not self.sock_impl
930 self.server = 1
931 self.sock_impl = _server_socket_impl(_get_jsockaddr(self.local_addr), backlog, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
932 self._config()
933 except java.lang.Exception, jlx:
934 raise _map_exception(jlx)
935
936 def accept(self):
937 "This signifies a server socket"
938 try:
939 if not self.sock_impl:
940 self.listen()
941 assert self.server
942 new_sock = self.sock_impl.accept()
943 if not new_sock:
944 raise would_block_error()
945 cliconn = _tcpsocket()
946 cliconn.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ] = new_sock.jsocket.getReuseAddress()
947 cliconn.sock_impl = new_sock
948 cliconn._setup()
949 return cliconn, new_sock.getpeername()
950 except java.lang.Exception, jlx:
951 raise _map_exception(jlx)
952
953 def _do_connect(self, addr):
954 try:
955 assert not self.sock_impl
956 self.sock_impl = _client_socket_impl()
957 if self.local_addr: # Has the socket been bound to a local address?
958 self.sock_impl.bind(_get_jsockaddr(self.local_addr), self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
959 self._config() # Configure timeouts, etc, now that the socket exists
960 self.sock_impl.connect(_get_jsockaddr(addr))
961 except java.lang.Exception, jlx:
962 raise _map_exception(jlx)
963
964 def connect(self, addr):
965 "This signifies a client socket"
966 self._do_connect(addr)
967 self._setup()
968
969 def connect_ex(self, addr):
970 "This signifies a client socket"
971 if not self.sock_impl:
972 self._do_connect(addr)
973 if self.sock_impl.finish_connect():
974 self._setup()
975 if self.mode == MODE_NONBLOCKING:
976 return errno.EISCONN
977 return 0
978 return errno.EINPROGRESS
979
980 def _setup(self):
981 if self.mode != MODE_NONBLOCKING:
982 self.istream = self.sock_impl.jsocket.getInputStream()
983 self.ostream = self.sock_impl.jsocket.getOutputStream()
984
985 def recv(self, n):
986 try:
987 if not self.sock_impl: raise error(errno.ENOTCONN, 'Socket is not connected')
988 if self.sock_impl.jchannel.isConnectionPending():
989 self.sock_impl.jchannel.finishConnect()
990 data = jarray.zeros(n, 'b')
991 m = self.sock_impl.read(data)
992 if m == -1:#indicates EOF has been reached, so we just return the empty string
993 return ""
994 elif m <= 0:
995 if self.mode == MODE_NONBLOCKING:
996 raise would_block_error()
997 return ""
998 if m < n:
999 data = data[:m]
1000 return data.tostring()
1001 except java.lang.Exception, jlx:
1002 raise _map_exception(jlx)
1003
1004 def recvfrom(self, n):
1005 return self.recv(n), None
1006
1007 def send(self, s):
1008 try:
1009 if not self.sock_impl: raise error(errno.ENOTCONN, 'Socket is not connected')
1010 if self.sock_impl.jchannel.isConnectionPending():
1011 self.sock_impl.jchannel.finishConnect()
1012 numwritten = self.sock_impl.write(s)
1013 if numwritten == 0 and self.mode == MODE_NONBLOCKING:
1014 raise would_block_error()
1015 return numwritten
1016 except java.lang.Exception, jlx:
1017 raise _map_exception(jlx)
1018
1019 sendall = send
1020
1021 def getsockname(self):
1022 try:
1023 if not self.sock_impl:
1024 host, port = self.local_addr or ("", 0)
1025 host = java.net.InetAddress.getByName(host).getHostAddress()
1026 else:
1027 if self.server:
1028 host = self.sock_impl.jsocket.getInetAddress().getHostAddress()
1029 else:
1030 host = self.sock_impl.jsocket.getLocalAddress().getHostAddress()
1031 port = self.sock_impl.jsocket.getLocalPort()
1032 return (host, port)
1033 except java.lang.Exception, jlx:
1034 raise _map_exception(jlx)
1035
1036 def getpeername(self):
1037 try:
1038 assert self.sock_impl
1039 assert not self.server
1040 host = self.sock_impl.jsocket.getInetAddress().getHostAddress()
1041 port = self.sock_impl.jsocket.getPort()
1042 return (host, port)
1043 except java.lang.Exception, jlx:
1044 raise _map_exception(jlx)
1045
1046 def close(self):
1047 try:
1048 if self.istream:
1049 self.istream.close()
1050 if self.ostream:
1051 self.ostream.close()
1052 if self.sock_impl:
1053 self.sock_impl.close()
1054 except java.lang.Exception, jlx:
1055 raise _map_exception(jlx)
1056
1057
1058class _udpsocket(_nonblocking_api_mixin):
1059
1060 sock_impl = None
1061 connected = False
1062
1063 def __init__(self):
1064 _nonblocking_api_mixin.__init__(self)
1065
1066 def bind(self, addr):
1067 try:
1068 assert not self.sock_impl
1069 self.sock_impl = _datagram_socket_impl(_get_jsockaddr(addr, True), self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
1070 self._config()
1071 except java.lang.Exception, jlx:
1072 raise _map_exception(jlx)
1073
1074 def _do_connect(self, addr):
1075 try:
1076 assert not self.connected, "Datagram Socket is already connected"
1077 if not self.sock_impl:
1078 self.sock_impl = _datagram_socket_impl()
1079 self._config()
1080 self.sock_impl.connect(_get_jsockaddr(addr))
1081 self.connected = True
1082 except java.lang.Exception, jlx:
1083 raise _map_exception(jlx)
1084
1085 def connect(self, addr):
1086 self._do_connect(addr)
1087
1088 def connect_ex(self, addr):
1089 if not self.sock_impl:
1090 self._do_connect(addr)
1091 return 0
1092
1093 def sendto(self, data, p1, p2=None):
1094 try:
1095 if not p2:
1096 flags, addr = 0, p1
1097 else:
1098 flags, addr = 0, p2
1099 if not self.sock_impl:
1100 self.sock_impl = _datagram_socket_impl()
1101 self._config()
1102 byte_array = java.lang.String(data).getBytes('iso-8859-1')
1103 result = self.sock_impl.sendto(byte_array, _get_jsockaddr(addr, True), flags)
1104 return result
1105 except java.lang.Exception, jlx:
1106 raise _map_exception(jlx)
1107
1108 def send(self, data, flags=None):
1109 if not self.connected: raise error(errno.ENOTCONN, "Socket is not connected")
1110 byte_array = java.lang.String(data).getBytes('iso-8859-1')
1111 return self.sock_impl.send(byte_array, flags)
1112
1113 def recvfrom(self, num_bytes, flags=None):
1114 """
1115 There is some disagreement as to what the behaviour should be if
1116 a recvfrom operation is requested on an unbound socket.
1117 See the following links for more information
1118 http://bugs.jython.org/issue1005
1119 http://bugs.sun.com/view_bug.do?bug_id=6621689
1120 """
1121 try:
1122 # This is the old 2.1 behaviour
1123 #assert self.sock_impl
1124 # This is amak's preferred interpretation
1125 #raise error(errno.ENOTCONN, "Recvfrom on unbound udp socket meaningless operation")
1126 # And this is the option for cpython compatibility
1127 if not self.sock_impl:
1128 self.sock_impl = _datagram_socket_impl()
1129 self._config()
1130 return self.sock_impl.recvfrom(num_bytes, flags)
1131 except java.lang.Exception, jlx:
1132 raise _map_exception(jlx)
1133
1134 def recv(self, num_bytes, flags=None):
1135 if not self.sock_impl: raise error(errno.ENOTCONN, "Socket is not connected")
1136 try:
1137 return self.sock_impl.recv(num_bytes, flags)
1138 except java.lang.Exception, jlx:
1139 raise _map_exception(jlx)
1140
1141 def getsockname(self):
1142 try:
1143 assert self.sock_impl
1144 host = self.sock_impl.jsocket.getLocalAddress().getHostAddress()
1145 port = self.sock_impl.jsocket.getLocalPort()
1146 return (host, port)
1147 except java.lang.Exception, jlx:
1148 raise _map_exception(jlx)
1149
1150 def getpeername(self):
1151 try:
1152 assert self.sock
1153 host = self.sock_impl.jsocket.getInetAddress().getHostAddress()
1154 port = self.sock_impl.jsocket.getPort()
1155 return (host, port)
1156 except java.lang.Exception, jlx:
1157 raise _map_exception(jlx)
1158
1159 def __del__(self):
1160 self.close()
1161
1162_socketmethods = (
1163 'bind', 'connect', 'connect_ex', 'fileno', 'listen',
1164 'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
1165 'sendall', 'setblocking',
1166 'settimeout', 'gettimeout', 'shutdown', 'getchannel')
1167
1168# All the method names that must be delegated to either the real socket
1169# object or the _closedsocket object.
1170_delegate_methods = ("recv", "recvfrom", "recv_into", "recvfrom_into",
1171 "send", "sendto")
1172
1173class _closedsocket(object):
1174 __slots__ = []
1175 def _dummy(*args):
1176 raise error(errno.EBADF, 'Bad file descriptor')
1177 # All _delegate_methods must also be initialized here.
1178 send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy
1179 __getattr__ = _dummy
1180
1181_active_sockets = set()
1182
1183def _closeActiveSockets():
1184 for socket in _active_sockets.copy():
1185 try:
1186 socket.close()
1187 except error:
1188 msg = 'Problem closing socket: %s: %r' % (socket, sys.exc_info())
1189 print >> sys.stderr, msg
1190
1191class _socketobject(object):
1192
1193 __doc__ = _realsocket.__doc__
1194
1195 __slots__ = ["_sock", "__weakref__"] + list(_delegate_methods)
1196
1197 def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
1198 if _sock is None:
1199 _sock = _realsocket(family, type, proto)
1200 _sock.reference_count += 1
1201 elif isinstance(_sock, _nonblocking_api_mixin):
1202 _sock.reference_count += 1
1203 self._sock = _sock
1204 for method in _delegate_methods:
1205 meth = getattr(_sock, method, None)
1206 if meth:
1207 setattr(self, method, meth)
1208 _active_sockets.add(self)
1209
1210 def close(self):
1211 try:
1212 _active_sockets.remove(self)
1213 except KeyError:
1214 pass
1215 _sock = self._sock
1216 if isinstance(_sock, _nonblocking_api_mixin):
1217 _sock.close_lock.acquire()
1218 try:
1219 _sock.reference_count -=1
1220 if not _sock.reference_count:
1221 _sock.close()
1222 self._sock = _closedsocket()
1223 dummy = self._sock._dummy
1224 for method in _delegate_methods:
1225 setattr(self, method, dummy)
1226 self.send = self.recv = self.sendto = self.recvfrom = \
1227 self._sock._dummy
1228 finally:
1229 _sock.close_lock.release()
1230 #close.__doc__ = _realsocket.close.__doc__
1231
1232 def accept(self):
1233 sock, addr = self._sock.accept()
1234 return _socketobject(_sock=sock), addr
1235 #accept.__doc__ = _realsocket.accept.__doc__
1236
1237 def dup(self):
1238 """dup() -> socket object
1239
1240 Return a new socket object connected to the same system resource."""
1241 _sock = self._sock
1242 if not isinstance(_sock, _nonblocking_api_mixin):
1243 return _socketobject(_sock=_sock)
1244
1245 _sock.close_lock.acquire()
1246 try:
1247 duped = _socketobject(_sock=_sock)
1248 finally:
1249 _sock.close_lock.release()
1250 return duped
1251
1252 def makefile(self, mode='r', bufsize=-1):
1253 """makefile([mode[, bufsize]]) -> file object
1254
1255 Return a regular file object corresponding to the socket. The mode
1256 and bufsize arguments are as for the built-in open() function."""
1257 _sock = self._sock
1258 if not isinstance(_sock, _nonblocking_api_mixin):
1259 return _fileobject(_sock, mode, bufsize)
1260
1261 _sock.close_lock.acquire()
1262 try:
1263 fileobject = _fileobject(_sock, mode, bufsize)
1264 finally:
1265 _sock.close_lock.release()
1266 return fileobject
1267
1268 family = property(lambda self: self._sock.family, doc="the socket family")
1269 type = property(lambda self: self._sock.type, doc="the socket type")
1270 proto = property(lambda self: self._sock.proto, doc="the socket protocol")
1271
1272 _s = ("def %s(self, *args): return self._sock.%s(*args)\n\n"
1273 #"%s.__doc__ = _realsocket.%s.__doc__\n")
1274 )
1275 for _m in _socketmethods:
1276 #exec _s % (_m, _m, _m, _m)
1277 exec _s % (_m, _m)
1278 del _m, _s
1279
1280socket = SocketType = _socketobject
1281
1282class _fileobject(object):
1283 """Faux file object attached to a socket object."""
1284
1285 default_bufsize = 8192
1286 name = "<socket>"
1287
1288 __slots__ = ["mode", "bufsize", "softspace",
1289 # "closed" is a property, see below
1290 "_sock", "_rbufsize", "_wbufsize", "_rbuf", "_wbuf",
1291 "_close"]
1292
1293 def __init__(self, sock, mode='rb', bufsize=-1, close=False):
1294 self._sock = sock
1295 if isinstance(sock, _nonblocking_api_mixin):
1296 sock.reference_count += 1
1297 self.mode = mode # Not actually used in this version
1298 if bufsize < 0:
1299 bufsize = self.default_bufsize
1300 self.bufsize = bufsize
1301 self.softspace = False
1302 if bufsize == 0:
1303 self._rbufsize = 1
1304 elif bufsize == 1:
1305 self._rbufsize = self.default_bufsize
1306 else:
1307 self._rbufsize = bufsize
1308 self._wbufsize = bufsize
1309 self._rbuf = "" # A string
1310 self._wbuf = [] # A list of strings
1311 self._close = close
1312
1313 def _getclosed(self):
1314 return self._sock is None
1315 closed = property(_getclosed, doc="True if the file is closed")
1316
1317 def close(self):
1318 try:
1319 if self._sock:
1320 self.flush()
1321 finally:
1322 if self._sock:
1323 if isinstance(self._sock, _nonblocking_api_mixin):
1324 self._sock.reference_count -= 1
1325 if not self._sock.reference_count or self._close:
1326 self._sock.close()
1327 elif self._close:
1328 self._sock.close()
1329 self._sock = None
1330
1331 def __del__(self):
1332 try:
1333 self.close()
1334 except:
1335 # close() may fail if __init__ didn't complete
1336 pass
1337
1338 def flush(self):
1339 if self._wbuf:
1340 buffer = "".join(self._wbuf)
1341 self._wbuf = []
1342 self._sock.sendall(buffer)
1343
1344 def fileno(self):
1345 return self._sock.fileno()
1346
1347 def write(self, data):
1348 data = str(data) # XXX Should really reject non-string non-buffers
1349 if not data:
1350 return
1351 self._wbuf.append(data)
1352 if (self._wbufsize == 0 or
1353 self._wbufsize == 1 and '\n' in data or
1354 self._get_wbuf_len() >= self._wbufsize):
1355 self.flush()
1356
1357 def writelines(self, list):
1358 # XXX We could do better here for very long lists
1359 # XXX Should really reject non-string non-buffers
1360 self._wbuf.extend(filter(None, map(str, list)))
1361 if (self._wbufsize <= 1 or
1362 self._get_wbuf_len() >= self._wbufsize):
1363 self.flush()
1364
1365 def _get_wbuf_len(self):
1366 buf_len = 0
1367 for x in self._wbuf:
1368 buf_len += len(x)
1369 return buf_len
1370
1371 def read(self, size=-1):
1372 data = self._rbuf
1373 if size < 0:
1374 # Read until EOF
1375 buffers = []
1376 if data:
1377 buffers.append(data)
1378 self._rbuf = ""
1379 if self._rbufsize <= 1:
1380 recv_size = self.default_bufsize
1381 else:
1382 recv_size = self._rbufsize
1383 while True:
1384 data = self._sock.recv(recv_size)
1385 if not data:
1386 break
1387 buffers.append(data)
1388 return "".join(buffers)
1389 else:
1390 # Read until size bytes or EOF seen, whichever comes first
1391 buf_len = len(data)
1392 if buf_len >= size:
1393 self._rbuf = data[size:]
1394 return data[:size]
1395 buffers = []
1396 if data:
1397 buffers.append(data)
1398 self._rbuf = ""
1399 while True:
1400 left = size - buf_len
1401 recv_size = max(self._rbufsize, left)
1402 data = self._sock.recv(recv_size)
1403 if not data:
1404 break
1405 buffers.append(data)
1406 n = len(data)
1407 if n >= left:
1408 self._rbuf = data[left:]
1409 buffers[-1] = data[:left]
1410 break
1411 buf_len += n
1412 return "".join(buffers)
1413
1414 def readline(self, size=-1):
1415 data = self._rbuf
1416 if size < 0:
1417 # Read until \n or EOF, whichever comes first
1418 if self._rbufsize <= 1:
1419 # Speed up unbuffered case
1420 assert data == ""
1421 buffers = []
1422 recv = self._sock.recv
1423 while data != "\n":
1424 data = recv(1)
1425 if not data:
1426 break
1427 buffers.append(data)
1428 return "".join(buffers)
1429 nl = data.find('\n')
1430 if nl >= 0:
1431 nl += 1
1432 self._rbuf = data[nl:]
1433 return data[:nl]
1434 buffers = []
1435 if data:
1436 buffers.append(data)
1437 self._rbuf = ""
1438 while True:
1439 data = self._sock.recv(self._rbufsize)
1440 if not data:
1441 break
1442 buffers.append(data)
1443 nl = data.find('\n')
1444 if nl >= 0:
1445 nl += 1
1446 self._rbuf = data[nl:]
1447 buffers[-1] = data[:nl]
1448 break
1449 return "".join(buffers)
1450 else:
1451 # Read until size bytes or \n or EOF seen, whichever comes first
1452 nl = data.find('\n', 0, size)
1453 if nl >= 0:
1454 nl += 1
1455 self._rbuf = data[nl:]
1456 return data[:nl]
1457 buf_len = len(data)
1458 if buf_len >= size:
1459 self._rbuf = data[size:]
1460 return data[:size]
1461 buffers = []
1462 if data:
1463 buffers.append(data)
1464 self._rbuf = ""
1465 while True:
1466 data = self._sock.recv(self._rbufsize)
1467 if not data:
1468 break
1469 buffers.append(data)
1470 left = size - buf_len
1471 nl = data.find('\n', 0, left)
1472 if nl >= 0:
1473 nl += 1
1474 self._rbuf = data[nl:]
1475 buffers[-1] = data[:nl]
1476 break
1477 n = len(data)
1478 if n >= left:
1479 self._rbuf = data[left:]
1480 buffers[-1] = data[:left]
1481 break
1482 buf_len += n
1483 return "".join(buffers)
1484
1485 def readlines(self, sizehint=0):
1486 total = 0
1487 list = []
1488 while True:
1489 line = self.readline()
1490 if not line:
1491 break
1492 list.append(line)
1493 total += len(line)
1494 if sizehint and total >= sizehint:
1495 break
1496 return list
1497
1498 # Iterator protocols
1499
1500 def __iter__(self):
1501 return self
1502
1503 def next(self):
1504 line = self.readline()
1505 if not line:
1506 raise StopIteration
1507 return line
1508
1509
1510# Define the SSL support
1511
1512class ssl:
1513
1514 def __init__(self, plain_sock, keyfile=None, certfile=None):
1515 try:
1516 self.ssl_sock = self._make_ssl_socket(plain_sock)
1517 self._in_buf = java.io.BufferedInputStream(self.ssl_sock.getInputStream())
1518 self._out_buf = java.io.BufferedOutputStream(self.ssl_sock.getOutputStream())
1519 except java.lang.Exception, jlx:
1520 raise _map_exception(jlx)
1521
1522 def _make_ssl_socket(self, plain_socket, auto_close=0):
1523 java_net_socket = plain_socket._get_jsocket()
1524 assert isinstance(java_net_socket, java.net.Socket)
1525 host = java_net_socket.getInetAddress().getHostAddress()
1526 port = java_net_socket.getPort()
1527 factory = javax.net.ssl.SSLSocketFactory.getDefault();
1528 ssl_socket = factory.createSocket(java_net_socket, host, port, auto_close)
1529 ssl_socket.setEnabledCipherSuites(ssl_socket.getSupportedCipherSuites())
1530 ssl_socket.startHandshake()
1531 return ssl_socket
1532
1533 def read(self, n=4096):
1534 try:
1535 data = jarray.zeros(n, 'b')
1536 m = self._in_buf.read(data, 0, n)
1537 if m <= 0:
1538 return ""
1539 if m < n:
1540 data = data[:m]
1541 return data.tostring()
1542 except java.lang.Exception, jlx:
1543 raise _map_exception(jlx)
1544
1545 def write(self, s):
1546 try:
1547 self._out_buf.write(s)
1548 self._out_buf.flush()
1549 return len(s)
1550 except java.lang.Exception, jlx:
1551 raise _map_exception(jlx)
1552
1553 def _get_server_cert(self):
1554 try:
1555 return self.ssl_sock.getSession().getPeerCertificates()[0]
1556 except java.lang.Exception, jlx:
1557 raise _map_exception(jlx)
1558
1559 def server(self):
1560 cert = self._get_server_cert()
1561 return cert.getSubjectDN().toString()
1562
1563 def issuer(self):
1564 cert = self._get_server_cert()
1565 return cert.getIssuerDN().toString()
1566
1567_realssl = ssl
1568def ssl(sock, keyfile=None, certfile=None):
1569 if hasattr(sock, "_sock"):
1570 sock = sock._sock
1571 return _realssl(sock, keyfile, certfile)
1572
1573def test():
1574 s = socket(AF_INET, SOCK_STREAM)
1575 s.connect(("", 80))
1576 s.send("GET / HTTP/1.0\r\n\r\n")
1577 while 1:
1578 data = s.recv(2000)
1579 print data
1580 if not data:
1581 break
1582
1583if __name__ == '__main__':
1584 test()