summaryrefslogtreecommitdiffstats
path: root/Modules/socketmodule.c
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2001-07-21 18:05:31 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2001-07-21 18:05:31 (GMT)
commit2d8d4276c67d39af113c1a169c2661d7f0f86285 (patch)
treef1414cb6fc9ef6ccdf384f3713186176e91f105b /Modules/socketmodule.c
parentb7cea6324ae24b81668185a8c6186447559e4263 (diff)
downloadcpython-2d8d4276c67d39af113c1a169c2661d7f0f86285.zip
cpython-2d8d4276c67d39af113c1a169c2661d7f0f86285.tar.gz
cpython-2d8d4276c67d39af113c1a169c2661d7f0f86285.tar.bz2
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.
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r--Modules/socketmodule.c649
1 files changed, 546 insertions, 103 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index e4bdf41..b44e9b8 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -7,7 +7,7 @@ This module provides an interface to Berkeley socket IPC.
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.
- no read/write operations (use send/recv or makefile instead)
- additional restrictions apply on Windows
@@ -15,6 +15,10 @@ Limitations:
Module interface:
- 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.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...])
- 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.htons(16 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.inet_aton(IP address) -> 32-bit packed IP representation
- socket.inet_ntoa(packed IP) -> IP address string
@@ -239,6 +246,10 @@ typedef int SOCKET_T;
# define SIZEOF_SOCKET_T SIZEOF_INT
#endif
+#ifdef MS_WIN32
+# define EAFNOSUPPORT WSAEAFNOSUPPORT
+# define snprintf _snprintf
+#endif
#if defined(PYOS_OS2)
#define SOCKETCLOSE soclose
@@ -253,6 +264,8 @@ typedef int SOCKET_T;
by this module (but not argument type or memory errors, etc.). */
static PyObject *PySocket_Error;
+static PyObject *PyH_Error;
+static PyObject *PyGAI_Error;
#ifdef USE_SSL
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,
like the address family, which is used to decode socket address
arguments properly. */
@@ -408,6 +458,10 @@ typedef struct {
#ifdef AF_UNIX
struct sockaddr_un un;
#endif
+#ifdef INET6
+ struct sockaddr_in6 in6;
+ struct sockaddr_storage storage;
+#endif
#if defined(linux) && defined(AF_PACKET)
struct sockaddr_ll ll;
#endif
@@ -484,85 +538,87 @@ PyThread_type_lock gethostbyname_lock;
/* Convert a string specifying a host name or one of a few symbolic
names to a numeric IP address. This usually calls gethostbyname()
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. */
static int
-setipaddr(char* name, struct sockaddr_in * addr_ret)
+setipaddr(char* name, struct sockaddr * addr_ret, int af)
{
- struct hostent *hp;
- int d1, d2, d3, d4;
- 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 */
+ struct addrinfo hints, *res;
+ int error;
memset((void *) addr_ret, '\0', sizeof(*addr_ret));
if (name[0] == '\0') {
- addr_ret->sin_addr.s_addr = INADDR_ANY;
- return 4;
+ int siz;
+ 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) {
- addr_ret->sin_addr.s_addr = INADDR_BROADCAST;
- return 4;
+ struct sockaddr_in *sin;
+ 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 &&
- 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
- 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
- addr_ret->sin_addr.s_addr = htonl(
- ((long) d1 << 24) | ((long) d2 << 16) |
- ((long) d3 << 8) | ((long) d4 << 0));
- return 4;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ error = getaddrinfo(name, NULL, &hints, &res);
+ if (error) {
+ PyGAI_Err(error);
+ return -1;
}
- 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);
+ memcpy((char *) addr_ret, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ switch (addr_ret->sa_family) {
+ case AF_INET:
+ return 4;
+#ifdef INET6
+ case AF_INET6:
+ return 16;
#endif
+ default:
+ PyErr_SetString(PySocket_Error, "unknown address family");
return -1;
}
- memcpy((char *) &addr_ret->sin_addr, hp->h_addr, hp->h_length);
- h_length = hp->h_length;
-#ifdef USE_GETHOSTBYNAME_LOCK
- PyThread_release_lock(gethostbyname_lock);
-#endif
- return h_length;
}
@@ -571,13 +627,17 @@ setipaddr(char* name, struct sockaddr_in * addr_ret)
size numbers). */
static PyObject *
-makeipaddr(struct sockaddr_in *addr)
+makeipaddr(struct sockaddr *addr, int addrlen)
{
- unsigned long x = ntohl(addr->sin_addr.s_addr);
- char buf[100];
- sprintf(buf, "%d.%d.%d.%d",
- (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
- (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
+ char buf[NI_MAXHOST];
+ int error;
+
+ error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error) {
+ PyGAI_Err(error);
+ return NULL;
+ }
return PyString_FromString(buf);
}
@@ -606,10 +666,11 @@ makesockaddr(int sockfd, struct sockaddr *addr, int addrlen)
case AF_INET:
{
- struct sockaddr_in *a = (struct sockaddr_in *) addr;
- PyObject *addrobj = makeipaddr(a);
+ struct sockaddr_in *a;
+ PyObject *addrobj = makeipaddr(addr, sizeof(*a));
PyObject *ret = NULL;
if (addrobj) {
+ a = (struct sockaddr_in *)addr;
ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
Py_DECREF(addrobj);
}
@@ -622,6 +683,22 @@ makesockaddr(int sockfd, struct sockaddr *addr, int addrlen)
struct sockaddr_un *a = (struct sockaddr_un *) addr;
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
#if defined(linux) && defined(AF_PACKET)
@@ -681,7 +758,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
"AF_UNIX path too long");
return 0;
}
- addr->sun_family = AF_UNIX;
+ addr->sun_family = s->sock_family;
memcpy(addr->sun_path, path, len);
addr->sun_path[len] = 0;
*addr_ret = (struct sockaddr *) addr;
@@ -704,7 +781,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
}
if (!PyArg_ParseTuple(args, "si:getsockaddrarg", &host, &port))
return 0;
- if (setipaddr(host, addr) < 0)
+ if (setipaddr(host, (struct sockaddr *)addr, AF_INET) < 0)
return 0;
addr->sin_family = AF_INET;
addr->sin_port = htons((short)port);
@@ -713,6 +790,30 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
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)
case AF_PACKET:
{
@@ -745,7 +846,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
}
#endif
-
/* More cases here... */
default:
@@ -779,6 +879,14 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
return 1;
}
+#ifdef INET6
+ case AF_INET6:
+ {
+ *len_ret = sizeof (struct sockaddr_in6);
+ return 1;
+ }
+#endif
+
#if defined(linux) && defined(AF_PACKET)
case AF_PACKET:
{
@@ -1652,12 +1760,14 @@ static PyObject *
PySocket_gethostbyname(PyObject *self, PyObject *args)
{
char *name;
- struct sockaddr_in addrbuf;
+ struct sockaddr_storage addrbuf;
+
if (!PyArg_ParseTuple(args, "s:gethostbyname", &name))
return NULL;
- if (setipaddr(name, &addrbuf) < 0)
+ if (setipaddr(name, (struct sockaddr *)&addrbuf, AF_INET) < 0)
return NULL;
- return makeipaddr(&addrbuf);
+ return makeipaddr((struct sockaddr *)&addrbuf,
+ sizeof(struct sockaddr_in));
}
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 */
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;
PyObject *rtn_tuple = (PyObject *)NULL;
PyObject *name_list = (PyObject *)NULL;
PyObject *addr_list = (PyObject *)NULL;
PyObject *tmp;
+
if (h == NULL) {
-#ifdef HAVE_HSTRERROR
/* Let's get real error message to return */
+#ifndef MS_WIN32
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
- PyErr_SetString(PySocket_Error, "host not found");
+ PyErr_SetString(PySocket_Error,
+ "Address family not supported by protocol family");
#endif
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)
goto err;
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++) {
int status;
- memcpy((char *) &addr->sin_addr, *pch, h->h_length);
- tmp = makeipaddr(addr);
+ switch (af) {
+ 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)
goto err;
status = PyList_Append(addr_list, tmp);
@@ -1727,7 +1893,7 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
{
char *name;
struct hostent *h;
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
PyObject *ret;
#ifdef HAVE_GETHOSTBYNAME_R
struct hostent hp_allocated;
@@ -1742,9 +1908,10 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
int result;
#endif
#endif /* HAVE_GETHOSTBYNAME_R */
+
if (!PyArg_ParseTuple(args, "s:gethostbyname_ex", &name))
return NULL;
- if (setipaddr(name, &addr) < 0)
+ if (setipaddr(name, (struct sockaddr *)&addr, PF_INET) < 0)
return NULL;
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_GETHOSTBYNAME_R
@@ -1764,7 +1931,7 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
h = gethostbyname(name);
#endif /* HAVE_GETHOSTBYNAME_R */
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
PyThread_release_lock(gethostbyname_lock);
#endif
@@ -1784,7 +1951,12 @@ for a host. The host argument is a string giving a host name or IP number.";
static PyObject *
PySocket_gethostbyaddr(PyObject *self, PyObject *args)
{
+#ifdef INET6
+ struct sockaddr_storage addr;
+#else
struct sockaddr_in addr;
+#endif
+ struct sockaddr *sa = (struct sockaddr *)&addr;
char *ip_num;
struct hostent *h;
PyObject *ret;
@@ -1801,40 +1973,55 @@ PySocket_gethostbyaddr(PyObject *self, PyObject *args)
int result;
#endif
#endif /* HAVE_GETHOSTBYNAME_R */
+ char *ap;
+ int al;
+ int af;
if (!PyArg_ParseTuple(args, "s:gethostbyaddr", &ip_num))
return NULL;
- if (setipaddr(ip_num, &addr) < 0)
+ af = PF_UNSPEC;
+ if (setipaddr(ip_num, sa, af) < 0)
+ 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
#ifdef HAVE_GETHOSTBYNAME_R
#if defined(HAVE_GETHOSTBYNAME_R_6_ARG)
- result = gethostbyaddr_r((char *)&addr.sin_addr,
- sizeof(addr.sin_addr),
- AF_INET, &hp_allocated, buf, buf_len,
+ result = gethostbyaddr_r(ap, al, af,
+ &hp_allocated, buf, buf_len,
&h, &errnop);
#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
- h = gethostbyaddr_r((char *)&addr.sin_addr,
- sizeof(addr.sin_addr),
- AF_INET,
+ h = gethostbyaddr_r(ap, al, af,
&hp_allocated, buf, buf_len, &errnop);
#else /* HAVE_GETHOSTBYNAME_R_3_ARG */
memset((void *) &data, '\0', sizeof(data));
- result = gethostbyaddr_r((char *)&addr.sin_addr,
- sizeof(addr.sin_addr),
- AF_INET, &hp_allocated, &data);
+ result = gethostbyaddr_r(ap, al, af, &hp_allocated, &data);
h = (result != 0) ? NULL : &hp_allocated;
#endif
#else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_acquire_lock(gethostbyname_lock, 1);
#endif
- h = gethostbyaddr((char *)&addr.sin_addr,
- sizeof(addr.sin_addr),
- AF_INET);
+ h = gethostbyaddr(ap, al, af);
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
- ret = gethost_common(h, &addr);
+ ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af);
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(gethostbyname_lock);
#endif
@@ -2134,6 +2321,156 @@ PySocket_inet_ntoa(PyObject *self, PyObject *args)
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
@@ -2389,6 +2726,10 @@ static PyMethodDef PySocket_methods[] = {
METH_VARARGS, inet_aton_doc},
{"inet_ntoa", PySocket_inet_ntoa,
METH_VARARGS, inet_ntoa_doc},
+ {"getaddrinfo", PySocket_getaddrinfo,
+ METH_VARARGS, getaddrinfo_doc},
+ {"getnameinfo", PySocket_getnameinfo,
+ METH_VARARGS, getnameinfo_doc},
#ifdef USE_SSL
{"ssl", PySocket_ssl,
METH_VARARGS, ssl_doc},
@@ -2559,6 +2900,13 @@ init_socket(void)
PySocket_Error = PyErr_NewException("socket.error", NULL, NULL);
if (PySocket_Error == NULL)
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
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
@@ -2584,6 +2932,9 @@ init_socket(void)
insint(d, "AF_UNSPEC", AF_UNSPEC);
#endif
insint(d, "AF_INET", AF_INET);
+#ifdef AF_INET6
+ insint(d, "AF_INET6", AF_INET6);
+#endif /* AF_INET6 */
#ifdef AF_UNIX
insint(d, "AF_UNIX", AF_UNIX);
#endif /* AF_UNIX */
@@ -2939,6 +3290,98 @@ init_socket(void)
insint(d, "IPX_TYPE", IPX_TYPE);
#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 */
#ifdef USE_GETHOSTBYNAME_LOCK
gethostbyname_lock = PyThread_allocate_lock();