summaryrefslogtreecommitdiffstats
path: root/Modules/socketmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r--Modules/socketmodule.c1314
1 files changed, 806 insertions, 508 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index b6f2bf5..7610b0c 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
@@ -459,7 +460,7 @@ static PyTypeObject sock_type;
#else
/* If there's no timeout left, we don't have to call select, so it's a safe,
* little white lie. */
-#define IS_SELECTABLE(s) (_PyIsSelectable_fd((s)->sock_fd) || (s)->sock_timeout <= 0.0)
+#define IS_SELECTABLE(s) (_PyIsSelectable_fd((s)->sock_fd) || (s)->sock_timeout <= 0)
#endif
static PyObject*
@@ -481,6 +482,19 @@ select_error(void)
#endif
#ifdef MS_WINDOWS
+# define GET_SOCK_ERROR WSAGetLastError()
+# define SET_SOCK_ERROR(err) WSASetLastError(err)
+# define SOCK_TIMEOUT_ERR WSAEWOULDBLOCK
+# define SOCK_INPROGRESS_ERR WSAEWOULDBLOCK
+#else
+# define GET_SOCK_ERROR errno
+# define SET_SOCK_ERROR(err) do { errno = err; } while (0)
+# define SOCK_TIMEOUT_ERR EWOULDBLOCK
+# define SOCK_INPROGRESS_ERR EINPROGRESS
+#endif
+
+
+#ifdef MS_WINDOWS
/* Does WSASocket() support the WSA_FLAG_NO_HANDLE_INHERIT flag? */
static int support_wsa_no_inherit = -1;
#endif
@@ -552,6 +566,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 +595,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
@@ -587,60 +604,79 @@ internal_setblocking(PySocketSockObject *s, int block)
return 1;
}
-/* Do a select()/poll() on the socket, if necessary (sock_timeout > 0).
- The argument writing indicates the direction.
- This does not raise an exception; we'll let our caller do that
- after they've reacquired the interpreter lock.
- Returns 1 on timeout, -1 on error, 0 otherwise. */
static int
-internal_select_ex(PySocketSockObject *s, int writing, double interval)
+internal_select(PySocketSockObject *s, int writing, _PyTime_t interval,
+ int connect)
{
int n;
+#ifdef HAVE_POLL
+ struct pollfd pollfd;
+ _PyTime_t ms;
+#else
+ fd_set fds, efds;
+ struct timeval tv, *tvp;
+#endif
- /* Nothing to do unless we're in timeout mode (not non-blocking) */
- if (s->sock_timeout <= 0.0)
- return 0;
+#ifdef WITH_THREAD
+ /* must be called with the GIL held */
+ assert(PyGILState_Check());
+#endif
+
+ /* Error condition is for output only */
+ assert(!(connect && !writing));
/* Guard against closed socket */
if (s->sock_fd < 0)
return 0;
- /* Handling this condition here simplifies the select loops */
- if (interval < 0.0)
- return 1;
-
/* Prefer poll, if available, since you can poll() any fd
* which can't be done with select(). */
#ifdef HAVE_POLL
- {
- struct pollfd pollfd;
- int timeout;
+ pollfd.fd = s->sock_fd;
+ pollfd.events = writing ? POLLOUT : POLLIN;
+ if (connect) {
+ /* On Windows, the socket becomes writable on connection success,
+ but a connection failure is notified as an error. On POSIX, the
+ socket becomes writable on connection success or on connection
+ failure. */
+ pollfd.events |= POLLERR;
+ }
- pollfd.fd = s->sock_fd;
- pollfd.events = writing ? POLLOUT : POLLIN;
+ /* s->sock_timeout is in seconds, timeout in ms */
+ ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING);
+ assert(ms <= INT_MAX);
- /* s->sock_timeout is in seconds, timeout in ms */
- timeout = (int)(interval * 1000 + 0.5);
- n = poll(&pollfd, 1, timeout);
- }
+ Py_BEGIN_ALLOW_THREADS;
+ n = poll(&pollfd, 1, (int)ms);
+ Py_END_ALLOW_THREADS;
#else
- {
- /* Construct the arguments to select */
- fd_set fds;
- struct timeval tv;
- tv.tv_sec = (int)interval;
- tv.tv_usec = (int)((interval - tv.tv_sec) * 1e6);
- FD_ZERO(&fds);
- FD_SET(s->sock_fd, &fds);
-
- /* See if the socket is ready */
- if (writing)
- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
- NULL, &fds, NULL, &tv);
- else
- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
- &fds, NULL, NULL, &tv);
+ if (interval >= 0) {
+ _PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING);
+ tvp = &tv;
}
+ else
+ tvp = NULL;
+
+ FD_ZERO(&fds);
+ FD_SET(s->sock_fd, &fds);
+ FD_ZERO(&efds);
+ if (connect) {
+ /* On Windows, the socket becomes writable on connection success,
+ but a connection failure is notified as an error. On POSIX, the
+ socket becomes writable on connection success or on connection
+ failure. */
+ FD_SET(s->sock_fd, &efds);
+ }
+
+ /* See if the socket is ready */
+ Py_BEGIN_ALLOW_THREADS;
+ if (writing)
+ n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
+ NULL, &fds, &efds, tvp);
+ else
+ n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
+ &fds, NULL, &efds, tvp);
+ Py_END_ALLOW_THREADS;
#endif
if (n < 0)
@@ -650,56 +686,166 @@ internal_select_ex(PySocketSockObject *s, int writing, double interval)
return 0;
}
+/* Call a socket function.
+
+ On error, raise an exception and return -1 if err is set, or fill err and
+ return -1 otherwise. If a signal was received and the signal handler raised
+ an exception, return -1, and set err to -1 if err is set.
+
+ On success, return 0, and set err to 0 if err is set.
+
+ If the socket has a timeout, wait until the socket is ready before calling
+ the function: wait until the socket is writable if writing is nonzero, wait
+ until the socket received data otherwise.
+
+ If the socket function is interrupted by a signal (failed with EINTR): retry
+ the function, except if the signal handler raised an exception (PEP 475).
+
+ When the function is retried, recompute the timeout using a monotonic clock.
+
+ sock_call_ex() must be called with the GIL held. The socket function is
+ called with the GIL released. */
static int
-internal_select(PySocketSockObject *s, int writing)
+sock_call_ex(PySocketSockObject *s,
+ int writing,
+ int (*sock_func) (PySocketSockObject *s, void *data),
+ void *data,
+ int connect,
+ int *err,
+ _PyTime_t timeout)
{
- return internal_select_ex(s, writing, s->sock_timeout);
-}
+ int has_timeout = (timeout > 0);
+ _PyTime_t deadline = 0;
+ int deadline_initialized = 0;
+ int res;
-/*
- Two macros for automatic retry of select() in case of false positives
- (for example, select() could indicate a socket is ready for reading
- but the data then discarded by the OS because of a wrong checksum).
- Here is an example of use:
+ /* sock_call() must be called with the GIL held. */
+ assert(PyGILState_Check());
+
+ /* outer loop to retry select() when select() is interrupted by a signal
+ or to retry select()+sock_func() on false positive (see above) */
+ while (1) {
+ /* For connect(), poll even for blocking socket. The connection
+ runs asynchronously. */
+ if (has_timeout || connect) {
+ if (has_timeout) {
+ _PyTime_t interval;
+
+ if (deadline_initialized) {
+ /* recompute the timeout */
+ interval = deadline - _PyTime_GetMonotonicClock();
+ }
+ else {
+ deadline_initialized = 1;
+ deadline = _PyTime_GetMonotonicClock() + timeout;
+ interval = timeout;
+ }
- BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS
- timeout = internal_select_ex(s, 0, interval);
- if (!timeout)
- outlen = recv(s->sock_fd, cbuf, len, flags);
- Py_END_ALLOW_THREADS
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
+ if (interval >= 0)
+ res = internal_select(s, writing, interval, connect);
+ else
+ res = 1;
+ }
+ else {
+ res = internal_select(s, writing, timeout, connect);
+ }
+
+ if (res == -1) {
+ if (err)
+ *err = GET_SOCK_ERROR;
+
+ if (CHECK_ERRNO(EINTR)) {
+ /* select() was interrupted by a signal */
+ if (PyErr_CheckSignals()) {
+ if (err)
+ *err = -1;
+ return -1;
+ }
+
+ /* retry select() */
+ continue;
+ }
+
+ /* select() failed */
+ s->errorhandler();
+ return -1;
+ }
+
+ if (res == 1) {
+ if (err)
+ *err = SOCK_TIMEOUT_ERR;
+ else
+ PyErr_SetString(socket_timeout, "timed out");
+ return -1;
+ }
+
+ /* the socket is ready */
+ }
+
+ /* inner loop to retry sock_func() when sock_func() is interrupted
+ by a signal */
+ while (1) {
+ Py_BEGIN_ALLOW_THREADS
+ res = sock_func(s, data);
+ Py_END_ALLOW_THREADS
+
+ if (res) {
+ /* sock_func() succeeded */
+ if (err)
+ *err = 0;
+ return 0;
+ }
+
+ if (err)
+ *err = GET_SOCK_ERROR;
+
+ if (!CHECK_ERRNO(EINTR))
+ break;
+
+ /* sock_func() was interrupted by a signal */
+ if (PyErr_CheckSignals()) {
+ if (err)
+ *err = -1;
+ return -1;
+ }
+
+ /* retry sock_func() */
+ }
+
+ if (s->sock_timeout > 0
+ && (CHECK_ERRNO(EWOULDBLOCK) || CHECK_ERRNO(EAGAIN))) {
+ /* False positive: sock_func() failed with EWOULDBLOCK or EAGAIN.
+
+ For example, select() could indicate a socket is ready for
+ reading, but the data then discarded by the OS because of a
+ wrong checksum.
+
+ Loop on select() to recheck for socket readyness. */
+ continue;
+ }
+
+ /* sock_func() failed */
+ if (!err)
+ s->errorhandler();
+ /* else: err was already set before */
return -1;
}
- END_SELECT_LOOP(s)
-*/
+}
+
+static int
+sock_call(PySocketSockObject *s,
+ int writing,
+ int (*func) (PySocketSockObject *s, void *data),
+ void *data)
+{
+ return sock_call_ex(s, writing, func, data, 0, NULL, s->sock_timeout);
+}
-#define BEGIN_SELECT_LOOP(s) \
- { \
- _PyTime_timeval now, deadline = {0, 0}; \
- double interval = s->sock_timeout; \
- int has_timeout = s->sock_timeout > 0.0; \
- if (has_timeout) { \
- _PyTime_gettimeofday(&now); \
- deadline = now; \
- _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \
- } \
- while (1) { \
- errno = 0; \
-
-#define END_SELECT_LOOP(s) \
- if (!has_timeout || \
- (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \
- break; \
- _PyTime_gettimeofday(&now); \
- interval = _PyTime_INTERVAL(now, deadline); \
- } \
- } \
/* Initialize a new socket object. */
-static double defaulttimeout = -1.0; /* Default timeout for new sockets */
+/* Default timeout for new sockets */
+static _PyTime_t defaulttimeout = _PYTIME_FROMSECONDS(-1);
static void
init_sockobject(PySocketSockObject *s,
@@ -713,12 +859,12 @@ init_sockobject(PySocketSockObject *s,
s->errorhandler = &set_error;
#ifdef SOCK_NONBLOCK
if (type & SOCK_NONBLOCK)
- s->sock_timeout = 0.0;
+ s->sock_timeout = 0;
else
#endif
{
s->sock_timeout = defaulttimeout;
- if (defaulttimeout >= 0.0)
+ if (defaulttimeout >= 0)
internal_setblocking(s, 0);
}
@@ -1214,6 +1360,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 +1441,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 +1452,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 +1472,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 +1522,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 +1532,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 +1557,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 +1569,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 +1706,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 +1716,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 +1746,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 +1830,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 +1880,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 +2115,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
@@ -1955,22 +2181,51 @@ get_cmsg_data_len(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *data_len)
#endif /* CMSG_LEN */
+struct sock_accept {
+ socklen_t *addrlen;
+ sock_addr_t *addrbuf;
+ SOCKET_T result;
+};
+
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
+static int accept4_works = -1;
+#endif
+
+static int
+sock_accept_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_accept *ctx = data;
+
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+ if (accept4_works != 0) {
+ ctx->result = accept4(s->sock_fd, SAS2SA(ctx->addrbuf), ctx->addrlen,
+ SOCK_CLOEXEC);
+ if (ctx->result == INVALID_SOCKET && accept4_works == -1) {
+ /* On Linux older than 2.6.28, accept4() fails with ENOSYS */
+ accept4_works = (errno != ENOSYS);
+ }
+ }
+ if (accept4_works == 0)
+ ctx->result = accept(s->sock_fd, SAS2SA(ctx->addrbuf), ctx->addrlen);
+#else
+ ctx->result = accept(s->sock_fd, SAS2SA(ctx->addrbuf), ctx->addrlen);
+#endif
+ return (ctx->result >= 0);
+}
+
/* s._accept() -> (fd, address) */
static PyObject *
sock_accept(PySocketSockObject *s)
{
sock_addr_t addrbuf;
- SOCKET_T newfd = INVALID_SOCKET;
+ SOCKET_T newfd;
socklen_t addrlen;
PyObject *sock = NULL;
PyObject *addr = NULL;
PyObject *res = NULL;
- int timeout;
-#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
- static int accept4_works = -1;
-#endif
+ struct sock_accept ctx;
if (!getsockaddrlen(s, &addrlen))
return NULL;
@@ -1979,36 +2234,11 @@ sock_accept(PySocketSockObject *s)
if (!IS_SELECTABLE(s))
return select_error();
- BEGIN_SELECT_LOOP(s)
-
- 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 = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
-#else
- newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
-#endif
- }
- Py_END_ALLOW_THREADS
-
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
+ ctx.addrlen = &addrlen;
+ ctx.addrbuf = &addrbuf;
+ if (sock_call(s, 0, sock_accept_impl, &ctx) < 0)
return NULL;
- }
- END_SELECT_LOOP(s)
-
- if (newfd == INVALID_SOCKET)
- return s->errorhandler();
+ newfd = ctx.result;
#ifdef MS_WINDOWS
if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
@@ -2069,7 +2299,7 @@ sock_setblocking(PySocketSockObject *s, PyObject *arg)
if (block == -1 && PyErr_Occurred())
return NULL;
- s->sock_timeout = block ? -1.0 : 0.0;
+ s->sock_timeout = _PyTime_FromSeconds(block ? -1 : 0);
internal_setblocking(s, block);
Py_INCREF(Py_None);
@@ -2083,6 +2313,47 @@ Set the socket to blocking (flag is true) or non-blocking (false).\n\
setblocking(True) is equivalent to settimeout(None);\n\
setblocking(False) is equivalent to settimeout(0.0).");
+static int
+socket_parse_timeout(_PyTime_t *timeout, PyObject *timeout_obj)
+{
+#ifdef MS_WINDOWS
+ struct timeval tv;
+#endif
+#ifndef HAVE_POLL
+ _PyTime_t ms;
+#endif
+ int overflow = 0;
+
+ if (timeout_obj == Py_None) {
+ *timeout = _PyTime_FromSeconds(-1);
+ return 0;
+ }
+
+ if (_PyTime_FromSecondsObject(timeout,
+ timeout_obj, _PyTime_ROUND_CEILING) < 0)
+ return -1;
+
+ if (*timeout < 0) {
+ PyErr_SetString(PyExc_ValueError, "Timeout value out of range");
+ return -1;
+ }
+
+#ifdef MS_WINDOWS
+ overflow |= (_PyTime_AsTimeval(*timeout, &tv, _PyTime_ROUND_CEILING) < 0);
+#endif
+#ifndef HAVE_POLL
+ ms = _PyTime_AsMilliseconds(*timeout, _PyTime_ROUND_CEILING);
+ overflow |= (ms > INT_MAX);
+#endif
+ if (overflow) {
+ PyErr_SetString(PyExc_OverflowError,
+ "timeout doesn't fit into C timeval");
+ return -1;
+ }
+
+ return 0;
+}
+
/* s.settimeout(timeout) method. Argument:
None -- no timeout, blocking mode; same as setblocking(True)
0.0 -- non-blocking mode; same as setblocking(False)
@@ -2092,22 +2363,13 @@ setblocking(False) is equivalent to settimeout(0.0).");
static PyObject *
sock_settimeout(PySocketSockObject *s, PyObject *arg)
{
- double timeout;
+ _PyTime_t timeout;
- if (arg == Py_None)
- timeout = -1.0;
- else {
- timeout = PyFloat_AsDouble(arg);
- if (timeout < 0.0) {
- if (!PyErr_Occurred())
- PyErr_SetString(PyExc_ValueError,
- "Timeout value out of range");
- return NULL;
- }
- }
+ if (socket_parse_timeout(&timeout, arg) < 0)
+ return NULL;
s->sock_timeout = timeout;
- internal_setblocking(s, timeout < 0.0);
+ internal_setblocking(s, timeout < 0);
Py_INCREF(Py_None);
return Py_None;
@@ -2126,12 +2388,14 @@ Setting a timeout of zero is the same as setblocking(0).");
static PyObject *
sock_gettimeout(PySocketSockObject *s)
{
- if (s->sock_timeout < 0.0) {
+ if (s->sock_timeout < 0) {
Py_INCREF(Py_None);
return Py_None;
}
- else
- return PyFloat_FromDouble(s->sock_timeout);
+ else {
+ double seconds = _PyTime_AsSecondsDouble(s->sock_timeout);
+ return PyFloat_FromDouble(seconds);
+ }
}
PyDoc_STRVAR(gettimeout_doc,
@@ -2152,22 +2416,22 @@ 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,
+ (char*)&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 +2535,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
@@ -2302,92 +2570,90 @@ The object cannot be used after this call, but the file descriptor\n\
can be reused for other purposes. The file descriptor is returned.");
static int
+sock_connect_impl(PySocketSockObject *s, void* Py_UNUSED(data))
+{
+ int err;
+ socklen_t size = sizeof err;
+
+ if (getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, (void *)&err, &size)) {
+ /* getsockopt() failed */
+ return 0;
+ }
+
+ if (err == EISCONN)
+ return 1;
+ if (err != 0) {
+ /* sock_call_ex() uses GET_SOCK_ERROR() to get the error code */
+ SET_SOCK_ERROR(err);
+ return 0;
+ }
+ return 1;
+}
+
+static int
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
- int *timeoutp)
+ int raise)
{
- int res, timeout;
+ int res, err, wait_connect;
- timeout = 0;
+ Py_BEGIN_ALLOW_THREADS
res = connect(s->sock_fd, addr, addrlen);
+ Py_END_ALLOW_THREADS
-#ifdef MS_WINDOWS
-
- if (s->sock_timeout > 0.0) {
- if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK &&
- IS_SELECTABLE(s)) {
- /* This is a mess. Best solution: trust select */
- fd_set fds;
- fd_set fds_exc;
- struct timeval tv;
- tv.tv_sec = (int)s->sock_timeout;
- tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
- FD_ZERO(&fds);
- FD_SET(s->sock_fd, &fds);
- FD_ZERO(&fds_exc);
- FD_SET(s->sock_fd, &fds_exc);
- res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
- NULL, &fds, &fds_exc, &tv);
- if (res == 0) {
- res = WSAEWOULDBLOCK;
- timeout = 1;
- } else if (res > 0) {
- if (FD_ISSET(s->sock_fd, &fds))
- /* The socket is in the writable set - this
- means connected */
- res = 0;
- else {
- /* As per MS docs, we need to call getsockopt()
- to get the underlying error */
- int res_size = sizeof res;
- /* It must be in the exception set */
- assert(FD_ISSET(s->sock_fd, &fds_exc));
- if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
- (char *)&res, &res_size))
- /* getsockopt also clears WSAGetLastError,
- so reset it back. */
- WSASetLastError(res);
- else
- res = WSAGetLastError();
- }
- }
- /* else if (res < 0) an error occurred */
- }
+ if (!res) {
+ /* connect() succeeded, the socket is connected */
+ return 0;
}
- if (res < 0)
- res = WSAGetLastError();
+ /* connect() failed */
-#else
+ /* save error, PyErr_CheckSignals() can replace it */
+ err = GET_SOCK_ERROR;
+ if (CHECK_ERRNO(EINTR)) {
+ if (PyErr_CheckSignals())
+ return -1;
- if (s->sock_timeout > 0.0) {
- if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
- timeout = internal_select(s, 1);
- if (timeout == 0) {
- /* Bug #1019808: in case of an EINPROGRESS,
- use getsockopt(SO_ERROR) to get the real
- error. */
- socklen_t res_size = sizeof res;
- (void)getsockopt(s->sock_fd, SOL_SOCKET,
- SO_ERROR, &res, &res_size);
- if (res == EISCONN)
- res = 0;
- errno = res;
- }
- else if (timeout == -1) {
- res = errno; /* had error */
- }
- else
- res = EWOULDBLOCK; /* timed out */
- }
- }
+ /* Issue #23618: when connect() fails with EINTR, the connection is
+ running asynchronously.
- if (res < 0)
- res = errno;
+ If the socket is blocking or has a timeout, wait until the
+ connection completes, fails or timed out using select(), and then
+ get the connection status using getsockopt(SO_ERROR).
-#endif
- *timeoutp = timeout;
+ If the socket is non-blocking, raise InterruptedError. The caller is
+ responsible to wait until the connection completes, fails or timed
+ out (it's the case in asyncio for example). */
+ wait_connect = (s->sock_timeout != 0 && IS_SELECTABLE(s));
+ }
+ else {
+ wait_connect = (s->sock_timeout > 0 && err == SOCK_INPROGRESS_ERR
+ && IS_SELECTABLE(s));
+ }
- return res;
+ if (!wait_connect) {
+ if (raise) {
+ /* restore error, maybe replaced by PyErr_CheckSignals() */
+ SET_SOCK_ERROR(err);
+ s->errorhandler();
+ return -1;
+ }
+ else
+ return err;
+ }
+
+ if (raise) {
+ /* socket.connect() raises an exception on error */
+ if (sock_call_ex(s, 1, sock_connect_impl, NULL,
+ 1, NULL, s->sock_timeout) < 0)
+ return -1;
+ }
+ else {
+ /* socket.connect_ex() returns the error code on error */
+ if (sock_call_ex(s, 1, sock_connect_impl, NULL,
+ 1, &err, s->sock_timeout) < 0)
+ return err;
+ }
+ return 0;
}
/* s.connect(sockaddr) method */
@@ -2398,23 +2664,15 @@ sock_connect(PySocketSockObject *s, PyObject *addro)
sock_addr_t addrbuf;
int addrlen;
int res;
- int timeout;
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
- Py_END_ALLOW_THREADS
-
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
+ res = internal_connect(s, SAS2SA(&addrbuf), addrlen, 1);
+ if (res < 0)
return NULL;
- }
- if (res != 0)
- return s->errorhandler();
- Py_INCREF(Py_None);
- return Py_None;
+
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(connect_doc,
@@ -2432,21 +2690,13 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro)
sock_addr_t addrbuf;
int addrlen;
int res;
- int timeout;
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
- Py_END_ALLOW_THREADS
-
- /* Signals are not errors (though they may raise exceptions). Adapted
- from PyErr_SetFromErrnoWithFilenameObject(). */
-#ifdef EINTR
- if (res == EINTR && PyErr_CheckSignals())
+ res = internal_connect(s, SAS2SA(&addrbuf), addrlen, 0);
+ if (res < 0)
return NULL;
-#endif
return PyLong_FromLong((long) res);
}
@@ -2534,14 +2784,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 +2808,34 @@ 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.");
+
+struct sock_recv {
+ char *cbuf;
+ Py_ssize_t len;
+ int flags;
+ Py_ssize_t result;
+};
+
+static int
+sock_recv_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_recv *ctx = data;
+
+#ifdef MS_WINDOWS
+ if (ctx->len > INT_MAX)
+ ctx->len = INT_MAX;
+ ctx->result = recv(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags);
+#else
+ ctx->result = recv(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags);
+#endif
+ return (ctx->result >= 0);
+}
/*
@@ -2576,8 +2850,7 @@ connections.");
static Py_ssize_t
sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
{
- Py_ssize_t outlen = -1;
- int timeout;
+ struct sock_recv ctx;
if (!IS_SELECTABLE(s)) {
select_error();
@@ -2588,32 +2861,13 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
return 0;
}
- BEGIN_SELECT_LOOP(s)
- 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);
-#else
- outlen = recv(s->sock_fd, cbuf, len, flags);
-#endif
- }
- Py_END_ALLOW_THREADS
-
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
- return -1;
- }
- END_SELECT_LOOP(s)
- if (outlen < 0) {
- /* Note: the call to errorhandler() ALWAYS indirectly returned
- NULL, so ignore its return value */
- s->errorhandler();
+ ctx.cbuf = cbuf;
+ ctx.len = len;
+ ctx.flags = flags;
+ if (sock_call(s, 0, sock_recv_impl, &ctx) < 0)
return -1;
- }
- return outlen;
+
+ return ctx.result;
}
@@ -2727,6 +2981,34 @@ is not specified (or 0), receive up to the size available in the given buffer.\n
\n\
See recv() for documentation about the flags.");
+struct sock_recvfrom {
+ char* cbuf;
+ Py_ssize_t len;
+ int flags;
+ socklen_t *addrlen;
+ sock_addr_t *addrbuf;
+ Py_ssize_t result;
+};
+
+static int
+sock_recvfrom_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_recvfrom *ctx = data;
+
+ memset(ctx->addrbuf, 0, *ctx->addrlen);
+
+#ifdef MS_WINDOWS
+ if (ctx->len > INT_MAX)
+ ctx->len = INT_MAX;
+ ctx->result = recvfrom(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags,
+ SAS2SA(ctx->addrbuf), ctx->addrlen);
+#else
+ ctx->result = recvfrom(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags,
+ SAS2SA(ctx->addrbuf), ctx->addrlen);
+#endif
+ return (ctx->result >= 0);
+}
+
/*
* This is the guts of the recvfrom() and recvfrom_into() methods, which reads
@@ -2744,9 +3026,8 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
PyObject** addr)
{
sock_addr_t addrbuf;
- int timeout;
- Py_ssize_t n = -1;
socklen_t addrlen;
+ struct sock_recvfrom ctx;
*addr = NULL;
@@ -2758,38 +3039,20 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
return -1;
}
- BEGIN_SELECT_LOOP(s)
- 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);
-#else
- n = recvfrom(s->sock_fd, cbuf, len, flags,
- SAS2SA(&addrbuf), &addrlen);
-#endif
- }
- Py_END_ALLOW_THREADS
-
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
+ ctx.cbuf = cbuf;
+ ctx.len = len;
+ ctx.flags = flags;
+ ctx.addrbuf = &addrbuf;
+ ctx.addrlen = &addrlen;
+ if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0)
return -1;
- }
- END_SELECT_LOOP(s)
- if (n < 0) {
- s->errorhandler();
- return -1;
- }
- if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
- addrlen, s->sock_proto)))
+ *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ s->sock_proto);
+ if (*addr == NULL)
return -1;
- return n;
+ return ctx.result;
}
/* s.recvfrom(nbytes [,flags]) method */
@@ -2900,10 +3163,24 @@ PyDoc_STRVAR(recvfrom_into_doc,
\n\
Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.");
-
/* The sendmsg() and recvmsg[_into]() methods require a working
CMSG_LEN(). See the comment near get_CMSG_LEN(). */
#ifdef CMSG_LEN
+struct sock_recvmsg {
+ struct msghdr *msg;
+ int flags;
+ ssize_t result;
+};
+
+static int
+sock_recvmsg_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_recvmsg *ctx = data;
+
+ ctx->result = recvmsg(s->sock_fd, ctx->msg, ctx->flags);
+ return (ctx->result >= 0);
+}
+
/*
* Call recvmsg() with the supplied iovec structures, flags, and
* ancillary data buffer size (controllen). Returns the tuple return
@@ -2919,8 +3196,6 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
int flags, Py_ssize_t controllen,
PyObject *(*makeval)(ssize_t, void *), void *makeval_data)
{
- ssize_t bytes_received = -1;
- int timeout;
sock_addr_t addrbuf;
socklen_t addrbuflen;
struct msghdr msg = {0};
@@ -2929,6 +3204,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
struct cmsghdr *cmsgh;
size_t cmsgdatalen = 0;
int cmsg_status;
+ struct sock_recvmsg ctx;
/* XXX: POSIX says that msg_name and msg_namelen "shall be
ignored" when the socket is connected (Linux fills them in
@@ -2955,28 +3231,17 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
goto finally;
}
- 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;
- }
- END_SELECT_LOOP(s)
- if (bytes_received < 0) {
- s->errorhandler();
+ ctx.msg = &msg;
+ ctx.flags = flags;
+ if (sock_call(s, 0, sock_recvmsg_impl, &ctx) < 0)
goto finally;
- }
/* Make list of (level, type, data) tuples from control messages. */
if ((cmsg_list = PyList_New(0)) == NULL)
@@ -3018,7 +3283,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
}
retval = Py_BuildValue("NOiN",
- (*makeval)(bytes_received, makeval_data),
+ (*makeval)(ctx.result, makeval_data),
cmsg_list,
(int)msg.msg_flags,
makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
@@ -3226,15 +3491,36 @@ SCM_RIGHTS mechanism.");
#endif /* CMSG_LEN */
+struct sock_send {
+ char *buf;
+ Py_ssize_t len;
+ int flags;
+ Py_ssize_t result;
+};
+
+static int
+sock_send_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_send *ctx = data;
+
+#ifdef MS_WINDOWS
+ if (ctx->len > INT_MAX)
+ ctx->len = INT_MAX;
+ ctx->result = send(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags);
+#else
+ ctx->result = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags);
+#endif
+ return (ctx->result >= 0);
+}
+
/* s.send(data [,flags]) method */
static PyObject *
sock_send(PySocketSockObject *s, PyObject *args)
{
- char *buf;
- Py_ssize_t len, n = -1;
- int flags = 0, timeout;
+ int flags = 0;
Py_buffer pbuf;
+ struct sock_send ctx;
if (!PyArg_ParseTuple(args, "y*|i:send", &pbuf, &flags))
return NULL;
@@ -3243,33 +3529,16 @@ sock_send(PySocketSockObject *s, PyObject *args)
PyBuffer_Release(&pbuf);
return select_error();
}
- buf = pbuf.buf;
- len = pbuf.len;
-
- BEGIN_SELECT_LOOP(s)
- 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);
-#else
- n = send(s->sock_fd, buf, len, flags);
-#endif
- }
- Py_END_ALLOW_THREADS
- if (timeout == 1) {
+ ctx.buf = pbuf.buf;
+ ctx.len = pbuf.len;
+ ctx.flags = flags;
+ if (sock_call(s, 1, sock_send_impl, &ctx) < 0) {
PyBuffer_Release(&pbuf);
- PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
- END_SELECT_LOOP(s)
-
PyBuffer_Release(&pbuf);
- if (n < 0)
- return s->errorhandler();
- return PyLong_FromSsize_t(n);
+
+ return PyLong_FromSsize_t(ctx.result);
}
PyDoc_STRVAR(send_doc,
@@ -3286,9 +3555,15 @@ static PyObject *
sock_sendall(PySocketSockObject *s, PyObject *args)
{
char *buf;
- Py_ssize_t len, n = -1;
- int flags = 0, timeout, saved_errno;
+ Py_ssize_t len, n;
+ int flags = 0;
Py_buffer pbuf;
+ struct sock_send ctx;
+ int has_timeout = (s->sock_timeout > 0);
+ _PyTime_t interval = s->sock_timeout;
+ _PyTime_t deadline = 0;
+ int deadline_initialized = 0;
+ PyObject *res = NULL;
if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
return NULL;
@@ -3301,50 +3576,47 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
}
do {
- Py_BEGIN_ALLOW_THREADS
- timeout = internal_select(s, 1);
- n = -1;
- if (!timeout) {
-#ifdef MS_WINDOWS
- 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);
-#endif
- }
- Py_END_ALLOW_THREADS
- if (timeout == 1) {
- PyBuffer_Release(&pbuf);
- PyErr_SetString(socket_timeout, "timed out");
- return NULL;
+ if (has_timeout) {
+ if (deadline_initialized) {
+ /* recompute the timeout */
+ interval = deadline - _PyTime_GetMonotonicClock();
+ }
+ else {
+ deadline_initialized = 1;
+ deadline = _PyTime_GetMonotonicClock() + s->sock_timeout;
+ }
+
+ if (interval <= 0) {
+ PyErr_SetString(socket_timeout, "timed out");
+ goto done;
+ }
}
- /* PyErr_CheckSignals() might change errno */
- saved_errno = errno;
+
+ ctx.buf = buf;
+ ctx.len = len;
+ ctx.flags = flags;
+ if (sock_call_ex(s, 1, sock_send_impl, &ctx, 0, NULL, interval) < 0)
+ goto done;
+ n = ctx.result;
+ assert(n >= 0);
+
+ buf += n;
+ len -= n;
+
/* 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;
- }
- buf += n;
- len -= n;
+ if (PyErr_CheckSignals())
+ goto done;
} while (len > 0);
PyBuffer_Release(&pbuf);
- if (n < 0)
- return s->errorhandler();
-
Py_INCREF(Py_None);
- return Py_None;
+ res = Py_None;
+
+done:
+ PyBuffer_Release(&pbuf);
+ return res;
}
PyDoc_STRVAR(sendall_doc,
@@ -3356,6 +3628,32 @@ until all data is sent. If an error occurs, it's impossible\n\
to tell how much data has been sent.");
+struct sock_sendto {
+ char *buf;
+ Py_ssize_t len;
+ int flags;
+ int addrlen;
+ sock_addr_t *addrbuf;
+ Py_ssize_t result;
+};
+
+static int
+sock_sendto_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_sendto *ctx = data;
+
+#ifdef MS_WINDOWS
+ if (ctx->len > INT_MAX)
+ ctx->len = INT_MAX;
+ ctx->result = sendto(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags,
+ SAS2SA(ctx->addrbuf), ctx->addrlen);
+#else
+ ctx->result = sendto(s->sock_fd, ctx->buf, ctx->len, ctx->flags,
+ SAS2SA(ctx->addrbuf), ctx->addrlen);
+#endif
+ return (ctx->result >= 0);
+}
+
/* s.sendto(data, [flags,] sockaddr) method */
static PyObject *
@@ -3363,11 +3661,10 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
{
Py_buffer pbuf;
PyObject *addro;
- char *buf;
- Py_ssize_t len, arglen;
+ Py_ssize_t arglen;
sock_addr_t addrbuf;
- int addrlen, flags, timeout;
- Py_ssize_t n = -1;
+ int addrlen, flags;
+ struct sock_sendto ctx;
flags = 0;
arglen = PyTuple_Size(args);
@@ -3388,9 +3685,6 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
if (PyErr_Occurred())
return NULL;
- buf = pbuf.buf;
- len = pbuf.len;
-
if (!IS_SELECTABLE(s)) {
PyBuffer_Release(&pbuf);
return select_error();
@@ -3401,32 +3695,18 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
return NULL;
}
- BEGIN_SELECT_LOOP(s)
- 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);
-#else
- n = sendto(s->sock_fd, buf, len, flags,
- SAS2SA(&addrbuf), addrlen);
-#endif
- }
- Py_END_ALLOW_THREADS
-
- if (timeout == 1) {
+ ctx.buf = pbuf.buf;
+ ctx.len = pbuf.len;
+ ctx.flags = flags;
+ ctx.addrlen = addrlen;
+ ctx.addrbuf = &addrbuf;
+ if (sock_call(s, 1, sock_sendto_impl, &ctx) < 0) {
PyBuffer_Release(&pbuf);
- PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
- END_SELECT_LOOP(s)
PyBuffer_Release(&pbuf);
- if (n < 0)
- return s->errorhandler();
- return PyLong_FromSsize_t(n);
+
+ return PyLong_FromSsize_t(ctx.result);
}
PyDoc_STRVAR(sendto_doc,
@@ -3439,6 +3719,21 @@ For IP sockets, the address is a pair (hostaddr, port).");
/* The sendmsg() and recvmsg[_into]() methods require a working
CMSG_LEN(). See the comment near get_CMSG_LEN(). */
#ifdef CMSG_LEN
+struct sock_sendmsg {
+ struct msghdr *msg;
+ int flags;
+ ssize_t result;
+};
+
+static int
+sock_sendmsg_impl(PySocketSockObject *s, void *data)
+{
+ struct sock_sendmsg *ctx = data;
+
+ ctx->result = sendmsg(s->sock_fd, ctx->msg, ctx->flags);
+ return (ctx->result >= 0);
+}
+
/* s.sendmsg(buffers[, ancdata[, flags[, address]]]) method */
static PyObject *
@@ -3456,10 +3751,10 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
} *cmsgs = NULL;
void *controlbuf = NULL;
size_t controllen, controllen_last;
- ssize_t bytes_sent = -1;
- int addrlen, timeout, flags = 0;
+ int addrlen, flags = 0;
PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL,
*cmsg_fast = NULL, *retval = NULL;
+ struct sock_sendmsg ctx;
if (!PyArg_ParseTuple(args, "O|OiO:sendmsg",
&data_arg, &cmsg_arg, &flags, &addr_arg))
@@ -3613,23 +3908,12 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
goto finally;
}
- 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");
+ ctx.msg = &msg;
+ ctx.flags = flags;
+ if (sock_call(s, 1, sock_sendmsg_impl, &ctx) < 0)
goto finally;
- }
- END_SELECT_LOOP(s)
- if (bytes_sent < 0) {
- s->errorhandler();
- goto finally;
- }
- retval = PyLong_FromSsize_t(bytes_sent);
+ retval = PyLong_FromSsize_t(ctx.result);
finally:
PyMem_Free(controlbuf);
@@ -3796,7 +4080,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},
@@ -3838,10 +4122,14 @@ static PyMemberDef sock_memberlist[] = {
{"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, "the socket family"},
{"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, "the socket type"},
{"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, "the socket protocol"},
- {"timeout", T_DOUBLE, offsetof(PySocketSockObject, sock_timeout), READONLY, "the socket timeout"},
{0},
};
+static PyGetSetDef sock_getsetlist[] = {
+ {"timeout", (getter)sock_gettimeout, NULL, PyDoc_STR("the socket timeout")},
+ {NULL} /* sentinel */
+};
+
/* Deallocate a socket object in response to the last Py_DECREF().
First close the file description. */
@@ -3905,7 +4193,7 @@ sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
new = type->tp_alloc(type, 0);
if (new != NULL) {
((PySocketSockObject *)new)->sock_fd = -1;
- ((PySocketSockObject *)new)->sock_timeout = -1.0;
+ ((PySocketSockObject *)new)->sock_timeout = _PyTime_FromSeconds(-1);
((PySocketSockObject *)new)->errorhandler = &set_error;
}
return new;
@@ -4088,7 +4376,7 @@ static PyTypeObject sock_type = {
0, /* tp_iternext */
sock_methods, /* tp_methods */
sock_memberlist, /* tp_members */
- 0, /* tp_getset */
+ sock_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
@@ -4227,7 +4515,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;
@@ -4944,21 +5232,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));
}
@@ -5069,8 +5358,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];
@@ -5081,31 +5369,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;
@@ -5124,8 +5416,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
@@ -5137,38 +5428,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,
@@ -5405,12 +5700,14 @@ Get host and port for a sockaddr.");
static PyObject *
socket_getdefaulttimeout(PyObject *self)
{
- if (defaulttimeout < 0.0) {
+ if (defaulttimeout < 0) {
Py_INCREF(Py_None);
return Py_None;
}
- else
- return PyFloat_FromDouble(defaulttimeout);
+ else {
+ double seconds = _PyTime_AsSecondsDouble(defaulttimeout);
+ return PyFloat_FromDouble(seconds);
+ }
}
PyDoc_STRVAR(getdefaulttimeout_doc,
@@ -5423,19 +5720,10 @@ When the socket module is first imported, the default is None.");
static PyObject *
socket_setdefaulttimeout(PyObject *self, PyObject *arg)
{
- double timeout;
+ _PyTime_t timeout;
- if (arg == Py_None)
- timeout = -1.0;
- else {
- timeout = PyFloat_AsDouble(arg);
- if (timeout < 0.0) {
- if (!PyErr_Occurred())
- PyErr_SetString(PyExc_ValueError,
- "Timeout value out of range");
- return NULL;
- }
- }
+ if (socket_parse_timeout(&timeout, arg) < 0)
+ return NULL;
defaulttimeout = timeout;
@@ -5782,11 +6070,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
@@ -6185,6 +6477,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
@@ -6322,6 +6617,9 @@ PyInit__socket(void)
PyModule_AddIntMacro(m, CAN_RAW_LOOPBACK);
PyModule_AddIntMacro(m, CAN_RAW_RECV_OWN_MSGS);
#endif
+#ifdef HAVE_LINUX_CAN_RAW_FD_FRAMES
+ PyModule_AddIntMacro(m, CAN_RAW_FD_FRAMES);
+#endif
#ifdef HAVE_LINUX_CAN_BCM_H
PyModule_AddIntMacro(m, CAN_BCM);
PyModule_AddIntConstant(m, "CAN_BCM_TX_SETUP", TX_SETUP);