1try:
2 from socket import inet_pton
3except ImportError:
4 from typing import TYPE_CHECKING
5
6 if TYPE_CHECKING: # pragma: no cover
7 pass
8 else:
9 # based on https://gist.github.com/nnemkin/4966028
10 # this code only applies on Windows Python 2.7
11 import ctypes
12 import socket
13
14 class SockAddr(ctypes.Structure):
15 _fields_ = [
16 ("sa_family", ctypes.c_short),
17 ("__pad1", ctypes.c_ushort),
18 ("ipv4_addr", ctypes.c_byte * 4),
19 ("ipv6_addr", ctypes.c_byte * 16),
20 ("__pad2", ctypes.c_ulong),
21 ]
22
23 WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA
24 WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA
25
26 def inet_pton(address_family, ip_string):
27 # type: (int, str) -> bytes
28 addr = SockAddr()
29 ip_string_bytes = ip_string.encode("ascii")
30 addr.sa_family = address_family
31 addr_size = ctypes.c_int(ctypes.sizeof(addr))
32
33 try:
34 attribute, size = {
35 socket.AF_INET: ("ipv4_addr", 4),
36 socket.AF_INET6: ("ipv6_addr", 16),
37 }[address_family]
38 except KeyError:
39 raise socket.error("unknown address family")
40
41 if (
42 WSAStringToAddressA(
43 ip_string_bytes,
44 address_family,
45 None,
46 ctypes.byref(addr),
47 ctypes.byref(addr_size),
48 )
49 != 0
50 ):
51 raise socket.error(ctypes.FormatError())
52
53 return ctypes.string_at(getattr(addr, attribute), size)