gh-103092: Isolate `socket` module (#103094)

This commit is contained in:
Erlend E. Aasland 2023-04-09 03:03:52 +02:00 committed by GitHub
parent 35167043e3
commit f329a8bc1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 242 additions and 167 deletions

View File

@ -8,6 +8,7 @@ import _thread as thread
import array
import contextlib
import errno
import gc
import io
import itertools
import math
@ -836,6 +837,12 @@ def requireSocket(*args):
class GeneralModuleTests(unittest.TestCase):
@unittest.skipUnless(_socket is not None, 'need _socket module')
def test_socket_type(self):
self.assertTrue(gc.is_tracked(_socket.socket))
with self.assertRaisesRegex(TypeError, "immutable"):
_socket.socket.foo = 1
def test_SocketType_is_socketobject(self):
import _socket
self.assertTrue(socket.SocketType is _socket.socket)

View File

@ -0,0 +1 @@
Isolate :mod:`!_socket` (apply :pep:`687`). Patch by Erlend E. Aasland.

View File

@ -108,6 +108,7 @@ Local naming conventions:
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "pycore_fileutils.h" // _Py_set_inheritable()
#include "pycore_moduleobject.h" // _PyModule_GetState
#include "structmember.h" // PyMemberDef
#ifdef _Py_MEMORY_SANITIZER
@ -337,9 +338,9 @@ static FlagRuntimeInfo win_runtime_flags[] = {
/*[clinic input]
module _socket
class _socket.socket "PySocketSockObject *" "&sock_type"
class _socket.socket "PySocketSockObject *" "clinic_state()->sock_type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7a8313d9b7f51988]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2db2489bd2219fd8]*/
static int
remove_unusable_flags(PyObject *m)
@ -541,22 +542,59 @@ remove_unusable_flags(PyObject *m)
#define INADDR_NONE (-1)
#endif
typedef struct _socket_state {
/* The sock_type variable contains pointers to various functions,
some of which call new_sockobject(), which uses sock_type, so
there has to be a circular reference. */
PyTypeObject *sock_type;
/* Global variable holding the exception type for errors detected
by this module (but not argument type or memory errors, etc.). */
PyObject *socket_herror;
PyObject *socket_gaierror;
/* Default timeout for new sockets */
_PyTime_t defaulttimeout;
#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
int accept4_works;
#endif
#endif
#ifdef SOCK_CLOEXEC
/* socket() and socketpair() fail with EINVAL on Linux kernel older
* than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */
int sock_cloexec_works;
#endif
} socket_state;
static inline socket_state *
get_module_state(PyObject *mod)
{
void *state = _PyModule_GetState(mod);
assert(state != NULL);
return (socket_state *)state;
}
static struct PyModuleDef socketmodule;
static inline socket_state *
find_module_state_by_def(PyTypeObject *type)
{
PyObject *mod = PyType_GetModuleByDef(type, &socketmodule);
assert(mod != NULL);
return get_module_state(mod);
}
#define clinic_state() (find_module_state_by_def(type))
#include "clinic/socketmodule.c.h"
#undef clinic_state
/* XXX There's a problem here: *static* functions are not supposed to have
a Py prefix (or use CapitalizedWords). Later... */
/* Global variable holding the exception type for errors detected
by this module (but not argument type or memory errors, etc.). */
static PyObject *socket_herror;
static PyObject *socket_gaierror;
/* A forward reference to the socket type object.
The sock_type variable contains pointers to various functions,
some of which call new_sockobject(), which uses sock_type, so
there has to be a circular reference. */
static PyTypeObject sock_type;
#if defined(HAVE_POLL_H)
#include <poll.h>
#elif defined(HAVE_SYS_POLL_H)
@ -641,7 +679,7 @@ set_error(void)
#if defined(HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYNAME) || defined (HAVE_GETHOSTBYADDR)
static PyObject *
set_herror(int h_error)
set_herror(socket_state *state, int h_error)
{
PyObject *v;
@ -651,7 +689,7 @@ set_herror(int h_error)
v = Py_BuildValue("(is)", h_error, "host not found");
#endif
if (v != NULL) {
PyErr_SetObject(socket_herror, v);
PyErr_SetObject(state->socket_herror, v);
Py_DECREF(v);
}
@ -662,7 +700,7 @@ set_herror(int h_error)
#ifdef HAVE_GETADDRINFO
static PyObject *
set_gaierror(int error)
set_gaierror(socket_state *state, int error)
{
PyObject *v;
@ -678,7 +716,7 @@ set_gaierror(int error)
v = Py_BuildValue("(is)", error, "getaddrinfo failed");
#endif
if (v != NULL) {
PyErr_SetObject(socket_gaierror, v);
PyErr_SetObject(state->socket_gaierror, v);
Py_DECREF(v);
}
@ -991,11 +1029,8 @@ sock_call(PySocketSockObject *s,
/* Initialize a new socket object. */
/* Default timeout for new sockets */
static _PyTime_t defaulttimeout = _PYTIME_FROMSECONDS(-1);
static int
init_sockobject(PySocketSockObject *s,
init_sockobject(socket_state *state, PySocketSockObject *s,
SOCKET_T fd, int family, int type, int proto)
{
s->sock_fd = fd;
@ -1025,13 +1060,14 @@ init_sockobject(PySocketSockObject *s,
else
#endif
{
s->sock_timeout = defaulttimeout;
if (defaulttimeout >= 0) {
s->sock_timeout = state->defaulttimeout;
if (state->defaulttimeout >= 0) {
if (internal_setblocking(s, 0) == -1) {
return -1;
}
}
}
s->state = state;
return 0;
}
@ -1043,14 +1079,15 @@ init_sockobject(PySocketSockObject *s,
in NEWOBJ()). */
static PySocketSockObject *
new_sockobject(SOCKET_T fd, int family, int type, int proto)
new_sockobject(socket_state *state, SOCKET_T fd, int family, int type,
int proto)
{
PySocketSockObject *s;
s = (PySocketSockObject *)
PyType_GenericNew(&sock_type, NULL, NULL);
if (s == NULL)
PyTypeObject *tp = state->sock_type;
PySocketSockObject *s = (PySocketSockObject *)tp->tp_alloc(tp, 0);
if (s == NULL) {
return NULL;
if (init_sockobject(s, fd, family, type, proto) == -1) {
}
if (init_sockobject(state, s, fd, family, type, proto) == -1) {
Py_DECREF(s);
return NULL;
}
@ -1074,7 +1111,8 @@ static PyThread_type_lock netdb_lock;
an error occurred; then an exception is raised. */
static int
setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
setipaddr(socket_state *state, const char *name, struct sockaddr *addr_ret,
size_t addr_ret_size, int af)
{
struct addrinfo hints, *res;
int error;
@ -1095,7 +1133,7 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int
outcome of the first call. */
if (error) {
res = NULL; // no-op, remind us that it is invalid; gh-100795
set_gaierror(error);
set_gaierror(state, error);
return -1;
}
switch (res->ai_family) {
@ -1206,7 +1244,7 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int
Py_END_ALLOW_THREADS
if (error) {
res = NULL; // no-op, remind us that it is invalid; gh-100795
set_gaierror(error);
set_gaierror(state, error);
return -1;
}
if (res->ai_addrlen < addr_ret_size)
@ -1889,7 +1927,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 0;
}
struct sockaddr_in* addr = &addrbuf->in;
result = setipaddr(host.buf, (struct sockaddr *)addr,
result = setipaddr(s->state, host.buf, (struct sockaddr *)addr,
sizeof(*addr), AF_INET);
idna_cleanup(&host);
if (result < 0)
@ -1934,7 +1972,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 0;
}
struct sockaddr_in6* addr = &addrbuf->in6;
result = setipaddr(host.buf, (struct sockaddr *)addr,
result = setipaddr(s->state, host.buf, (struct sockaddr *)addr,
sizeof(*addr), AF_INET6);
idna_cleanup(&host);
if (result < 0)
@ -2813,10 +2851,6 @@ struct sock_accept {
};
#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
#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)
@ -2835,15 +2869,16 @@ sock_accept_impl(PySocketSockObject *s, void *data)
#endif
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
if (accept4_works != 0) {
socket_state *state = s->state;
if (state->accept4_works != 0) {
ctx->result = accept4(s->sock_fd, addr, paddrlen,
SOCK_CLOEXEC);
if (ctx->result == INVALID_SOCKET && accept4_works == -1) {
if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) {
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
accept4_works = (errno != ENOSYS);
state->accept4_works = (errno != ENOSYS);
}
}
if (accept4_works == 0)
if (state->accept4_works == 0)
ctx->result = accept(s->sock_fd, addr, paddrlen);
#else
ctx->result = accept(s->sock_fd, addr, paddrlen);
@ -2896,7 +2931,8 @@ sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
#else
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
if (!accept4_works)
socket_state *state = s->state;
if (!state->accept4_works)
#endif
{
if (_Py_set_inheritable(newfd, 0, NULL) < 0) {
@ -5219,13 +5255,23 @@ sock_finalize(PySocketSockObject *s)
PyErr_SetRaisedException(exc);
}
static int
sock_traverse(PySocketSockObject *s, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(s));
return 0;
}
static void
sock_dealloc(PySocketSockObject *s)
{
if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0)
if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) {
return;
Py_TYPE(s)->tp_free((PyObject *)s);
}
PyTypeObject *tp = Py_TYPE(s);
PyObject_GC_UnTrack(s);
tp->tp_free((PyObject *)s);
Py_DECREF(tp);
}
@ -5277,12 +5323,6 @@ sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
/* Initialize a new socket object. */
#ifdef SOCK_CLOEXEC
/* socket() and socketpair() fail with EINVAL on Linux kernel older
* than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */
static int sock_cloexec_works = -1;
#endif
/*ARGSUSED*/
#ifndef HAVE_SOCKET
@ -5310,10 +5350,11 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
{
SOCKET_T fd = INVALID_SOCKET;
socket_state *state = find_module_state_by_def(Py_TYPE(self));
#ifndef MS_WINDOWS
#ifdef SOCK_CLOEXEC
int *atomic_flag_works = &sock_cloexec_works;
int *atomic_flag_works = &state->sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
@ -5468,15 +5509,15 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
/* UNIX */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
if (sock_cloexec_works != 0) {
if (state->sock_cloexec_works != 0) {
fd = socket(family, type | SOCK_CLOEXEC, proto);
if (sock_cloexec_works == -1) {
if (state->sock_cloexec_works == -1) {
if (fd >= 0) {
sock_cloexec_works = 1;
state->sock_cloexec_works = 1;
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
sock_cloexec_works = 0;
state->sock_cloexec_works = 0;
fd = socket(family, type, proto);
}
}
@ -5499,7 +5540,7 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
}
#endif
}
if (init_sockobject(self, fd, family, type, proto) == -1) {
if (init_sockobject(state, self, fd, family, type, proto) == -1) {
SOCKETCLOSE(fd);
return -1;
}
@ -5511,55 +5552,26 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
/* Type object for socket objects. */
static PyTypeObject sock_type = {
PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */
"_socket.socket", /* tp_name */
sizeof(PySocketSockObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)sock_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
(reprfunc)sock_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
sock_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
sock_methods, /* tp_methods */
sock_memberlist, /* tp_members */
sock_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
sock_initobj, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
sock_new, /* tp_new */
PyObject_Del, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
0, /* tp_del */
0, /* tp_version_tag */
(destructor)sock_finalize, /* tp_finalize */
static PyType_Slot sock_slots[] = {
{Py_tp_dealloc, sock_dealloc},
{Py_tp_traverse, sock_traverse},
{Py_tp_repr, sock_repr},
{Py_tp_doc, (void *)sock_doc},
{Py_tp_methods, sock_methods},
{Py_tp_members, sock_memberlist},
{Py_tp_getset, sock_getsetlist},
{Py_tp_init, sock_initobj},
{Py_tp_new, sock_new},
{Py_tp_finalize, sock_finalize},
{0, NULL},
};
static PyType_Spec sock_spec = {
.name = "_socket.socket",
.basicsize = sizeof(PySocketSockObject),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = sock_slots,
};
@ -5687,8 +5699,12 @@ socket_gethostbyname(PyObject *self, PyObject *args)
if (PySys_Audit("socket.gethostbyname", "O", args) < 0) {
goto finally;
}
if (setipaddr(name, (struct sockaddr *)&addrbuf, sizeof(addrbuf), AF_INET) < 0)
socket_state *state = get_module_state(self);
int rc = setipaddr(state, name, (struct sockaddr *)&addrbuf,
sizeof(addrbuf), AF_INET);
if (rc < 0) {
goto finally;
}
ret = make_ipv4_addr(&addrbuf);
finally:
PyMem_Free(name);
@ -5719,7 +5735,8 @@ sock_decode_hostname(const char *name)
/* Convenience function common to gethostbyname_ex and gethostbyaddr */
static PyObject *
gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af)
gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr,
size_t alen, int af)
{
char **pch;
PyObject *rtn_tuple = (PyObject *)NULL;
@ -5730,7 +5747,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af)
if (h == NULL) {
/* Let's get real error message to return */
set_herror(h_errno);
set_herror(state, h_errno);
return NULL;
}
@ -5877,8 +5894,10 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
if (PySys_Audit("socket.gethostbyname", "O", args) < 0) {
goto finally;
}
if (setipaddr(name, SAS2SA(&addr), sizeof(addr), AF_INET) < 0)
socket_state *state = get_module_state(self);
if (setipaddr(state, name, SAS2SA(&addr), sizeof(addr), AF_INET) < 0) {
goto finally;
}
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_GETHOSTBYNAME_R
#if defined(HAVE_GETHOSTBYNAME_R_6_ARG)
@ -5904,7 +5923,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
Therefore, we cast the sockaddr_storage into sockaddr to
access sa_family. */
sa = SAS2SA(&addr);
ret = gethost_common(h, SAS2SA(&addr), sizeof(addr),
ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr),
sa->sa_family);
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(netdb_lock);
@ -5960,8 +5979,10 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
goto finally;
}
af = AF_UNSPEC;
if (setipaddr(ip_num, sa, sizeof(addr), af) < 0)
socket_state *state = get_module_state(self);
if (setipaddr(state, ip_num, sa, sizeof(addr), af) < 0) {
goto finally;
}
af = sa->sa_family;
ap = NULL;
/* al = 0; */
@ -6002,7 +6023,7 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
h = gethostbyaddr(ap, al, af);
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
ret = gethost_common(h, SAS2SA(&addr), sizeof(addr), af);
ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr), af);
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(netdb_lock);
#endif
@ -6221,8 +6242,9 @@ socket_socketpair(PyObject *self, PyObject *args)
SOCKET_T sv[2];
int family, type = SOCK_STREAM, proto = 0;
PyObject *res = NULL;
socket_state *state = get_module_state(self);
#ifdef SOCK_CLOEXEC
int *atomic_flag_works = &sock_cloexec_works;
int *atomic_flag_works = &state->sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
@ -6240,15 +6262,15 @@ socket_socketpair(PyObject *self, PyObject *args)
/* Create a pair of socket fds */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
if (sock_cloexec_works != 0) {
if (state->sock_cloexec_works != 0) {
ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv);
if (sock_cloexec_works == -1) {
if (state->sock_cloexec_works == -1) {
if (ret >= 0) {
sock_cloexec_works = 1;
state->sock_cloexec_works = 1;
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
sock_cloexec_works = 0;
state->sock_cloexec_works = 0;
ret = socketpair(family, type, proto, sv);
}
}
@ -6268,10 +6290,10 @@ socket_socketpair(PyObject *self, PyObject *args)
if (_Py_set_inheritable(sv[1], 0, atomic_flag_works) < 0)
goto finally;
s0 = new_sockobject(sv[0], family, type, proto);
s0 = new_sockobject(state, sv[0], family, type, proto);
if (s0 == NULL)
goto finally;
s1 = new_sockobject(sv[1], family, type, proto);
s1 = new_sockobject(state, sv[1], family, type, proto);
if (s1 == NULL)
goto finally;
res = PyTuple_Pack(2, s0, s1);
@ -6726,7 +6748,8 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
Py_END_ALLOW_THREADS
if (error) {
res0 = NULL; // gh-100795
set_gaierror(error);
socket_state *state = get_module_state(self);
set_gaierror(state, error);
goto err;
}
@ -6825,7 +6848,8 @@ socket_getnameinfo(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
if (error) {
res = NULL; // gh-100795
set_gaierror(error);
socket_state *state = get_module_state(self);
set_gaierror(state, error);
goto fail;
}
if (res->ai_next) {
@ -6857,7 +6881,8 @@ socket_getnameinfo(PyObject *self, PyObject *args)
error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags);
if (error) {
set_gaierror(error);
socket_state *state = get_module_state(self);
set_gaierror(state, error);
goto fail;
}
@ -6883,11 +6908,12 @@ Get host and port for a sockaddr.");
static PyObject *
socket_getdefaulttimeout(PyObject *self, PyObject *Py_UNUSED(ignored))
{
if (defaulttimeout < 0) {
socket_state *state = get_module_state(self);
if (state->defaulttimeout < 0) {
Py_RETURN_NONE;
}
else {
double seconds = _PyTime_AsSecondsDouble(defaulttimeout);
double seconds = _PyTime_AsSecondsDouble(state->defaulttimeout);
return PyFloat_FromDouble(seconds);
}
}
@ -6907,7 +6933,8 @@ socket_setdefaulttimeout(PyObject *self, PyObject *arg)
if (socket_parse_timeout(&timeout, arg) < 0)
return NULL;
defaulttimeout = timeout;
socket_state *state = get_module_state(self);
state->defaulttimeout = timeout;
Py_RETURN_NONE;
}
@ -7293,7 +7320,7 @@ sock_destroy_api(PyObject *capsule)
}
static PySocketModule_APIObject *
sock_get_api(void)
sock_get_api(socket_state *state)
{
PySocketModule_APIObject *capi = PyMem_Malloc(sizeof(PySocketModule_APIObject));
if (capi == NULL) {
@ -7301,7 +7328,7 @@ sock_get_api(void)
return NULL;
}
capi->Sock_Type = (PyTypeObject *)Py_NewRef(&sock_type);
capi->Sock_Type = (PyTypeObject *)Py_NewRef(state->sock_type);
capi->error = Py_NewRef(PyExc_OSError);
capi->timeout_error = Py_NewRef(PyExc_TimeoutError);
return capi;
@ -7323,47 +7350,38 @@ PyDoc_STRVAR(socket_doc,
\n\
See the socket module for documentation.");
static struct PyModuleDef socketmodule = {
PyModuleDef_HEAD_INIT,
PySocket_MODULE_NAME,
socket_doc,
-1,
socket_methods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__socket(void)
static int
socket_exec(PyObject *m)
{
PyObject *m = NULL;
if (!os_init()) {
goto error;
}
Py_SET_TYPE(&sock_type, &PyType_Type);
m = PyModule_Create(&socketmodule);
if (m == NULL) {
goto error;
}
socket_state *state = get_module_state(m);
state->defaulttimeout = _PYTIME_FROMSECONDS(-1);
#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
state->accept4_works = -1;
#endif
#endif
#ifdef SOCK_CLOEXEC
state->sock_cloexec_works = -1;
#endif
#define ADD_EXC(MOD, NAME, VAR, BASE) do { \
VAR = PyErr_NewException("socket." NAME, BASE, NULL); \
if (VAR == NULL) { \
goto error; \
} \
int rc = PyModule_AddObjectRef(MOD, NAME, VAR); \
Py_DECREF(VAR); \
if (rc < 0) { \
if (PyModule_AddObjectRef(MOD, NAME, VAR) < 0) { \
goto error; \
} \
} while (0)
ADD_EXC(m, "herror", socket_herror, PyExc_OSError);
ADD_EXC(m, "gaierror", socket_gaierror, PyExc_OSError);
ADD_EXC(m, "herror", state->socket_herror, PyExc_OSError);
ADD_EXC(m, "gaierror", state->socket_gaierror, PyExc_OSError);
#undef ADD_EXC
@ -7373,10 +7391,16 @@ PyInit__socket(void)
if (PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError) < 0) {
goto error;
}
if (PyModule_AddObjectRef(m, "SocketType", (PyObject *)&sock_type) < 0) {
PyObject *sock_type = PyType_FromMetaclass(NULL, m, &sock_spec, NULL);
if (sock_type == NULL) {
goto error;
}
if (PyModule_AddType(m, &sock_type) < 0) {
state->sock_type = (PyTypeObject *)sock_type;
if (PyModule_AddObjectRef(m, "SocketType", sock_type) < 0) {
goto error;
}
if (PyModule_AddType(m, state->sock_type) < 0) {
goto error;
}
@ -7391,7 +7415,7 @@ PyInit__socket(void)
}
/* Export C API */
PySocketModule_APIObject *capi = sock_get_api();
PySocketModule_APIObject *capi = sock_get_api(state);
if (capi == NULL) {
goto error;
}
@ -8813,9 +8837,57 @@ PyInit__socket(void)
#undef ADD_INT_CONST
#undef ADD_STR_CONST
return m;
return 0;
error:
Py_XDECREF(m);
return NULL;
return -1;
}
static struct PyModuleDef_Slot socket_slots[] = {
{Py_mod_exec, socket_exec},
{0, NULL},
};
static int
socket_traverse(PyObject *mod, visitproc visit, void *arg)
{
socket_state *state = get_module_state(mod);
Py_VISIT(state->sock_type);
Py_VISIT(state->socket_herror);
Py_VISIT(state->socket_gaierror);
return 0;
}
static int
socket_clear(PyObject *mod)
{
socket_state *state = get_module_state(mod);
Py_CLEAR(state->sock_type);
Py_CLEAR(state->socket_herror);
Py_CLEAR(state->socket_gaierror);
return 0;
}
static void
socket_free(void *mod)
{
(void)socket_clear((PyObject *)mod);
}
static struct PyModuleDef socketmodule = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = PySocket_MODULE_NAME,
.m_doc = socket_doc,
.m_size = sizeof(socket_state),
.m_methods = socket_methods,
.m_slots = socket_slots,
.m_traverse = socket_traverse,
.m_clear = socket_clear,
.m_free = socket_free,
};
PyMODINIT_FUNC
PyInit__socket(void)
{
return PyModuleDef_Init(&socketmodule);
}

View File

@ -322,6 +322,7 @@ typedef struct {
sets a Python exception */
_PyTime_t sock_timeout; /* Operation timeout in seconds;
0.0 means non-blocking */
struct _socket_state *state;
} PySocketSockObject;
/* --- C API ----------------------------------------------------*/

View File

@ -392,7 +392,6 @@ Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type -
Modules/_decimal/_decimal.c - PyDec_Type -
Modules/ossaudiodev.c - OSSAudioType -
Modules/ossaudiodev.c - OSSMixerType -
Modules/socketmodule.c - sock_type -
Modules/xxmodule.c - Null_Type -
Modules/xxmodule.c - Str_Type -
Modules/xxmodule.c - Xxo_Type -
@ -416,8 +415,6 @@ Modules/_cursesmodule.c - PyCursesError -
Modules/_decimal/_decimal.c - DecimalException -
Modules/_tkinter.c - Tkinter_TclError -
Modules/ossaudiodev.c - OSSAudioError -
Modules/socketmodule.c - socket_herror -
Modules/socketmodule.c - socket_gaierror -
Modules/xxlimited_35.c - ErrorObject -
Modules/xxmodule.c - ErrorObject -
@ -514,8 +511,6 @@ Modules/cjkcodecs/cjkcodecs.h - mapping_list -
Modules/readline.c - libedit_append_replace_history_offset -
Modules/readline.c - using_libedit_emulation -
Modules/readline.c - libedit_history_start -
Modules/socketmodule.c - accept4_works -
Modules/socketmodule.c - sock_cloexec_works -
##-----------------------
## state
@ -541,4 +536,3 @@ Modules/readline.c - sigwinch_ohandler -
Modules/readline.c - completed_input_string -
Modules/rotatingtree.c - random_stream -
Modules/rotatingtree.c - random_value -
Modules/socketmodule.c - defaulttimeout -

Can't render this file because it has a wrong number of fields in line 4.