#include "pycore_fileutils.h" // _Py_set_inheritable()
#include "pycore_moduleobject.h" // _PyModule_GetState
#include "pycore_time.h" // _PyTime_AsMilliseconds()
+#include "pycore_pyatomic_ft_wrappers.h"
#ifdef _Py_MEMORY_SANITIZER
# include <sanitizer/msan_interface.h>
#endif
} socket_state;
+static inline void
+set_sock_fd(PySocketSockObject *s, SOCKET_T fd)
+{
+#ifdef Py_GIL_DISABLED
+#if SIZEOF_SOCKET_T == SIZEOF_INT
+ _Py_atomic_store_int_relaxed((int *)&s->sock_fd, (int)fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG
+ _Py_atomic_store_long_relaxed((long *)&s->sock_fd, (long)fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG
+ _Py_atomic_store_llong_relaxed((long long *)&s->sock_fd, (long long)fd);
+#else
+ #error "Unsupported SIZEOF_SOCKET_T"
+#endif
+#else
+ s->sock_fd = fd;
+#endif
+}
+
+static inline SOCKET_T
+get_sock_fd(PySocketSockObject *s)
+{
+#ifdef Py_GIL_DISABLED
+#if SIZEOF_SOCKET_T == SIZEOF_INT
+ return (SOCKET_T)_Py_atomic_load_int_relaxed((int *)&s->sock_fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG
+ return (SOCKET_T)_Py_atomic_load_long_relaxed((long *)&s->sock_fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG
+ return (SOCKET_T)_Py_atomic_load_llong_relaxed((long long *)&s->sock_fd);
+#else
+ #error "Unsupported SIZEOF_SOCKET_T"
+#endif
+#else
+ return s->sock_fd;
+#endif
+}
+
static inline socket_state *
get_module_state(PyObject *mod)
{
#ifndef MS_WINDOWS
#if (defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO))
block = !block;
- if (ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block) == -1)
+ if (ioctl(get_sock_fd(s), FIONBIO, (unsigned int *)&block) == -1)
goto done;
#else
- delay_flag = fcntl(s->sock_fd, F_GETFL, 0);
+ delay_flag = fcntl(get_sock_fd(s), F_GETFL, 0);
if (delay_flag == -1)
goto done;
if (block)
else
new_delay_flag = delay_flag | O_NONBLOCK;
if (new_delay_flag != delay_flag)
- if (fcntl(s->sock_fd, F_SETFL, new_delay_flag) == -1)
+ if (fcntl(get_sock_fd(s), F_SETFL, new_delay_flag) == -1)
goto done;
#endif
#else /* MS_WINDOWS */
arg = !block;
- if (ioctlsocket(s->sock_fd, FIONBIO, &arg) != 0)
+ if (ioctlsocket(get_sock_fd(s), FIONBIO, &arg) != 0)
goto done;
#endif /* MS_WINDOWS */
assert(!(connect && !writing));
/* Guard against closed socket */
- if (s->sock_fd == INVALID_SOCKET)
+ if (get_sock_fd(s) == INVALID_SOCKET)
return 0;
/* Prefer poll, if available, since you can poll() any fd
* which can't be done with select(). */
#ifdef HAVE_POLL
- pollfd.fd = s->sock_fd;
+ pollfd.fd = get_sock_fd(s);
pollfd.events = writing ? POLLOUT : POLLIN;
if (connect) {
/* On Windows, the socket becomes writable on connection success,
tvp = NULL;
FD_ZERO(&fds);
- FD_SET(s->sock_fd, &fds);
+ FD_SET(get_sock_fd(s), &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);
+ FD_SET(get_sock_fd(s), &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),
+ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int),
NULL, &fds, &efds, tvp);
else
- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
+ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int),
&fds, NULL, &efds, tvp);
Py_END_ALLOW_THREADS;
#endif
init_sockobject(socket_state *state, PySocketSockObject *s,
SOCKET_T fd, int family, int type, int proto)
{
- s->sock_fd = fd;
+ set_sock_fd(s, fd);
s->sock_family = family;
s->sock_type = type;
}
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) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
PyBuffer_Release(&haddr);
return 0;
} 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) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
Py_DECREF(interfaceName);
return 0;
} 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) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
Py_DECREF(interfaceName);
return 0;
} 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) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
Py_DECREF(interfaceName);
return 0;
sizeof(info.ctl_name));
Py_DECREF(ctl_name);
- if (ioctl(s->sock_fd, CTLIOCGINFO, &info)) {
+ if (ioctl(get_sock_fd(s), CTLIOCGINFO, &info)) {
PyErr_SetString(PyExc_OSError,
"cannot find kernel control with provided name");
return 0;
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
socket_state *state = s->state;
if (state->accept4_works != 0) {
- ctx->result = accept4(s->sock_fd, addr, paddrlen,
+ ctx->result = accept4(get_sock_fd(s), addr, paddrlen,
SOCK_CLOEXEC);
if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) {
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
}
}
if (state->accept4_works == 0)
- ctx->result = accept(s->sock_fd, addr, paddrlen);
+ ctx->result = accept(get_sock_fd(s), addr, paddrlen);
#else
- ctx->result = accept(s->sock_fd, addr, paddrlen);
+ ctx->result = accept(get_sock_fd(s), addr, paddrlen);
#endif
#ifdef MS_WINDOWS
goto finally;
}
- addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
+ addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf),
addrlen, s->sock_proto);
if (addr == NULL)
goto finally;
if (PyArg_ParseTuple(args, "iiK:setsockopt",
&level, &optname, &vflag)) {
// level should always be set to AF_VSOCK
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
(void*)&vflag, sizeof vflag);
goto done;
}
#ifdef MS_WINDOWS
if (optname == SIO_TCP_SET_ACK_FREQUENCY) {
int dummy;
- res = WSAIoctl(s->sock_fd, SIO_TCP_SET_ACK_FREQUENCY, &flag,
+ res = WSAIoctl(get_sock_fd(s), SIO_TCP_SET_ACK_FREQUENCY, &flag,
sizeof(flag), NULL, 0, &dummy, NULL, NULL);
if (res >= 0) {
s->quickack = flag;
goto done;
}
#endif
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
(char*)&flag, sizeof flag);
goto done;
}
if (PyArg_ParseTuple(args, "iiO!I:setsockopt",
&level, &optname, Py_TYPE(Py_None), &none, &optlen)) {
assert(sizeof(socklen_t) >= sizeof(unsigned int));
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
NULL, (socklen_t)optlen);
goto done;
}
INT_MAX);
return NULL;
}
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
optval.buf, (int)optval.len);
#else
- res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len);
+ res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len);
#endif
PyBuffer_Release(&optval);
if (s->sock_family == AF_VSOCK) {
uint64_t vflag = 0; // Must be set width of 64 bits
flagsize = sizeof vflag;
- res = getsockopt(s->sock_fd, level, optname,
+ res = getsockopt(get_sock_fd(s), level, optname,
(void *)&vflag, &flagsize);
if (res < 0)
return s->errorhandler();
}
#endif
flagsize = sizeof flag;
- res = getsockopt(s->sock_fd, level, optname,
+ res = getsockopt(get_sock_fd(s), level, optname,
(void *)&flag, &flagsize);
if (res < 0)
return s->errorhandler();
buf = PyBytes_FromStringAndSize((char *)NULL, buflen);
if (buf == NULL)
return NULL;
- res = getsockopt(s->sock_fd, level, optname,
+ res = getsockopt(get_sock_fd(s), level, optname,
(void *)PyBytes_AS_STRING(buf), &buflen);
if (res < 0) {
Py_DECREF(buf);
}
Py_BEGIN_ALLOW_THREADS
- res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen);
+ res = bind(get_sock_fd(s), SAS2SA(&addrbuf), addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
SOCKET_T fd;
int res;
- fd = s->sock_fd;
+ fd = get_sock_fd(s);
if (fd != INVALID_SOCKET) {
- s->sock_fd = INVALID_SOCKET;
+ set_sock_fd(s, INVALID_SOCKET);
/* We do not want to retry upon EINTR: see
http://lwn.net/Articles/576478/ and
static PyObject *
sock_detach(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
{
- SOCKET_T fd = s->sock_fd;
- s->sock_fd = INVALID_SOCKET;
+ SOCKET_T fd = get_sock_fd(s);
+ set_sock_fd(s, INVALID_SOCKET);
return PyLong_FromSocket_t(fd);
}
int err;
socklen_t size = sizeof err;
- if (getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, (void *)&err, &size)) {
+ if (getsockopt(get_sock_fd(s), SOL_SOCKET, SO_ERROR, (void *)&err, &size)) {
/* getsockopt() failed */
return 0;
}
int res, err, wait_connect;
Py_BEGIN_ALLOW_THREADS
- res = connect(s->sock_fd, addr, addrlen);
+ res = connect(get_sock_fd(s), addr, addrlen);
Py_END_ALLOW_THREADS
if (!res) {
static PyObject *
sock_fileno(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
{
- return PyLong_FromSocket_t(s->sock_fd);
+ return PyLong_FromSocket_t(get_sock_fd(s));
}
PyDoc_STRVAR(fileno_doc,
return NULL;
memset(&addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
- res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+ res = getsockname(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen,
s->sock_proto);
}
return NULL;
memset(&addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
- res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+ res = getpeername(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen,
s->sock_proto);
}
* (which doesn't make sense anyway) we force a minimum value of 0. */
if (backlog < 0)
backlog = 0;
- res = listen(s->sock_fd, backlog);
+ res = listen(get_sock_fd(s), backlog);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
#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);
+ ctx->result = recv(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags);
#else
- ctx->result = recv(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags);
+ ctx->result = recv(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags);
#endif
return (ctx->result >= 0);
}
#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,
+ ctx->result = recvfrom(get_sock_fd(s), 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,
+ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags,
SAS2SA(ctx->addrbuf), ctx->addrlen);
#endif
return (ctx->result >= 0);
if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0)
return -1;
- *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ *addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen,
s->sock_proto);
if (*addr == NULL)
return -1;
{
struct sock_recvmsg *ctx = data;
- ctx->result = recvmsg(s->sock_fd, ctx->msg, ctx->flags);
+ ctx->result = recvmsg(get_sock_fd(s), ctx->msg, ctx->flags);
return (ctx->result >= 0);
}
(*makeval)(ctx.result, makeval_data),
cmsg_list,
(int)msg.msg_flags,
- makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
+ makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf),
((msg.msg_namelen > addrbuflen) ?
addrbuflen : msg.msg_namelen),
s->sock_proto));
#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);
+ ctx->result = send(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags);
#else
- ctx->result = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags);
+ ctx->result = send(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags);
#endif
return (ctx->result >= 0);
}
#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,
+ ctx->result = sendto(get_sock_fd(s), 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,
+ ctx->result = sendto(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags,
SAS2SA(ctx->addrbuf), ctx->addrlen);
#endif
return (ctx->result >= 0);
{
struct sock_sendmsg *ctx = data;
- ctx->result = sendmsg(s->sock_fd, ctx->msg, ctx->flags);
+ ctx->result = sendmsg(get_sock_fd(s), ctx->msg, ctx->flags);
return (ctx->result >= 0);
}
if (how == -1 && PyErr_Occurred())
return NULL;
Py_BEGIN_ALLOW_THREADS
- res = shutdown(s->sock_fd, how);
+ res = shutdown(get_sock_fd(s), how);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
unsigned int option = RCVALL_ON;
if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option))
return NULL;
- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option),
+ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option),
NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
return set_error();
}
if (!PyArg_ParseTuple(arg, "k(kkk):ioctl", &cmd,
&ka.onoff, &ka.keepalivetime, &ka.keepaliveinterval))
return NULL;
- if (WSAIoctl(s->sock_fd, cmd, &ka, sizeof(ka),
+ if (WSAIoctl(get_sock_fd(s), cmd, &ka, sizeof(ka),
NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
return set_error();
}
unsigned int option;
if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option))
return NULL;
- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option),
+ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option),
NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
return set_error();
}
return NULL;
Py_BEGIN_ALLOW_THREADS
- result = WSADuplicateSocketW(s->sock_fd, processId, &info);
+ result = WSADuplicateSocketW(get_sock_fd(s), processId, &info);
Py_END_ALLOW_THREADS
if (result == SOCKET_ERROR)
return set_error();
/* Save the current exception, if any. */
PyObject *exc = PyErr_GetRaisedException();
- if (s->sock_fd != INVALID_SOCKET) {
+ if (get_sock_fd(s) != INVALID_SOCKET) {
if (PyErr_ResourceWarning((PyObject *)s, 1, "unclosed %R", s)) {
/* Spurious errors can appear at shutdown */
if (PyErr_ExceptionMatches(PyExc_Warning)) {
to allow the logger to call socket methods like
socket.getsockname(). If the socket is closed before, socket
methods fails with the EBADF error. */
- fd = s->sock_fd;
- s->sock_fd = INVALID_SOCKET;
+ fd = get_sock_fd(s);
+ set_sock_fd(s, INVALID_SOCKET);
/* We do not want to retry upon EINTR: see sock_close() */
Py_BEGIN_ALLOW_THREADS
{
long sock_fd;
/* On Windows, this test is needed because SOCKET_T is unsigned */
- if (s->sock_fd == INVALID_SOCKET) {
+ if (get_sock_fd(s) == INVALID_SOCKET) {
sock_fd = -1;
}
#if SIZEOF_SOCKET_T > SIZEOF_LONG
- else if (s->sock_fd > LONG_MAX) {
+ else if (get_sock_fd(s) > LONG_MAX) {
/* this can occur on Win64, and actually there is a special
ugly printf formatter for decimal pointer length integer
printing, only bother if necessary*/
}
#endif
else
- sock_fd = (long)s->sock_fd;
+ sock_fd = (long)get_sock_fd(s);
return PyUnicode_FromFormat(
"<socket object, fd=%ld, family=%d, type=%d, proto=%d>",
sock_fd, s->sock_family,