diff options
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r-- | Modules/socketmodule.c | 496 |
1 files changed, 305 insertions, 191 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index e9feba378e..8cf6140145 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -121,7 +121,7 @@ getpeername() -- return remote address [*]\n\ getsockname() -- return local address\n\ getsockopt(level, optname[, buflen]) -- get socket options\n\ gettimeout() -- return timeout or None\n\ -listen(n) -- start listening for incoming connections\n\ +listen([n]) -- start listening for incoming connections\n\ recv(buflen[, flags]) -- receive data\n\ recv_into(buffer[, nbytes[, flags]]) -- receive data (into a buffer)\n\ recvfrom(buflen[, flags]) -- receive data and sender\'s address\n\ @@ -284,14 +284,15 @@ if_indextoname(index) -- return the corresponding interface name\n\ # include <fcntl.h> # endif +#if defined(_MSC_VER) && _MSC_VER >= 1800 +/* Provides the IsWindows7SP1OrGreater() function */ +#include <VersionHelpers.h> #endif -#include <stddef.h> - -#ifndef offsetof -# define offsetof(type, member) ((size_t)(&((type *)0)->member)) #endif +#include <stddef.h> + #ifndef O_NONBLOCK # define O_NONBLOCK O_NDELAY #endif @@ -552,6 +553,9 @@ set_gaierror(int error) static int internal_setblocking(PySocketSockObject *s, int block) { +#ifdef MS_WINDOWS + u_long arg; +#endif #if !defined(MS_WINDOWS) \ && !((defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO))) int delay_flag, new_delay_flag; @@ -578,8 +582,8 @@ internal_setblocking(PySocketSockObject *s, int block) fcntl(s->sock_fd, F_SETFL, new_delay_flag); #endif #else /* MS_WINDOWS */ - block = !block; - ioctlsocket(s->sock_fd, FIONBIO, (u_long*)&block); + arg = !block; + ioctlsocket(s->sock_fd, FIONBIO, &arg); #endif /* MS_WINDOWS */ Py_END_ALLOW_THREADS @@ -681,9 +685,9 @@ internal_select(PySocketSockObject *s, int writing) double interval = s->sock_timeout; \ int has_timeout = s->sock_timeout > 0.0; \ if (has_timeout) { \ - _PyTime_gettimeofday(&now); \ + _PyTime_monotonic(&now); \ deadline = now; \ - _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \ + _PyTime_AddDouble(&deadline, s->sock_timeout, _PyTime_ROUND_UP); \ } \ while (1) { \ errno = 0; \ @@ -692,7 +696,7 @@ internal_select(PySocketSockObject *s, int writing) if (!has_timeout || \ (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \ break; \ - _PyTime_gettimeofday(&now); \ + _PyTime_monotonic(&now); \ interval = _PyTime_INTERVAL(now, deadline); \ } \ } \ @@ -1214,6 +1218,71 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) } } +/* Helper for getsockaddrarg: bypass IDNA for ASCII-only host names + (in particular, numeric IP addresses). */ +struct maybe_idna { + PyObject *obj; + char *buf; +}; + +static void +idna_cleanup(struct maybe_idna *data) +{ + Py_CLEAR(data->obj); +} + +static int +idna_converter(PyObject *obj, struct maybe_idna *data) +{ + size_t len; + PyObject *obj2, *obj3; + if (obj == NULL) { + idna_cleanup(data); + return 1; + } + data->obj = NULL; + len = -1; + if (PyBytes_Check(obj)) { + data->buf = PyBytes_AsString(obj); + len = PyBytes_Size(obj); + } + else if (PyByteArray_Check(obj)) { + data->buf = PyByteArray_AsString(obj); + len = PyByteArray_Size(obj); + } + else if (PyUnicode_Check(obj) && PyUnicode_READY(obj) == 0 && PyUnicode_IS_COMPACT_ASCII(obj)) { + data->buf = PyUnicode_DATA(obj); + len = PyUnicode_GET_LENGTH(obj); + } + else { + obj2 = PyUnicode_FromObject(obj); + if (!obj2) { + PyErr_Format(PyExc_TypeError, "string or unicode text buffer expected, not %s", + obj->ob_type->tp_name); + return 0; + } + obj3 = PyUnicode_AsEncodedString(obj2, "idna", NULL); + Py_DECREF(obj2); + if (!obj3) { + PyErr_SetString(PyExc_TypeError, "encoding of hostname failed"); + return 0; + } + if (!PyBytes_Check(obj3)) { + Py_DECREF(obj3); + PyErr_SetString(PyExc_TypeError, "encoding of hostname failed to return bytes"); + return 0; + } + data->obj = obj3; + data->buf = PyBytes_AS_STRING(obj3); + len = PyBytes_GET_SIZE(obj3); + } + if (strlen(data->buf) != len) { + Py_CLEAR(data->obj); + PyErr_SetString(PyExc_TypeError, "host name must not contain null character"); + return 0; + } + return Py_CLEANUP_SUPPORTED; +} /* Parse a socket address argument according to the socket object's address family. Return 1 if the address was in the proper format, @@ -1230,8 +1299,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, case AF_UNIX: { struct sockaddr_un* addr; - char *path; - int len; + Py_buffer path; int retval = 0; /* PEP 383. Not using PyUnicode_FSConverter since we need to @@ -1242,14 +1310,17 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, } else Py_INCREF(args); - if (!PyArg_Parse(args, "y#", &path, &len)) - goto unix_out; + if (!PyArg_Parse(args, "y*", &path)) { + Py_DECREF(args); + return retval; + } + assert(path.len >= 0); addr = (struct sockaddr_un*)addr_ret; #ifdef linux - if (len > 0 && path[0] == 0) { + if (path.len > 0 && *(const char *)path.buf == 0) { /* Linux abstract namespace extension */ - if (len > sizeof addr->sun_path) { + if ((size_t)path.len > sizeof addr->sun_path) { PyErr_SetString(PyExc_OSError, "AF_UNIX path too long"); goto unix_out; @@ -1259,18 +1330,19 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, #endif /* linux */ { /* regular NULL-terminated string */ - if (len >= sizeof addr->sun_path) { + if ((size_t)path.len >= sizeof addr->sun_path) { PyErr_SetString(PyExc_OSError, "AF_UNIX path too long"); goto unix_out; } - addr->sun_path[len] = 0; + addr->sun_path[path.len] = 0; } addr->sun_family = s->sock_family; - memcpy(addr->sun_path, path, len); - *len_ret = len + offsetof(struct sockaddr_un, sun_path); + memcpy(addr->sun_path, path.buf, path.len); + *len_ret = path.len + offsetof(struct sockaddr_un, sun_path); retval = 1; unix_out: + PyBuffer_Release(&path); Py_DECREF(args); return retval; } @@ -1308,7 +1380,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, case AF_INET: { struct sockaddr_in* addr; - char *host; + struct maybe_idna host = {NULL, NULL}; int port, result; if (!PyTuple_Check(args)) { PyErr_Format( @@ -1318,13 +1390,13 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, Py_TYPE(args)->tp_name); return 0; } - if (!PyArg_ParseTuple(args, "eti:getsockaddrarg", - "idna", &host, &port)) + if (!PyArg_ParseTuple(args, "O&i:getsockaddrarg", + idna_converter, &host, &port)) return 0; addr=(struct sockaddr_in*)addr_ret; - result = setipaddr(host, (struct sockaddr *)addr, + result = setipaddr(host.buf, (struct sockaddr *)addr, sizeof(*addr), AF_INET); - PyMem_Free(host); + idna_cleanup(&host); if (result < 0) return 0; if (port < 0 || port > 0xffff) { @@ -1343,7 +1415,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, case AF_INET6: { struct sockaddr_in6* addr; - char *host; + struct maybe_idna host = {NULL, NULL}; int port, result; unsigned int flowinfo, scope_id; flowinfo = scope_id = 0; @@ -1355,15 +1427,15 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, Py_TYPE(args)->tp_name); return 0; } - if (!PyArg_ParseTuple(args, "eti|II", - "idna", &host, &port, &flowinfo, + if (!PyArg_ParseTuple(args, "O&i|II", + idna_converter, &host, &port, &flowinfo, &scope_id)) { return 0; } addr = (struct sockaddr_in6*)addr_ret; - result = setipaddr(host, (struct sockaddr *)addr, + result = setipaddr(host.buf, (struct sockaddr *)addr, sizeof(*addr), AF_INET6); - PyMem_Free(host); + idna_cleanup(&host); if (result < 0) return 0; if (port < 0 || port > 0xffff) { @@ -1492,8 +1564,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, int protoNumber; int hatype = 0; int pkttype = 0; - char *haddr = NULL; - unsigned int halen = 0; + Py_buffer haddr = {NULL, NULL}; if (!PyTuple_Check(args)) { PyErr_Format( @@ -1503,25 +1574,28 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, Py_TYPE(args)->tp_name); return 0; } - if (!PyArg_ParseTuple(args, "si|iiy#", &interfaceName, + if (!PyArg_ParseTuple(args, "si|iiy*", &interfaceName, &protoNumber, &pkttype, &hatype, - &haddr, &halen)) + &haddr)) return 0; strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { s->errorhandler(); + PyBuffer_Release(&haddr); return 0; } - if (halen > 8) { - PyErr_SetString(PyExc_ValueError, - "Hardware address must be 8 bytes or less"); - return 0; + if (haddr.buf && haddr.len > 8) { + PyErr_SetString(PyExc_ValueError, + "Hardware address must be 8 bytes or less"); + PyBuffer_Release(&haddr); + return 0; } if (protoNumber < 0 || protoNumber > 0xffff) { PyErr_SetString( PyExc_OverflowError, "getsockaddrarg: protoNumber must be 0-65535."); + PyBuffer_Release(&haddr); return 0; } addr = (struct sockaddr_ll*)addr_ret; @@ -1530,11 +1604,14 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, addr->sll_ifindex = ifr.ifr_ifindex; addr->sll_pkttype = pkttype; addr->sll_hatype = hatype; - if (halen != 0) { - memcpy(&addr->sll_addr, haddr, halen); + if (haddr.buf) { + memcpy(&addr->sll_addr, haddr.buf, haddr.len); + addr->sll_halen = haddr.len; } - addr->sll_halen = halen; + else + addr->sll_halen = 0; *len_ret = sizeof *addr; + PyBuffer_Release(&haddr); return 1; } #endif @@ -1611,7 +1688,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, if (len == 0) { ifr.ifr_ifindex = 0; - } else if (len < sizeof(ifr.ifr_name)) { + } else if ((size_t)len < sizeof(ifr.ifr_name)) { strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { @@ -1661,7 +1738,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, return 0; } - if (PyBytes_GET_SIZE(ctl_name) > sizeof(info.ctl_name)) { + if (PyBytes_GET_SIZE(ctl_name) > (Py_ssize_t)sizeof(info.ctl_name)) { PyErr_SetString(PyExc_ValueError, "provided string is too long"); Py_DECREF(ctl_name); @@ -1896,8 +1973,15 @@ cmsg_min_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t space) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #endif + #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wtype-limits" + #endif if (msg->msg_controllen < 0) return 0; + #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))) + #pragma GCC diagnostic pop + #endif #ifdef __clang__ #pragma clang diagnostic pop #endif @@ -1967,6 +2051,7 @@ sock_accept(PySocketSockObject *s) PyObject *addr = NULL; PyObject *res = NULL; int timeout; + int async_err = 0; #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ static int accept4_works = -1; @@ -1980,27 +2065,27 @@ sock_accept(PySocketSockObject *s) return select_error(); BEGIN_SELECT_LOOP(s) - - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 0, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 0, interval); + if (!timeout) { #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) - if (accept4_works != 0) { - newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, - SOCK_CLOEXEC); - if (newfd == INVALID_SOCKET && accept4_works == -1) { - /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ - accept4_works = (errno != ENOSYS); + if (accept4_works != 0) { + newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, + SOCK_CLOEXEC); + if (newfd == INVALID_SOCKET && accept4_works == -1) { + /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ + accept4_works = (errno != ENOSYS); + } } - } - if (accept4_works == 0) - newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); + if (accept4_works == 0) + newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); #else - newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); + newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); #endif - } - Py_END_ALLOW_THREADS - + } + Py_END_ALLOW_THREADS + } while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; @@ -2008,7 +2093,7 @@ sock_accept(PySocketSockObject *s) END_SELECT_LOOP(s) if (newfd == INVALID_SOCKET) - return s->errorhandler(); + return (!async_err) ? s->errorhandler() : NULL; #ifdef MS_WINDOWS if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) { @@ -2152,22 +2237,21 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args) int level; int optname; int res; - char *buf; - int buflen; + Py_buffer optval; int flag; if (PyArg_ParseTuple(args, "iii:setsockopt", &level, &optname, &flag)) { - buf = (char *) &flag; - buflen = sizeof flag; + res = setsockopt(s->sock_fd, level, optname, &flag, sizeof flag); } else { PyErr_Clear(); - if (!PyArg_ParseTuple(args, "iiy#:setsockopt", - &level, &optname, &buf, &buflen)) + if (!PyArg_ParseTuple(args, "iiy*:setsockopt", + &level, &optname, &optval)) return NULL; + res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len); + PyBuffer_Release(&optval); } - res = setsockopt(s->sock_fd, level, optname, (void *)buf, buflen); if (res < 0) return s->errorhandler(); Py_INCREF(Py_None); @@ -2271,6 +2355,10 @@ sock_close(PySocketSockObject *s) { SOCKET_T fd; + /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/ + * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + * for more details. + */ if ((fd = s->sock_fd) != -1) { s->sock_fd = -1; Py_BEGIN_ALLOW_THREADS @@ -2443,10 +2531,8 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro) /* Signals are not errors (though they may raise exceptions). Adapted from PyErr_SetFromErrnoWithFilenameObject(). */ -#ifdef EINTR if (res == EINTR && PyErr_CheckSignals()) return NULL; -#endif return PyLong_FromLong((long) res); } @@ -2534,14 +2620,16 @@ info is a pair (hostaddr, port)."); /* s.listen(n) method */ static PyObject * -sock_listen(PySocketSockObject *s, PyObject *arg) +sock_listen(PySocketSockObject *s, PyObject *args) { - int backlog; + /* We try to choose a default backlog high enough to avoid connection drops + * for common workloads, yet not too high to limit resource usage. */ + int backlog = Py_MIN(SOMAXCONN, 128); int res; - backlog = _PyLong_AsInt(arg); - if (backlog == -1 && PyErr_Occurred()) + if (!PyArg_ParseTuple(args, "|i:listen", &backlog)) return NULL; + Py_BEGIN_ALLOW_THREADS /* To avoid problems on systems that don't allow a negative backlog * (which doesn't make sense anyway) we force a minimum value of 0. */ @@ -2556,12 +2644,12 @@ sock_listen(PySocketSockObject *s, PyObject *arg) } PyDoc_STRVAR(listen_doc, -"listen(backlog)\n\ +"listen([backlog])\n\ \n\ -Enable a server to accept connections. The backlog argument must be at\n\ -least 0 (if it is lower, it is set to 0); it specifies the number of\n\ +Enable a server to accept connections. If backlog is specified, it must be\n\ +at least 0 (if it is lower, it is set to 0); it specifies the number of\n\ unaccepted connections that the system will allow before refusing new\n\ -connections."); +connections. If not specified, a default reasonable value is chosen."); /* @@ -2578,6 +2666,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags) { Py_ssize_t outlen = -1; int timeout; + int async_err = 0; if (!IS_SELECTABLE(s)) { select_error(); @@ -2589,18 +2678,20 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags) } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 0, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 0, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - outlen = recv(s->sock_fd, cbuf, (int)len, flags); + if (len > INT_MAX) + len = INT_MAX; + outlen = recv(s->sock_fd, cbuf, (int)len, flags); #else - outlen = recv(s->sock_fd, cbuf, len, flags); + outlen = recv(s->sock_fd, cbuf, len, flags); #endif - } - Py_END_ALLOW_THREADS + } + Py_END_ALLOW_THREADS + } while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); @@ -2610,7 +2701,8 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags) if (outlen < 0) { /* Note: the call to errorhandler() ALWAYS indirectly returned NULL, so ignore its return value */ - s->errorhandler(); + if (!async_err) + s->errorhandler(); return -1; } return outlen; @@ -2747,6 +2839,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags, int timeout; Py_ssize_t n = -1; socklen_t addrlen; + int async_err = 0; *addr = NULL; @@ -2759,21 +2852,23 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags, } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - memset(&addrbuf, 0, addrlen); - timeout = internal_select_ex(s, 0, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + memset(&addrbuf, 0, addrlen); + timeout = internal_select_ex(s, 0, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = recvfrom(s->sock_fd, cbuf, (int)len, flags, - (void *) &addrbuf, &addrlen); + if (len > INT_MAX) + len = INT_MAX; + n = recvfrom(s->sock_fd, cbuf, (int)len, flags, + (void *) &addrbuf, &addrlen); #else - n = recvfrom(s->sock_fd, cbuf, len, flags, - SAS2SA(&addrbuf), &addrlen); + n = recvfrom(s->sock_fd, cbuf, len, flags, + SAS2SA(&addrbuf), &addrlen); #endif - } - Py_END_ALLOW_THREADS + } + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); @@ -2781,7 +2876,8 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags, } END_SELECT_LOOP(s) if (n < 0) { - s->errorhandler(); + if (!async_err) + s->errorhandler(); return -1; } @@ -2921,6 +3017,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen, { ssize_t bytes_received = -1; int timeout; + int async_err = 0; sock_addr_t addrbuf; socklen_t addrbuflen; struct msghdr msg = {0}; @@ -2956,25 +3053,29 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen, } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS; - msg.msg_name = SAS2SA(&addrbuf); - msg.msg_namelen = addrbuflen; - msg.msg_iov = iov; - msg.msg_iovlen = iovlen; - msg.msg_control = controlbuf; - msg.msg_controllen = controllen; - timeout = internal_select_ex(s, 0, interval); - if (!timeout) - bytes_received = recvmsg(s->sock_fd, &msg, flags); - Py_END_ALLOW_THREADS; - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); - goto finally; - } + do { + Py_BEGIN_ALLOW_THREADS; + msg.msg_name = SAS2SA(&addrbuf); + msg.msg_namelen = addrbuflen; + msg.msg_iov = iov; + msg.msg_iovlen = iovlen; + msg.msg_control = controlbuf; + msg.msg_controllen = controllen; + timeout = internal_select_ex(s, 0, interval); + if (!timeout) + bytes_received = recvmsg(s->sock_fd, &msg, flags); + Py_END_ALLOW_THREADS; + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + goto finally; + } + } while (bytes_received < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); END_SELECT_LOOP(s) if (bytes_received < 0) { - s->errorhandler(); + if (!async_err) + s->errorhandler(); goto finally; } @@ -3233,6 +3334,7 @@ sock_send(PySocketSockObject *s, PyObject *args) { char *buf; Py_ssize_t len, n = -1; + int async_err = 0; int flags = 0, timeout; Py_buffer pbuf; @@ -3247,18 +3349,20 @@ sock_send(PySocketSockObject *s, PyObject *args) len = pbuf.len; BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 1, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 1, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = send(s->sock_fd, buf, (int)len, flags); + if (len > INT_MAX) + len = INT_MAX; + n = send(s->sock_fd, buf, (int)len, flags); #else - n = send(s->sock_fd, buf, len, flags); + n = send(s->sock_fd, buf, len, flags); #endif - } - Py_END_ALLOW_THREADS + } + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyBuffer_Release(&pbuf); PyErr_SetString(socket_timeout, "timed out"); @@ -3268,7 +3372,7 @@ sock_send(PySocketSockObject *s, PyObject *args) PyBuffer_Release(&pbuf); if (n < 0) - return s->errorhandler(); + return (!async_err) ? s->errorhandler() : NULL; return PyLong_FromSsize_t(n); } @@ -3287,7 +3391,8 @@ sock_sendall(PySocketSockObject *s, PyObject *args) { char *buf; Py_ssize_t len, n = -1; - int flags = 0, timeout, saved_errno; + int async_err = 0; + int flags = 0, timeout; Py_buffer pbuf; if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags)) @@ -3319,29 +3424,16 @@ sock_sendall(PySocketSockObject *s, PyObject *args) PyErr_SetString(socket_timeout, "timed out"); return NULL; } - /* PyErr_CheckSignals() might change errno */ - saved_errno = errno; - /* We must run our signal handlers before looping again. - send() can return a successful partial write when it is - interrupted, so we can't restrict ourselves to EINTR. */ - if (PyErr_CheckSignals()) { - PyBuffer_Release(&pbuf); - return NULL; - } - if (n < 0) { - /* If interrupted, try again */ - if (saved_errno == EINTR) - continue; - else - break; + if (n >= 0) { + buf += n; + len -= n; } - buf += n; - len -= n; - } while (len > 0); + } while (len > 0 && (n >= 0 || errno == EINTR) && + !(async_err = PyErr_CheckSignals())); PyBuffer_Release(&pbuf); - if (n < 0) - return s->errorhandler(); + if (n < 0 || async_err) + return (!async_err) ? s->errorhandler() : NULL; Py_INCREF(Py_None); return Py_None; @@ -3367,6 +3459,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args) Py_ssize_t len, arglen; sock_addr_t addrbuf; int addrlen, n = -1, flags, timeout; + int async_err = 0; flags = 0; arglen = PyTuple_Size(args); @@ -3401,20 +3494,22 @@ sock_sendto(PySocketSockObject *s, PyObject *args) } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 1, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 1, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = sendto(s->sock_fd, buf, (int)len, flags, - SAS2SA(&addrbuf), addrlen); + if (len > INT_MAX) + len = INT_MAX; + n = sendto(s->sock_fd, buf, (int)len, flags, + SAS2SA(&addrbuf), addrlen); #else - n = sendto(s->sock_fd, buf, len, flags, - SAS2SA(&addrbuf), addrlen); + n = sendto(s->sock_fd, buf, len, flags, + SAS2SA(&addrbuf), addrlen); #endif - } - Py_END_ALLOW_THREADS + } + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyBuffer_Release(&pbuf); @@ -3424,7 +3519,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args) END_SELECT_LOOP(s) PyBuffer_Release(&pbuf); if (n < 0) - return s->errorhandler(); + return (!async_err) ? s->errorhandler() : NULL; return PyLong_FromSsize_t(n); } @@ -3456,6 +3551,7 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args) void *controlbuf = NULL; size_t controllen, controllen_last; ssize_t bytes_sent = -1; + int async_err = 0; int addrlen, timeout, flags = 0; PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL, *cmsg_fast = NULL, *retval = NULL; @@ -3613,19 +3709,23 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args) } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS; - timeout = internal_select_ex(s, 1, interval); - if (!timeout) - bytes_sent = sendmsg(s->sock_fd, &msg, flags); - Py_END_ALLOW_THREADS; - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); - goto finally; - } + do { + Py_BEGIN_ALLOW_THREADS; + timeout = internal_select_ex(s, 1, interval); + if (!timeout) + bytes_sent = sendmsg(s->sock_fd, &msg, flags); + Py_END_ALLOW_THREADS; + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + goto finally; + } + } while (bytes_sent < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); END_SELECT_LOOP(s) if (bytes_sent < 0) { - s->errorhandler(); + if (!async_err) + s->errorhandler(); goto finally; } retval = PyLong_FromSsize_t(bytes_sent); @@ -3795,7 +3895,7 @@ static PyMethodDef sock_methods[] = { {"share", (PyCFunction)sock_share, METH_VARARGS, sock_share_doc}, #endif - {"listen", (PyCFunction)sock_listen, METH_O, + {"listen", (PyCFunction)sock_listen, METH_VARARGS, listen_doc}, {"recv", (PyCFunction)sock_recv, METH_VARARGS, recv_doc}, @@ -4226,7 +4326,7 @@ 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 *addr, int alen, int af) +gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af) { char **pch; PyObject *rtn_tuple = (PyObject *)NULL; @@ -4943,21 +5043,22 @@ Convert an IP address from 32-bit packed binary format to string format"); static PyObject* socket_inet_ntoa(PyObject *self, PyObject *args) { - char *packed_str; - int addr_len; + Py_buffer packed_ip; struct in_addr packed_addr; - if (!PyArg_ParseTuple(args, "y#:inet_ntoa", &packed_str, &addr_len)) { + if (!PyArg_ParseTuple(args, "y*:inet_ntoa", &packed_ip)) { return NULL; } - if (addr_len != sizeof(packed_addr)) { + if (packed_ip.len != sizeof(packed_addr)) { PyErr_SetString(PyExc_OSError, "packed IP wrong length for inet_ntoa"); + PyBuffer_Release(&packed_ip); return NULL; } - memcpy(&packed_addr, packed_str, addr_len); + memcpy(&packed_addr, packed_ip.buf, packed_ip.len); + PyBuffer_Release(&packed_ip); return PyUnicode_FromString(inet_ntoa(packed_addr)); } @@ -5068,8 +5169,7 @@ static PyObject * socket_inet_ntop(PyObject *self, PyObject *args) { int af; - char* packed; - int len; + Py_buffer packed_ip; const char* retval; #ifdef ENABLE_IPV6 char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; @@ -5080,31 +5180,35 @@ socket_inet_ntop(PyObject *self, PyObject *args) /* Guarantee NUL-termination for PyUnicode_FromString() below */ memset((void *) &ip[0], '\0', sizeof(ip)); - if (!PyArg_ParseTuple(args, "iy#:inet_ntop", &af, &packed, &len)) { + if (!PyArg_ParseTuple(args, "iy*:inet_ntop", &af, &packed_ip)) { return NULL; } if (af == AF_INET) { - if (len != sizeof(struct in_addr)) { + if (packed_ip.len != sizeof(struct in_addr)) { PyErr_SetString(PyExc_ValueError, "invalid length of packed IP address string"); + PyBuffer_Release(&packed_ip); return NULL; } #ifdef ENABLE_IPV6 } else if (af == AF_INET6) { - if (len != sizeof(struct in6_addr)) { + if (packed_ip.len != sizeof(struct in6_addr)) { PyErr_SetString(PyExc_ValueError, "invalid length of packed IP address string"); + PyBuffer_Release(&packed_ip); return NULL; } #endif } else { PyErr_Format(PyExc_ValueError, "unknown address family %d", af); + PyBuffer_Release(&packed_ip); return NULL; } - retval = inet_ntop(af, packed, ip, sizeof(ip)); + retval = inet_ntop(af, packed_ip.buf, ip, sizeof(ip)); + PyBuffer_Release(&packed_ip); if (!retval) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -5123,8 +5227,7 @@ static PyObject * socket_inet_ntop(PyObject *self, PyObject *args) { int af; - char* packed; - int len; + Py_buffer packed_ip; struct sockaddr_in6 addr; DWORD addrlen, ret, retlen; #ifdef ENABLE_IPV6 @@ -5136,38 +5239,42 @@ socket_inet_ntop(PyObject *self, PyObject *args) /* Guarantee NUL-termination for PyUnicode_FromString() below */ memset((void *) &ip[0], '\0', sizeof(ip)); - if (!PyArg_ParseTuple(args, "iy#:inet_ntop", &af, &packed, &len)) { + if (!PyArg_ParseTuple(args, "iy*:inet_ntop", &af, &packed_ip)) { return NULL; } if (af == AF_INET) { struct sockaddr_in * addr4 = (struct sockaddr_in *)&addr; - if (len != sizeof(struct in_addr)) { + if (packed_ip.len != sizeof(struct in_addr)) { PyErr_SetString(PyExc_ValueError, "invalid length of packed IP address string"); + PyBuffer_Release(&packed_ip); return NULL; } memset(addr4, 0, sizeof(struct sockaddr_in)); addr4->sin_family = AF_INET; - memcpy(&(addr4->sin_addr), packed, sizeof(addr4->sin_addr)); + memcpy(&(addr4->sin_addr), packed_ip.buf, sizeof(addr4->sin_addr)); addrlen = sizeof(struct sockaddr_in); } else if (af == AF_INET6) { - if (len != sizeof(struct in6_addr)) { + if (packed_ip.len != sizeof(struct in6_addr)) { PyErr_SetString(PyExc_ValueError, "invalid length of packed IP address string"); + PyBuffer_Release(&packed_ip); return NULL; } memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; - memcpy(&(addr.sin6_addr), packed, sizeof(addr.sin6_addr)); + memcpy(&(addr.sin6_addr), packed_ip.buf, sizeof(addr.sin6_addr)); addrlen = sizeof(addr); } else { PyErr_Format(PyExc_ValueError, "unknown address family %d", af); + PyBuffer_Release(&packed_ip); return NULL; } + PyBuffer_Release(&packed_ip); retlen = sizeof(ip); ret = WSAAddressToStringA((struct sockaddr*)&addr, addrlen, NULL, @@ -5780,11 +5887,15 @@ PyInit__socket(void) #ifdef MS_WINDOWS if (support_wsa_no_inherit == -1) { +#if defined(_MSC_VER) && _MSC_VER >= 1800 + support_wsa_no_inherit = IsWindows7SP1OrGreater(); +#else DWORD version = GetVersion(); DWORD major = (DWORD)LOBYTE(LOWORD(version)); DWORD minor = (DWORD)HIBYTE(LOWORD(version)); /* need Windows 7 SP1, 2008 R2 SP1 or later */ - support_wsa_no_inherit = (major >= 6 && minor >= 1); + support_wsa_no_inherit = major > 6 || (major == 6 && minor >= 1); +#endif } #endif @@ -6183,6 +6294,9 @@ PyInit__socket(void) #ifdef SO_PRIORITY PyModule_AddIntMacro(m, SO_PRIORITY); #endif +#ifdef SO_MARK + PyModule_AddIntMacro(m, SO_MARK); +#endif /* Maximum number of connections for "listen" */ #ifdef SOMAXCONN |