Согласно справочной странице linux для getaddrinfo структура addrinfo
, в которой хранятся результаты getaddrinfo
, определяется как
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
и согласно FreeBSDСтраница man для getaddrinfo (или одна из страниц руководства Apple для getaddrinfo , которая похожа), ее addrinfo
выглядит одинаково, при условии, что все типы совпадают.
struct addrinfo {
int ai_flags; /* input flags */
int ai_family; /* address family for socket */
int ai_socktype; /* socket type */
int ai_protocol; /* protocol for socket */
socklen_t ai_addrlen; /* length of socket-address */
struct sockaddr *ai_addr; /* socket-address for socket */
char *ai_canonname; /* canonical name for service location */
struct addrinfo *ai_next; /* pointer to next in list */
};
Однако глядя на источник FreeBSD (или один из проектов Apple с открытым исходным кодом , который похож), мы видим немного другое определение:
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* AF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
socklen_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
Очень легко пропустить, но ai_canonname
и ai_addr
- это обратный путь к тому, как они задокументированы .Это означает, что определение типа Python для Mac (/ аналогичное) должно быть
class c_addrinfo(Structure):
pass
c_addrinfo._fields_ = [
('ai_flags', c_int),
('ai_family', c_int),
('ai_socktype', c_int),
('ai_protocol', c_int),
('ai_addrlen', c_size_t),
('ai_canonname', c_char_p),
('ai_addr', c_void_p),
('ai_next', POINTER(c_addrinfo)),
]
или такое, которое работает как на Mac, так и на Linux (и без комментариев на других платформах)
import platform
c_addrinfo._fields_ = [
('ai_flags', c_int),
('ai_family', c_int),
('ai_socktype', c_int),
('ai_protocol', c_int),
('ai_addrlen', c_size_t),
] + ([
('ai_canonname', c_char_p),
('ai_addr', c_void_p),
] if platform.system() == 'Darwin' else [
('ai_addr', c_void_p),
('ai_canonname', c_char_p),
]) + [
('ai_next', POINTER(c_addrinfo)),
]
И в этих версиях на Mac указатель ai_addr
больше не равен нулю.Вы также можете увидеть раннюю / экспериментальную версию, которая анализирует сами адреса, которая работает как в Mac, так и в Linux .
Редактировать: похоже, о проблеме документации уже сообщалосьFreeBSD