diff options
author | Martin v. Löwis <martin@v.loewis.de> | 2001-07-21 18:05:31 (GMT) |
---|---|---|
committer | Martin v. Löwis <martin@v.loewis.de> | 2001-07-21 18:05:31 (GMT) |
commit | 2d8d4276c67d39af113c1a169c2661d7f0f86285 (patch) | |
tree | f1414cb6fc9ef6ccdf384f3713186176e91f105b /Modules/socketmodule.c | |
parent | b7cea6324ae24b81668185a8c6186447559e4263 (diff) | |
download | cpython-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.c | 649 |
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(); |