diff --git a/src/core/IronPython.Modules/_socket.cs b/src/core/IronPython.Modules/_socket.cs index a28e30843..9f5cde8a3 100644 --- a/src/core/IronPython.Modules/_socket.cs +++ b/src/core/IronPython.Modules/_socket.cs @@ -1151,7 +1151,8 @@ public static object getnameinfo(CodeContext/*!*/ context, [NotNone] PythonTuple string host = Converter.ConvertToString(socketAddr[0]); if (host == null) throw PythonOps.TypeError("argument 1 must be string"); - int port = 0; + + int port; try { port = (int)socketAddr[1]!; } catch (InvalidCastException) { @@ -1167,60 +1168,45 @@ public static object getnameinfo(CodeContext/*!*/ context, [NotNone] PythonTuple } } - string resultHost; - string resultPort; - // Host - IList addrs; - try { - addrs = HostToAddresses(context, host, AddressFamily.InterNetwork); - } catch (IndexOutOfRangeException) { + if (!IPAddress.TryParse(host, out IPAddress? addr)) { throw MakeGaiException(context, EAI_NODATA); } - if (addrs.Count > 1) { - // ignore non-IPV4 addresses - List newAddrs = new List(addrs.Count); - foreach (IPAddress addr in addrs) { - if (addr.AddressFamily == AddressFamily.InterNetwork) { - newAddrs.Add(addr); + string resultHost; + if ((flags & NI_NUMERICHOST) != 0) { + resultHost = addr.ToString(); + } else { + string hostName; + if (addr.Equals(IPAddress.Any) || addr.Equals(IPAddress.IPv6Any)) { + hostName = Dns.GetHostName(); + } else { + try { + hostName = Dns.GetHostEntry(addr).HostName; + } catch (SocketException ex) { + throw MakeGaiException(context, ex); } } - if (newAddrs.Count > 1) { - throw PythonExceptions.CreateThrowable(error, "sockaddr resolved to multiple addresses"); - } - addrs = newAddrs; - } - if (addrs.Count < 1) { - throw MakeGaiException(context, EAI_NODATA); - } - - IPHostEntry hostEntry; - try { - hostEntry = Dns.GetHostEntry(addrs[0]); - } catch (SocketException ex) { - throw MakeGaiException(context, ex); - } - if ((flags & (int)NI_NUMERICHOST) != 0) { - resultHost = addrs[0].ToString(); - } else if ((flags & (int)NI_NOFQDN) != 0) { - resultHost = RemoveLocalDomain(hostEntry.HostName); - } else { - resultHost = hostEntry.HostName; + if ((flags & NI_NOFQDN) != 0) { + resultHost = RemoveLocalDomain(hostName); + } else { + resultHost = hostName; + } } // Port - if ((flags & (int)NI_NUMERICSERV) == 0) { + string resultPort; + if ((flags & NI_NUMERICSERV) == 0) { //call the servbyport to translate port if not just use the port.ToString as the result try { resultPort = getservbyport(context, port); } catch { resultPort = port.ToString(); } - flags = flags | (int)NI_NUMERICSERV; - } else + } else { resultPort = port.ToString(); + } return PythonTuple.MakeTuple(resultHost, resultPort); } @@ -2032,7 +2018,7 @@ private static IPAddress[] HostToAddresses(CodeContext/*!*/ context, string host if (addrs.Count > 0) return addrs.ToArray(); } throw MakeGaiException(context, EAI_NODATA); - } catch (SocketException ex) { + } catch (SocketException ex) { throw MakeGaiException(context, ex); } } diff --git a/src/core/IronPython/Runtime/Operations/StringOps.cs b/src/core/IronPython/Runtime/Operations/StringOps.cs index fce9ba646..f17a210d3 100644 --- a/src/core/IronPython/Runtime/Operations/StringOps.cs +++ b/src/core/IronPython/Runtime/Operations/StringOps.cs @@ -623,6 +623,7 @@ public static bool isalpha([NotNone] this string self) { return true; } + // new in Python 3.7 public static bool isascii([NotNone] this string self) { foreach (char c in self) { if (c > 0x7f) return false; diff --git a/tests/suite/modules/network_related/test__socket.py b/tests/suite/modules/network_related/test__socket.py index 594eabb58..f3ff0124f 100644 --- a/tests/suite/modules/network_related/test__socket.py +++ b/tests/suite/modules/network_related/test__socket.py @@ -352,12 +352,29 @@ def test_getnameinfo(self): host, service = _socket.getnameinfo( ("127.0.0.1", 80), 0) self.assertEqual(service, "http") #IP gives a TypeError - #self.assertRaises(SystemError, _socket.getnameinfo, ("127.0.0.1"), 8) - #self.assertRaises(SystemError, _socket.getnameinfo, (321), 8) + self.assertRaises(TypeError, _socket.getnameinfo, ("127.0.0.1"), 8) + self.assertRaises(TypeError, _socket.getnameinfo, (321), 8) self.assertRaises(TypeError, _socket.getnameinfo, ("127.0.0.1"), '0') self.assertRaises(TypeError, _socket.getnameinfo, ("127.0.0.1", 80, 0, 0, 0), 8) self.assertRaises(_socket.gaierror, _socket.getnameinfo, ('no such host will ever exist', 80), 8) + # try some IPv6 cases + ports = { + 80: "http", + 443: "https", + } + + addresses = ["::1", "::", "::0"] + address_num = {"::0": "::"} + + for address in addresses: + for port, port_name in ports.items(): + res = _socket.getnameinfo((address, port), 0) + # don't check the host name, unreliable across platforms + self.assertEqual(res[1], port_name) + res = _socket.getnameinfo((address, port), _socket.NI_NUMERICHOST | _socket.NI_NUMERICSERV) + self.assertEqual(res, (address_num.get(address, address), str(port))) + def test_gethostbyaddr(self): '''Tests _socket.gethostbyaddr''' _socket.gethostbyaddr("localhost") diff --git a/tests/suite/test_socket_stdlib.py b/tests/suite/test_socket_stdlib.py index fbfe9ff4f..247429f58 100644 --- a/tests/suite/test_socket_stdlib.py +++ b/tests/suite/test_socket_stdlib.py @@ -41,10 +41,6 @@ def load_tests(loader, standard_tests, pattern): failing_tests += [ test.test_socket.NonBlockingTCPTests('testRecv'), # TODO: figure out ] - if not is_mono: - failing_tests += [ - test.test_socket.GeneralModuleTests('test_getnameinfo'), # https://github.com/IronLanguages/ironpython3/issues/1222 - ] if is_linux: failing_tests += [ test.test_socket.GeneralModuleTests('test_idna'), # TODO: figure out