Patch #401196: IPv6 extensions to the socket module.

New functions getnameinfo, getaddrinfo. New exceptions socket.gaierror,
socket.herror. Various new constants, in particular AF_INET6 and error
codes and parameters for getaddrinfo.
AF_INET6 support in setipaddr, makesockaddr, getsockaddr, getsockaddrlen,
gethost_common, PySocket_gethostbyaddr.
This commit is contained in:
Martin v. Löwis 2001-07-21 18:05:31 +00:00
parent b7cea6324a
commit 2d8d4276c6
1 changed files with 547 additions and 104 deletions

View File

@ -7,7 +7,7 @@ This module provides an interface to Berkeley socket IPC.
Limitations: Limitations:
- only AF_INET and AF_UNIX address families are supported in a - only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
portable manner, though AF_PACKET is supported under Linux. portable manner, though AF_PACKET is supported under Linux.
- no read/write operations (use send/recv or makefile instead) - no read/write operations (use send/recv or makefile instead)
- additional restrictions apply on Windows - additional restrictions apply on Windows
@ -15,6 +15,10 @@ Limitations:
Module interface: Module interface:
- socket.error: exception raised for socket specific errors - socket.error: exception raised for socket specific errors
- socket.gaierror: exception raised for getaddrinfo/getnameinfo errors,
a subclass of socket.error
- socket.herror: exception raised for gethostby* errors,
a subclass of socket.error
- socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd') - socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd')
- socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...]) - socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...])
- socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com') - socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com')
@ -25,6 +29,9 @@ Module interface:
- socket.ntohl(32 bit value) --> new int object - socket.ntohl(32 bit value) --> new int object
- socket.htons(16 bit value) --> new int object - socket.htons(16 bit value) --> new int object
- socket.htonl(32 bit value) --> new int object - socket.htonl(32 bit value) --> new int object
- socket.getaddrinfo(host, port [, family, socktype, proto, flags])
--> List of (family, socktype, proto, canonname, sockaddr)
- socket.getnameinfo(sockaddr, flags) --> (host, port)
- socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h> - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h>
- socket.inet_aton(IP address) -> 32-bit packed IP representation - socket.inet_aton(IP address) -> 32-bit packed IP representation
- socket.inet_ntoa(packed IP) -> IP address string - socket.inet_ntoa(packed IP) -> IP address string
@ -239,6 +246,10 @@ typedef int SOCKET_T;
# define SIZEOF_SOCKET_T SIZEOF_INT # define SIZEOF_SOCKET_T SIZEOF_INT
#endif #endif
#ifdef MS_WIN32
# define EAFNOSUPPORT WSAEAFNOSUPPORT
# define snprintf _snprintf
#endif
#if defined(PYOS_OS2) #if defined(PYOS_OS2)
#define SOCKETCLOSE soclose #define SOCKETCLOSE soclose
@ -253,6 +264,8 @@ typedef int SOCKET_T;
by this module (but not argument type or memory errors, etc.). */ by this module (but not argument type or memory errors, etc.). */
static PyObject *PySocket_Error; static PyObject *PySocket_Error;
static PyObject *PyH_Error;
static PyObject *PyGAI_Error;
#ifdef USE_SSL #ifdef USE_SSL
static PyObject *SSLErrorObject; static PyObject *SSLErrorObject;
@ -393,6 +406,43 @@ PySocket_Err(void)
} }
static PyObject *
PyH_Err(int h_error)
{
PyObject *v;
#ifdef HAVE_HSTRERROR
v = Py_BuildValue("(is)", h_error, (char *)hstrerror(h_error));
#else
v = Py_BuildValue("(is)", h_error, "host not found");
#endif
if (v != NULL) {
PyErr_SetObject(PyGAI_Error, v);
Py_DECREF(v);
}
return NULL;
}
static PyObject *
PyGAI_Err(int error)
{
PyObject *v;
if (error == EAI_SYSTEM)
return PySocket_Err();
v = Py_BuildValue("(is)", error, gai_strerror(error));
if (v != NULL) {
PyErr_SetObject(PyGAI_Error, v);
Py_DECREF(v);
}
return NULL;
}
/* The object holding a socket. It holds some extra information, /* The object holding a socket. It holds some extra information,
like the address family, which is used to decode socket address like the address family, which is used to decode socket address
arguments properly. */ arguments properly. */
@ -408,6 +458,10 @@ typedef struct {
#ifdef AF_UNIX #ifdef AF_UNIX
struct sockaddr_un un; struct sockaddr_un un;
#endif #endif
#ifdef INET6
struct sockaddr_in6 in6;
struct sockaddr_storage storage;
#endif
#if defined(linux) && defined(AF_PACKET) #if defined(linux) && defined(AF_PACKET)
struct sockaddr_ll ll; struct sockaddr_ll ll;
#endif #endif
@ -484,85 +538,87 @@ PyThread_type_lock gethostbyname_lock;
/* Convert a string specifying a host name or one of a few symbolic /* Convert a string specifying a host name or one of a few symbolic
names to a numeric IP address. This usually calls gethostbyname() names to a numeric IP address. This usually calls gethostbyname()
to do the work; the names "" and "<broadcast>" are special. to do the work; the names "" and "<broadcast>" are special.
Return the length (should always be 4 bytes), or negative if Return the length (IPv4 should be 4 bytes), or negative if
an error occurred; then an exception is raised. */ an error occurred; then an exception is raised. */
static int static int
setipaddr(char* name, struct sockaddr_in * addr_ret) setipaddr(char* name, struct sockaddr * addr_ret, int af)
{ {
struct hostent *hp; struct addrinfo hints, *res;
int d1, d2, d3, d4; int error;
int h_length;
char ch;
#ifdef HAVE_GETHOSTBYNAME_R
struct hostent hp_allocated;
#ifdef HAVE_GETHOSTBYNAME_R_3_ARG
struct hostent_data data;
#else
char buf[1001];
int buf_len = (sizeof buf) - 1;
int errnop;
#endif
#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG)
int result;
#endif
#endif /* HAVE_GETHOSTBYNAME_R */
memset((void *) addr_ret, '\0', sizeof(*addr_ret)); memset((void *) addr_ret, '\0', sizeof(*addr_ret));
if (name[0] == '\0') { if (name[0] == '\0') {
addr_ret->sin_addr.s_addr = INADDR_ANY; int siz;
return 4; memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_PASSIVE;
error = getaddrinfo(NULL, "0", &hints, &res);
if (error) {
PyGAI_Err(error);
return -1;
}
switch (res->ai_family) {
case AF_INET:
siz = 4;
break;
#ifdef INET6
case AF_INET6:
siz = 16;
break;
#endif
default:
freeaddrinfo(res);
PyErr_SetString(PySocket_Error,
"unsupported address family");
return -1;
}
if (res->ai_next) {
PyErr_SetString(PySocket_Error,
"wildcard resolved to multiple address");
return -1;
}
memcpy(addr_ret, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
return siz;
} }
if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) { if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
addr_ret->sin_addr.s_addr = INADDR_BROADCAST; struct sockaddr_in *sin;
return 4; if (af != PF_INET && af != PF_UNSPEC) {
PyErr_SetString(PySocket_Error,
"address family mismatched");
return -1;
}
sin = (struct sockaddr_in *)addr_ret;
memset((void *) sin, '\0', sizeof(*sin));
sin->sin_family = AF_INET;
#ifdef HAVE_SOCKADDR_SA_LEN
sin->sin_len = sizeof(*sin);
#endif
sin->sin_addr.s_addr = INADDR_BROADCAST;
return sizeof(sin->sin_addr);
} }
if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && memset(&hints, 0, sizeof(hints));
0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && hints.ai_family = af;
0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { error = getaddrinfo(name, NULL, &hints, &res);
addr_ret->sin_addr.s_addr = htonl( if (error) {
((long) d1 << 24) | ((long) d2 << 16) | PyGAI_Err(error);
((long) d3 << 8) | ((long) d4 << 0));
return 4;
}
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_GETHOSTBYNAME_R
#if defined(HAVE_GETHOSTBYNAME_R_6_ARG)
result = gethostbyname_r(name, &hp_allocated, buf, buf_len, &hp, &errnop);
#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
hp = gethostbyname_r(name, &hp_allocated, buf, buf_len, &errnop);
#else /* HAVE_GETHOSTBYNAME_R_3_ARG */
memset((void *) &data, '\0', sizeof(data));
result = gethostbyname_r(name, &hp_allocated, &data);
hp = (result != 0) ? NULL : &hp_allocated;
#endif
#else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(gethostbyname_lock, 1);
#endif
hp = gethostbyname(name);
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
if (hp == NULL) {
#ifdef HAVE_HSTRERROR
/* Let's get real error message to return */
extern int h_errno;
PyErr_SetString(PySocket_Error, (char *)hstrerror(h_errno));
#else
PyErr_SetString(PySocket_Error, "host not found");
#endif
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(gethostbyname_lock);
#endif
return -1; return -1;
} }
memcpy((char *) &addr_ret->sin_addr, hp->h_addr, hp->h_length); memcpy((char *) addr_ret, res->ai_addr, res->ai_addrlen);
h_length = hp->h_length; freeaddrinfo(res);
#ifdef USE_GETHOSTBYNAME_LOCK switch (addr_ret->sa_family) {
PyThread_release_lock(gethostbyname_lock); case AF_INET:
return 4;
#ifdef INET6
case AF_INET6:
return 16;
#endif #endif
return h_length; default:
PyErr_SetString(PySocket_Error, "unknown address family");
return -1;
}
} }
@ -571,13 +627,17 @@ setipaddr(char* name, struct sockaddr_in * addr_ret)
size numbers). */ size numbers). */
static PyObject * static PyObject *
makeipaddr(struct sockaddr_in *addr) makeipaddr(struct sockaddr *addr, int addrlen)
{ {
unsigned long x = ntohl(addr->sin_addr.s_addr); char buf[NI_MAXHOST];
char buf[100]; int error;
sprintf(buf, "%d.%d.%d.%d",
(int) (x>>24) & 0xff, (int) (x>>16) & 0xff, error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
(int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff); NI_NUMERICHOST);
if (error) {
PyGAI_Err(error);
return NULL;
}
return PyString_FromString(buf); return PyString_FromString(buf);
} }
@ -606,10 +666,11 @@ makesockaddr(int sockfd, struct sockaddr *addr, int addrlen)
case AF_INET: case AF_INET:
{ {
struct sockaddr_in *a = (struct sockaddr_in *) addr; struct sockaddr_in *a;
PyObject *addrobj = makeipaddr(a); PyObject *addrobj = makeipaddr(addr, sizeof(*a));
PyObject *ret = NULL; PyObject *ret = NULL;
if (addrobj) { if (addrobj) {
a = (struct sockaddr_in *)addr;
ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port)); ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
Py_DECREF(addrobj); Py_DECREF(addrobj);
} }
@ -622,6 +683,22 @@ makesockaddr(int sockfd, struct sockaddr *addr, int addrlen)
struct sockaddr_un *a = (struct sockaddr_un *) addr; struct sockaddr_un *a = (struct sockaddr_un *) addr;
return PyString_FromString(a->sun_path); return PyString_FromString(a->sun_path);
} }
#endif /* AF_UNIX */
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 *a;
PyObject *addrobj = makeipaddr(addr, sizeof(*a));
PyObject *ret = NULL;
if (addrobj) {
a = (struct sockaddr_in6 *)addr;
ret = Py_BuildValue("Oiii", addrobj, ntohs(a->sin6_port),
a->sin6_flowinfo, a->sin6_scope_id);
Py_DECREF(addrobj);
}
return ret;
}
#endif #endif
#if defined(linux) && defined(AF_PACKET) #if defined(linux) && defined(AF_PACKET)
@ -681,7 +758,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
"AF_UNIX path too long"); "AF_UNIX path too long");
return 0; return 0;
} }
addr->sun_family = AF_UNIX; addr->sun_family = s->sock_family;
memcpy(addr->sun_path, path, len); memcpy(addr->sun_path, path, len);
addr->sun_path[len] = 0; addr->sun_path[len] = 0;
*addr_ret = (struct sockaddr *) addr; *addr_ret = (struct sockaddr *) addr;
@ -704,7 +781,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} }
if (!PyArg_ParseTuple(args, "si:getsockaddrarg", &host, &port)) if (!PyArg_ParseTuple(args, "si:getsockaddrarg", &host, &port))
return 0; return 0;
if (setipaddr(host, addr) < 0) if (setipaddr(host, (struct sockaddr *)addr, AF_INET) < 0)
return 0; return 0;
addr->sin_family = AF_INET; addr->sin_family = AF_INET;
addr->sin_port = htons((short)port); addr->sin_port = htons((short)port);
@ -713,6 +790,30 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 1; return 1;
} }
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6* addr;
char *host;
int port, flowinfo, scope_id;
addr = (struct sockaddr_in6*)&(s->sock_addr).in6;
flowinfo = scope_id = 0;
if (!PyArg_ParseTuple(args, "si|ii", &host, &port, &flowinfo,
&scope_id)) {
return 0;
}
if (setipaddr(host, (struct sockaddr *)addr, AF_INET6) < 0)
return 0;
addr->sin6_family = s->sock_family;
addr->sin6_port = htons((short)port);
addr->sin6_flowinfo = flowinfo;
addr->sin6_scope_id = scope_id;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
#endif
#if defined(linux) && defined(AF_PACKET) #if defined(linux) && defined(AF_PACKET)
case AF_PACKET: case AF_PACKET:
{ {
@ -745,7 +846,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} }
#endif #endif
/* More cases here... */ /* More cases here... */
default: default:
@ -779,6 +879,14 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
return 1; return 1;
} }
#ifdef INET6
case AF_INET6:
{
*len_ret = sizeof (struct sockaddr_in6);
return 1;
}
#endif
#if defined(linux) && defined(AF_PACKET) #if defined(linux) && defined(AF_PACKET)
case AF_PACKET: case AF_PACKET:
{ {
@ -1652,12 +1760,14 @@ static PyObject *
PySocket_gethostbyname(PyObject *self, PyObject *args) PySocket_gethostbyname(PyObject *self, PyObject *args)
{ {
char *name; char *name;
struct sockaddr_in addrbuf; struct sockaddr_storage addrbuf;
if (!PyArg_ParseTuple(args, "s:gethostbyname", &name)) if (!PyArg_ParseTuple(args, "s:gethostbyname", &name))
return NULL; return NULL;
if (setipaddr(name, &addrbuf) < 0) if (setipaddr(name, (struct sockaddr *)&addrbuf, AF_INET) < 0)
return NULL; return NULL;
return makeipaddr(&addrbuf); return makeipaddr((struct sockaddr *)&addrbuf,
sizeof(struct sockaddr_in));
} }
static char gethostbyname_doc[] = static char gethostbyname_doc[] =
@ -1669,23 +1779,44 @@ Return the IP address (a string of the form '255.255.255.255') for a host.";
/* Convenience function common to gethostbyname_ex and gethostbyaddr */ /* Convenience function common to gethostbyname_ex and gethostbyaddr */
static PyObject * static PyObject *
gethost_common(struct hostent *h, struct sockaddr_in *addr) gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
{ {
char **pch; char **pch;
PyObject *rtn_tuple = (PyObject *)NULL; PyObject *rtn_tuple = (PyObject *)NULL;
PyObject *name_list = (PyObject *)NULL; PyObject *name_list = (PyObject *)NULL;
PyObject *addr_list = (PyObject *)NULL; PyObject *addr_list = (PyObject *)NULL;
PyObject *tmp; PyObject *tmp;
if (h == NULL) { if (h == NULL) {
#ifdef HAVE_HSTRERROR
/* Let's get real error message to return */ /* Let's get real error message to return */
#ifndef MS_WIN32
extern int h_errno; extern int h_errno;
PyErr_SetString(PySocket_Error, (char *)hstrerror(h_errno)); #endif
PyH_Err(h_errno);
return NULL;
}
if (h->h_addrtype != af) {
#ifdef HAVE_STRERROR
/* Let's get real error message to return */
PyErr_SetString(PySocket_Error, (char *)strerror(EAFNOSUPPORT));
#else #else
PyErr_SetString(PySocket_Error, "host not found"); PyErr_SetString(PySocket_Error,
"Address family not supported by protocol family");
#endif #endif
return NULL; return NULL;
} }
switch (af) {
case AF_INET:
if (alen < sizeof(struct sockaddr_in))
return NULL;
break;
#ifdef INET6
case AF_INET6:
if (alen < sizeof(struct sockaddr_in6))
return NULL;
break;
#endif
}
if ((name_list = PyList_New(0)) == NULL) if ((name_list = PyList_New(0)) == NULL)
goto err; goto err;
if ((addr_list = PyList_New(0)) == NULL) if ((addr_list = PyList_New(0)) == NULL)
@ -1702,8 +1833,43 @@ gethost_common(struct hostent *h, struct sockaddr_in *addr)
} }
for (pch = h->h_addr_list; *pch != NULL; pch++) { for (pch = h->h_addr_list; *pch != NULL; pch++) {
int status; int status;
memcpy((char *) &addr->sin_addr, *pch, h->h_length); switch (af) {
tmp = makeipaddr(addr); case AF_INET:
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = af;
#ifdef HAVE_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif
memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr));
tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin));
if (pch == h->h_addr_list && alen >= sizeof(sin))
memcpy((char *) addr, &sin, sizeof(sin));
break;
}
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = af;
#ifdef HAVE_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif
memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr));
tmp = makeipaddr((struct sockaddr *)&sin6,
sizeof(sin6));
if (pch == h->h_addr_list && alen >= sizeof(sin6))
memcpy((char *) addr, &sin6, sizeof(sin6));
break;
}
#endif
default: /* can't happen */
PyErr_SetString(PySocket_Error,
"unsupported address family");
return NULL;
}
if (tmp == NULL) if (tmp == NULL)
goto err; goto err;
status = PyList_Append(addr_list, tmp); status = PyList_Append(addr_list, tmp);
@ -1727,7 +1893,7 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
{ {
char *name; char *name;
struct hostent *h; struct hostent *h;
struct sockaddr_in addr; struct sockaddr_storage addr;
PyObject *ret; PyObject *ret;
#ifdef HAVE_GETHOSTBYNAME_R #ifdef HAVE_GETHOSTBYNAME_R
struct hostent hp_allocated; struct hostent hp_allocated;
@ -1742,9 +1908,10 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
int result; int result;
#endif #endif
#endif /* HAVE_GETHOSTBYNAME_R */ #endif /* HAVE_GETHOSTBYNAME_R */
if (!PyArg_ParseTuple(args, "s:gethostbyname_ex", &name)) if (!PyArg_ParseTuple(args, "s:gethostbyname_ex", &name))
return NULL; return NULL;
if (setipaddr(name, &addr) < 0) if (setipaddr(name, (struct sockaddr *)&addr, PF_INET) < 0)
return NULL; return NULL;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_GETHOSTBYNAME_R #ifdef HAVE_GETHOSTBYNAME_R
@ -1764,7 +1931,7 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
h = gethostbyname(name); h = gethostbyname(name);
#endif /* HAVE_GETHOSTBYNAME_R */ #endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
ret = gethost_common(h, &addr); ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), addr.ss_family);
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(gethostbyname_lock); PyThread_release_lock(gethostbyname_lock);
#endif #endif
@ -1784,7 +1951,12 @@ for a host. The host argument is a string giving a host name or IP number.";
static PyObject * static PyObject *
PySocket_gethostbyaddr(PyObject *self, PyObject *args) PySocket_gethostbyaddr(PyObject *self, PyObject *args)
{ {
#ifdef INET6
struct sockaddr_storage addr;
#else
struct sockaddr_in addr; struct sockaddr_in addr;
#endif
struct sockaddr *sa = (struct sockaddr *)&addr;
char *ip_num; char *ip_num;
struct hostent *h; struct hostent *h;
PyObject *ret; PyObject *ret;
@ -1801,40 +1973,55 @@ PySocket_gethostbyaddr(PyObject *self, PyObject *args)
int result; int result;
#endif #endif
#endif /* HAVE_GETHOSTBYNAME_R */ #endif /* HAVE_GETHOSTBYNAME_R */
char *ap;
int al;
int af;
if (!PyArg_ParseTuple(args, "s:gethostbyaddr", &ip_num)) if (!PyArg_ParseTuple(args, "s:gethostbyaddr", &ip_num))
return NULL; return NULL;
if (setipaddr(ip_num, &addr) < 0) af = PF_UNSPEC;
if (setipaddr(ip_num, sa, af) < 0)
return NULL; return NULL;
af = sa->sa_family;
ap = NULL;
al = 0;
switch (af) {
case AF_INET:
ap = (char *)&((struct sockaddr_in *)sa)->sin_addr;
al = sizeof(((struct sockaddr_in *)sa)->sin_addr);
break;
#ifdef INET6
case AF_INET6:
ap = (char *)&((struct sockaddr_in6 *)sa)->sin6_addr;
al = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
break;
#endif
default:
PyErr_SetString(PySocket_Error, "unsupported address family");
return NULL;
}
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_GETHOSTBYNAME_R #ifdef HAVE_GETHOSTBYNAME_R
#if defined(HAVE_GETHOSTBYNAME_R_6_ARG) #if defined(HAVE_GETHOSTBYNAME_R_6_ARG)
result = gethostbyaddr_r((char *)&addr.sin_addr, result = gethostbyaddr_r(ap, al, af,
sizeof(addr.sin_addr), &hp_allocated, buf, buf_len,
AF_INET, &hp_allocated, buf, buf_len,
&h, &errnop); &h, &errnop);
#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
h = gethostbyaddr_r((char *)&addr.sin_addr, h = gethostbyaddr_r(ap, al, af,
sizeof(addr.sin_addr),
AF_INET,
&hp_allocated, buf, buf_len, &errnop); &hp_allocated, buf, buf_len, &errnop);
#else /* HAVE_GETHOSTBYNAME_R_3_ARG */ #else /* HAVE_GETHOSTBYNAME_R_3_ARG */
memset((void *) &data, '\0', sizeof(data)); memset((void *) &data, '\0', sizeof(data));
result = gethostbyaddr_r((char *)&addr.sin_addr, result = gethostbyaddr_r(ap, al, af, &hp_allocated, &data);
sizeof(addr.sin_addr),
AF_INET, &hp_allocated, &data);
h = (result != 0) ? NULL : &hp_allocated; h = (result != 0) ? NULL : &hp_allocated;
#endif #endif
#else /* not HAVE_GETHOSTBYNAME_R */ #else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(gethostbyname_lock, 1); PyThread_acquire_lock(gethostbyname_lock, 1);
#endif #endif
h = gethostbyaddr((char *)&addr.sin_addr, h = gethostbyaddr(ap, al, af);
sizeof(addr.sin_addr),
AF_INET);
#endif /* HAVE_GETHOSTBYNAME_R */ #endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
ret = gethost_common(h, &addr); ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af);
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(gethostbyname_lock); PyThread_release_lock(gethostbyname_lock);
#endif #endif
@ -2134,6 +2321,156 @@ PySocket_inet_ntoa(PyObject *self, PyObject *args)
return PyString_FromString(inet_ntoa(packed_addr)); return PyString_FromString(inet_ntoa(packed_addr));
} }
/* Python interface to getaddrinfo(host, port). */
/*ARGSUSED*/
static PyObject *
PySocket_getaddrinfo(PyObject *self, PyObject *args)
{
struct addrinfo hints, *res0, *res;
PyObject *pobj = (PyObject *)NULL;
char pbuf[10];
char *hptr, *pptr;
int family, socktype, protocol, flags;
int error;
PyObject *all = (PyObject *)NULL;
PyObject *single = (PyObject *)NULL;
family = socktype = protocol = flags = 0;
family = PF_UNSPEC;
if (!PyArg_ParseTuple(args, "zO|iiii:getaddrinfo",
&hptr, &pobj, &family, &socktype,
&protocol, &flags)) {
return NULL;
}
if (PyInt_Check(pobj)) {
snprintf(pbuf, sizeof(pbuf), "%ld", PyInt_AsLong(pobj));
pptr = pbuf;
} else if (PyString_Check(pobj)) {
pptr = PyString_AsString(pobj);
} else if (pobj == Py_None) {
pptr = (char *)NULL;
} else {
PyErr_SetString(PySocket_Error, "Int or String expected");
return NULL;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = socktype;
hints.ai_protocol = protocol;
hints.ai_flags = flags;
error = getaddrinfo(hptr, pptr, &hints, &res0);
if (error) {
PyGAI_Err(error);
return NULL;
}
if ((all = PyList_New(0)) == NULL)
goto err;
for (res = res0; res; res = res->ai_next) {
single = Py_BuildValue("iiisO", res->ai_family,
res->ai_socktype, res->ai_protocol,
res->ai_canonname ? res->ai_canonname : "",
makesockaddr(-1, res->ai_addr, res->ai_addrlen));
if (single == NULL)
goto err;
if (PyList_Append(all, single))
goto err;
Py_XDECREF(single);
}
Py_XDECREF(pobj);
return all;
err:
Py_XDECREF(single);
Py_XDECREF(all);
Py_XDECREF(pobj);
return (PyObject *)NULL;
}
static char getaddrinfo_doc[] =
"socket.getaddrinfo(host, port [, family, socktype, proto, flags])\n\
--> List of (family, socktype, proto, canonname, sockaddr)\n\
\n\
Resolve host and port into addrinfo struct.";
/* Python interface to getnameinfo(sa, flags). */
/*ARGSUSED*/
static PyObject *
PySocket_getnameinfo(PyObject *self, PyObject *args)
{
PyObject *sa = (PyObject *)NULL;
int flags;
char *hostp;
int n, port, flowinfo, scope_id;
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
struct addrinfo hints, *res = NULL;
int error;
PyObject *ret = (PyObject *)NULL;
flags = flowinfo = scope_id = 0;
if (PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags) == 0)
return NULL;
n = PyArg_ParseTuple(sa, "si|ii", &hostp, &port, &flowinfo, scope_id);
if (n == 0)
goto fail;
snprintf(pbuf, sizeof(pbuf), "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
error = getaddrinfo(hostp, pbuf, &hints, &res);
if (error) {
PyGAI_Err(error);
goto fail;
}
if (res->ai_next) {
PyErr_SetString(PySocket_Error,
"sockaddr resolved to multiple addresses");
goto fail;
}
switch (res->ai_family) {
case AF_INET:
{
char *t1;
int t2;
if (PyArg_ParseTuple(sa, "si", &t1, &t2) == 0) {
PyErr_SetString(PySocket_Error,
"IPv4 sockaddr must be 2 tuple");
goto fail;
}
break;
}
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)res->ai_addr;
sin6->sin6_flowinfo = flowinfo;
sin6->sin6_scope_id = scope_id;
break;
}
#endif
}
error = getnameinfo(res->ai_addr, res->ai_addrlen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags);
if (error) {
PyGAI_Err(error);
goto fail;
}
ret = Py_BuildValue("ss", hbuf, pbuf);
fail:
if (res)
freeaddrinfo(res);
Py_XDECREF(sa);
return ret;
}
static char getnameinfo_doc[] =
"socket.getnameinfo(sockaddr, flags) --> (host, port)\n\
\n\
Get host and port for a sockaddr.";
#ifdef USE_SSL #ifdef USE_SSL
@ -2389,6 +2726,10 @@ static PyMethodDef PySocket_methods[] = {
METH_VARARGS, inet_aton_doc}, METH_VARARGS, inet_aton_doc},
{"inet_ntoa", PySocket_inet_ntoa, {"inet_ntoa", PySocket_inet_ntoa,
METH_VARARGS, inet_ntoa_doc}, METH_VARARGS, inet_ntoa_doc},
{"getaddrinfo", PySocket_getaddrinfo,
METH_VARARGS, getaddrinfo_doc},
{"getnameinfo", PySocket_getnameinfo,
METH_VARARGS, getnameinfo_doc},
#ifdef USE_SSL #ifdef USE_SSL
{"ssl", PySocket_ssl, {"ssl", PySocket_ssl,
METH_VARARGS, ssl_doc}, METH_VARARGS, ssl_doc},
@ -2559,6 +2900,13 @@ init_socket(void)
PySocket_Error = PyErr_NewException("socket.error", NULL, NULL); PySocket_Error = PyErr_NewException("socket.error", NULL, NULL);
if (PySocket_Error == NULL) if (PySocket_Error == NULL)
return; return;
PyH_Error = PyErr_NewException("socket.herror", PySocket_Error, NULL);
if (PyH_Error == NULL)
return;
PyGAI_Error = PyErr_NewException("socket.gaierror", PySocket_Error,
NULL);
if (PyGAI_Error == NULL)
return;
#ifdef USE_SSL #ifdef USE_SSL
SSL_load_error_strings(); SSL_load_error_strings();
SSLeay_add_ssl_algorithms(); SSLeay_add_ssl_algorithms();
@ -2584,6 +2932,9 @@ init_socket(void)
insint(d, "AF_UNSPEC", AF_UNSPEC); insint(d, "AF_UNSPEC", AF_UNSPEC);
#endif #endif
insint(d, "AF_INET", AF_INET); insint(d, "AF_INET", AF_INET);
#ifdef AF_INET6
insint(d, "AF_INET6", AF_INET6);
#endif /* AF_INET6 */
#ifdef AF_UNIX #ifdef AF_UNIX
insint(d, "AF_UNIX", AF_UNIX); insint(d, "AF_UNIX", AF_UNIX);
#endif /* AF_UNIX */ #endif /* AF_UNIX */
@ -2939,6 +3290,98 @@ init_socket(void)
insint(d, "IPX_TYPE", IPX_TYPE); insint(d, "IPX_TYPE", IPX_TYPE);
#endif #endif
/* get{addr,name}info parameters */
#ifdef EAI_ADDRFAMILY
insint(d, "EAI_ADDRFAMILY", EAI_ADDRFAMILY);
#endif
#ifdef EAI_AGAIN
insint(d, "EAI_AGAIN", EAI_AGAIN);
#endif
#ifdef EAI_BADFLAGS
insint(d, "EAI_BADFLAGS", EAI_BADFLAGS);
#endif
#ifdef EAI_FAIL
insint(d, "EAI_FAIL", EAI_FAIL);
#endif
#ifdef EAI_FAMILY
insint(d, "EAI_FAMILY", EAI_FAMILY);
#endif
#ifdef EAI_MEMORY
insint(d, "EAI_MEMORY", EAI_MEMORY);
#endif
#ifdef EAI_NODATA
insint(d, "EAI_NODATA", EAI_NODATA);
#endif
#ifdef EAI_NONAME
insint(d, "EAI_NONAME", EAI_NONAME);
#endif
#ifdef EAI_SERVICE
insint(d, "EAI_SERVICE", EAI_SERVICE);
#endif
#ifdef EAI_SOCKTYPE
insint(d, "EAI_SOCKTYPE", EAI_SOCKTYPE);
#endif
#ifdef EAI_SYSTEM
insint(d, "EAI_SYSTEM", EAI_SYSTEM);
#endif
#ifdef EAI_BADHINTS
insint(d, "EAI_BADHINTS", EAI_BADHINTS);
#endif
#ifdef EAI_PROTOCOL
insint(d, "EAI_PROTOCOL", EAI_PROTOCOL);
#endif
#ifdef EAI_MAX
insint(d, "EAI_MAX", EAI_MAX);
#endif
#ifdef AI_PASSIVE
insint(d, "AI_PASSIVE", AI_PASSIVE);
#endif
#ifdef AI_CANONNAME
insint(d, "AI_CANONNAME", AI_CANONNAME);
#endif
#ifdef AI_NUMERICHOST
insint(d, "AI_NUMERICHOST", AI_NUMERICHOST);
#endif
#ifdef AI_MASK
insint(d, "AI_MASK", AI_MASK);
#endif
#ifdef AI_ALL
insint(d, "AI_ALL", AI_ALL);
#endif
#ifdef AI_V4MAPPED_CFG
insint(d, "AI_V4MAPPED_CFG", AI_V4MAPPED_CFG);
#endif
#ifdef AI_ADDRCONFIG
insint(d, "AI_ADDRCONFIG", AI_ADDRCONFIG);
#endif
#ifdef AI_V4MAPPED
insint(d, "AI_V4MAPPED", AI_V4MAPPED);
#endif
#ifdef AI_DEFAULT
insint(d, "AI_DEFAULT", AI_DEFAULT);
#endif
#ifdef NI_MAXHOST
insint(d, "NI_MAXHOST", NI_MAXHOST);
#endif
#ifdef NI_MAXSERV
insint(d, "NI_MAXSERV", NI_MAXSERV);
#endif
#ifdef NI_NOFQDN
insint(d, "NI_NOFQDN", NI_NOFQDN);
#endif
#ifdef NI_NUMERICHOST
insint(d, "NI_NUMERICHOST", NI_NUMERICHOST);
#endif
#ifdef NI_NAMEREQD
insint(d, "NI_NAMEREQD", NI_NAMEREQD);
#endif
#ifdef NI_NUMERICSERV
insint(d, "NI_NUMERICSERV", NI_NUMERICSERV);
#endif
#ifdef NI_DGRAM
insint(d, "NI_DGRAM", NI_DGRAM);
#endif
/* Initialize gethostbyname lock */ /* Initialize gethostbyname lock */
#ifdef USE_GETHOSTBYNAME_LOCK #ifdef USE_GETHOSTBYNAME_LOCK
gethostbyname_lock = PyThread_allocate_lock(); gethostbyname_lock = PyThread_allocate_lock();