summaryrefslogtreecommitdiff
path: root/Modules/socketmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r--Modules/socketmodule.c384
1 files changed, 239 insertions, 145 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index e9feba378e..7c7cb7de6f 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,7 +685,7 @@ 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); \
} \
@@ -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,
@@ -1244,12 +1313,13 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
Py_INCREF(args);
if (!PyArg_Parse(args, "y#", &path, &len))
goto unix_out;
+ assert(len >= 0);
addr = (struct sockaddr_un*)addr_ret;
#ifdef linux
if (len > 0 && path[0] == 0) {
/* Linux abstract namespace extension */
- if (len > sizeof addr->sun_path) {
+ if ((size_t)len > sizeof addr->sun_path) {
PyErr_SetString(PyExc_OSError,
"AF_UNIX path too long");
goto unix_out;
@@ -1259,7 +1329,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
#endif /* linux */
{
/* regular NULL-terminated string */
- if (len >= sizeof addr->sun_path) {
+ if ((size_t)len >= sizeof addr->sun_path) {
PyErr_SetString(PyExc_OSError,
"AF_UNIX path too long");
goto unix_out;
@@ -1308,7 +1378,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 +1388,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 +1413,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 +1425,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) {
@@ -1611,7 +1681,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) {
@@ -1967,6 +2037,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 +2051,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 +2079,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)) {
@@ -2271,6 +2342,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 +2518,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 +2607,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 +2631,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 +2653,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 +2665,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 +2688,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 +2826,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 +2839,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 +2863,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 +3004,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 +3040,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 +3321,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 +3336,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 +3359,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 +3378,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 +3411,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) {
+ buf += n;
+ len -= n;
}
- if (n < 0) {
- /* If interrupted, try again */
- if (saved_errno == EINTR)
- continue;
- else
- break;
- }
- 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 +3446,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 +3481,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 +3506,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 +3538,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 +3696,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 +3882,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 +4313,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;
@@ -5780,11 +5867,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 +6274,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