[Jython-checkins] jython (merge 2.5 -> default): Merge w/2.5: Fix for http://bugs.jython.org/issue1844 (bad host returned by

alan.kennedy jython-checkins at python.org
Sat Mar 17 23:03:30 CET 2012


http://hg.python.org/jython/rev/76287b6c2863
changeset:   6409:76287b6c2863
parent:      6406:5add107a20c8
parent:      6408:a33beb889a79
user:        Alan Kennedy <alan at xhaus.com>
date:        Sat Mar 17 22:02:42 2012 +0000
summary:
  Merge w/2.5: Fix for http://bugs.jython.org/issue1844 (bad host returned by getsockname)

files:
  Lib/socket.py           |  58 ++++++++++++++-------------
  Lib/test/test_socket.py |  62 +++++++++++++++++++++-------
  NEWS                    |   4 +
  3 files changed, 81 insertions(+), 43 deletions(-)


diff --git a/Lib/socket.py b/Lib/socket.py
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -230,6 +230,8 @@
 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
@@ -744,39 +746,36 @@
 
     __repr__ = __str__
 
-def _get_jsockaddr(address_object, for_udp=False):
-    if address_object is None:
-        return java.net.InetSocketAddress(0) # Let the system pick an ephemeral port
+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 \
-            len(address_object) not in [2,4] 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) 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, port = address_object[0].strip(), address_object[1]
-    if for_udp:
-        if hostname == "":
-            hostname = INADDR_ANY
-        elif hostname == "<broadcast>":
-            hostname = INADDR_BROADCAST
-    else:
-        if hostname == "":
-            hostname = None
-    if hostname is None:
-        return java.net.InetSocketAddress(port)
+    if family == AF_INET and sock_type == SOCK_DGRAM and hostname == "<broadcast>":
+        hostname = INADDR_BROADCAST
+    if hostname == "":
+        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)
-    if len(address_object) == 4:
-        # There is no way to get a Inet6Address: Inet6Address.getByName() simply calls
-        # InetAddress.getByName,() which also returns Inet4Address objects
-        # If users want to use IPv6 address, scoped or not, 
-        # they should use getaddrinfo(family=AF_INET6)
-        pass
-    return java.net.InetSocketAddress(java.net.InetAddress.getByName(hostname), port)
+    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
@@ -1072,7 +1071,7 @@
         assert not self.sock_impl
         assert not self.local_addr
         # Do the address format check
-        _get_jsockaddr(addr)
+        _get_jsockaddr(addr, self.family, self.type, self.proto, 0)
         self.local_addr = addr
 
     def listen(self, backlog):
@@ -1080,7 +1079,8 @@
         try:
             assert not self.sock_impl
             self.server = 1
-            self.sock_impl = _server_socket_impl(_get_jsockaddr(self.local_addr), backlog, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
+            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)
@@ -1107,9 +1107,10 @@
             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.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
+                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.sock_impl.connect(_get_jsockaddr(addr, self.family, self.type, self.proto, 0))
         except java.lang.Exception, jlx:
             raise _map_exception(jlx)
 
@@ -1218,7 +1219,8 @@
     def bind(self, addr):
         try:
             assert not self.sock_impl
-            self.sock_impl = _datagram_socket_impl(_get_jsockaddr(addr, True), self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ])
+            self.sock_impl = _datagram_socket_impl(_get_jsockaddr(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)
@@ -1229,7 +1231,7 @@
             if not self.sock_impl:
                 self.sock_impl = _datagram_socket_impl()
                 self._config()
-                self.sock_impl.connect(_get_jsockaddr(addr))
+                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)
@@ -1252,7 +1254,7 @@
                 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, True), flags)
+            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)
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1884,7 +1884,7 @@
 
     def testIPV4AddressesFromGetAddrInfo(self):
         local_addr = socket.getaddrinfo("localhost", 80, socket.AF_INET, socket.SOCK_STREAM, 0, 0)[0][4]
-        sockaddr = socket._get_jsockaddr(local_addr)
+        sockaddr = socket._get_jsockaddr(local_addr, socket.AF_INET, None, 0, 0)
         self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr)))
         self.failUnlessEqual(sockaddr.address.hostAddress, "127.0.0.1")
         self.failUnlessEqual(sockaddr.port, 80)
@@ -1895,27 +1895,28 @@
             # older FreeBSDs may have spotty IPV6 Java support
             return
         local_addr = addrinfo[0][4]
-        sockaddr = socket._get_jsockaddr(local_addr)
+        sockaddr = socket._get_jsockaddr(local_addr, socket.AF_INET6, None, 0, 0)
         self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr)))
         self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"])
         self.failUnlessEqual(sockaddr.port, 80)
 
     def testAddressesFrom2Tuple(self):
-        for addr_tuple in [
-            ("localhost", 80),
+        for family, addr_tuple, jaddress_type, expected in [
+            (socket.AF_INET,  ("localhost", 80), java.net.Inet4Address, ["127.0.0.1"]),
+            (socket.AF_INET6, ("localhost", 80), java.net.Inet6Address, ["::1", "0:0:0:0:0:0:0:1"]),
             ]:
-            sockaddr = socket._get_jsockaddr(addr_tuple)
+            sockaddr = socket._get_jsockaddr(addr_tuple, family, None, 0, 0)
             self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr)))
-            self.failUnless(sockaddr.address.hostAddress in ["127.0.0.1", "::1", "0:0:0:0:0:0:0:1"])
+            self.failUnless(isinstance(sockaddr.address, jaddress_type), "_get_jsockaddr returned wrong address type: '%s'(family=%d)" % (str(type(sockaddr.address)), family))
+            self.failUnless(sockaddr.address.hostAddress in expected)
             self.failUnlessEqual(sockaddr.port, 80)
 
     def testAddressesFrom4Tuple(self):
-        # This test disabled: cannot construct IPV6 addresses from 4-tuple
-        return
         for addr_tuple in [
+            ("localhost", 80),
             ("localhost", 80, 0, 0),
             ]:
-            sockaddr = socket._get_jsockaddr(addr_tuple)
+            sockaddr = socket._get_jsockaddr(addr_tuple, socket.AF_INET6, None, 0, 0)
             self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr)))
             self.failUnless(isinstance(sockaddr.address, java.net.Inet6Address), "_get_jsockaddr returned wrong address type: '%s'" % str(type(sockaddr.address)))
             self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"])
@@ -1923,13 +1924,44 @@
             self.failUnlessEqual(sockaddr.port, 80)
 
     def testSpecialHostnames(self):
-        for addr_tuple, for_udp, expected_hostname in [
-            ( ("", 80),            False, socket.INADDR_ANY),
-            ( ("", 80),            True,  socket.INADDR_ANY),
-            ( ("<broadcast>", 80), True,  socket.INADDR_BROADCAST),
+        for family, sock_type, flags, addr_tuple, expected in [
+            ( socket.AF_INET,  None,              0,                 ("", 80),            ["localhost"]),
+            ( socket.AF_INET,  None,              socket.AI_PASSIVE, ("", 80),            [socket.INADDR_ANY]),
+            ( socket.AF_INET6, None,              0,                 ("", 80),            ["localhost"]),
+            ( socket.AF_INET6, None,              socket.AI_PASSIVE, ("", 80),            [socket.IN6ADDR_ANY_INIT, "0:0:0:0:0:0:0:0"]),
+            ( socket.AF_INET,  socket.SOCK_DGRAM, 0,                 ("<broadcast>", 80), [socket.INADDR_BROADCAST]),
             ]:
-            sockaddr = socket._get_jsockaddr(addr_tuple, for_udp)
-            self.failUnlessEqual(sockaddr.hostName, expected_hostname, "_get_jsockaddr returned wrong hostname '%s' for special hostname '%s'" % (sockaddr.hostName, expected_hostname))
+            sockaddr = socket._get_jsockaddr(addr_tuple, family, sock_type, 0, flags)
+            self.failUnless(sockaddr.hostName in expected, "_get_jsockaddr returned wrong hostname '%s' for special hostname '%s'(family=%d)" % (sockaddr.hostName, addr_tuple[0], family))
+
+    def testNoneTo_get_jsockaddr(self):
+        for family, flags, expected in [
+            ( socket.AF_INET,  0,                 ["localhost"]),
+            ( socket.AF_INET,  socket.AI_PASSIVE, [socket.INADDR_ANY]),
+            ( socket.AF_INET6, 0,                 ["localhost"]),
+            ( socket.AF_INET6, socket.AI_PASSIVE, [socket.IN6ADDR_ANY_INIT, "0:0:0:0:0:0:0:0"]),
+            ]:
+            sockaddr = socket._get_jsockaddr(None, family, None, 0, flags)
+            self.failUnless(sockaddr.hostName in expected, "_get_jsockaddr returned wrong hostname '%s' for sock tuple == None (family=%d)" % (sockaddr.hostName, family))
+
+    def testBadAddressTuples(self):
+        for family, address_tuple in [
+            ( socket.AF_INET,  ()                      ),
+            ( socket.AF_INET,  ("")                    ),
+            ( socket.AF_INET,  (80)                    ),
+            ( socket.AF_INET,  ("localhost", 80, 0)    ),
+            ( socket.AF_INET,  ("localhost", 80, 0, 0) ),
+            ( socket.AF_INET6,  ()                      ),
+            ( socket.AF_INET6,  ("")                    ),
+            ( socket.AF_INET6,  (80)                    ),
+            ( socket.AF_INET6,  ("localhost", 80, 0)    ),
+            ]:
+            try:
+                sockaddr = socket._get_jsockaddr(address_tuple, family, None, 0, 0)
+            except TypeError:
+                pass
+            else:
+                self.fail("Bad tuple %s (family=%d) should have raised TypeError" % (str(address_tuple), family))
 
 class TestExceptions(unittest.TestCase):
 
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,9 @@
 Jython NEWS
 
+Jython 2.5.3b2
+  Bugs Fixed
+    - [ 1844 ] bad host returned by getsockname
+
 Jython 2.5.3b1
   Bugs Fixed
     - [ 1835 ] s/occured/occurred/ :)

-- 
Repository URL: http://hg.python.org/jython


More information about the Jython-checkins mailing list