Skip to main content

Modules/_socketmodule.c

cpython 3.14 @ ab2d84fe1023/Modules/_socketmodule.c

Modules/_socketmodule.c is the C extension that backs Python's socket module. It wraps BSD socket / Winsock2 system calls into PySocketSockObject, a Python object that holds a file descriptor and an address family. The module handles address family encoding, non-blocking connect/accept with the GIL released, and platform differences between POSIX and Windows.

Map

LinesSymbolRole
1-200includes, platform guardsOS detection, Winsock vs POSIX headers
201-600PySocketSockObjectSocket object struct and type object
601-1200address conversionsetipaddr, idna_converter, getsockaddrarg, getsockaddrlen
1201-2000sock_connect, sock_acceptConnect and accept with GIL-release retry loop
2001-3200sock_send, sock_recvSend/recv families with GIL-release and buffer protocol
3201-4500sock_setsockopt, sock_getsockoptSocket option get/set with type dispatch
4501-5500module-level functionsgetaddrinfo, getnameinfo, socketpair, setdefaulttimeout
5501-6800type and module initPySocketSock_Type, PyInit__socket

Reading

PySocketSockObject and timeout

Every socket object stores the file descriptor, address family, protocol, and a timeout value. A negative timeout means blocking; zero means non-blocking; positive means the select-then-call pattern.

// CPython: Modules/_socketmodule.c:210 PySocketSockObject
typedef struct {
PyObject_HEAD
SOCKET_T sock_fd;
int sock_family;
int sock_type;
int sock_proto;
PyObject *sock_timeout; /* stored as float seconds; None -> blocking */
} PySocketSockObject;

GIL-release pattern in sock_connect

Blocking socket calls release the GIL so other threads continue while the syscall waits. The pattern is Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS around the raw syscall.

// CPython: Modules/_socketmodule.c:1240 sock_connect_impl
static int
sock_connect_impl(PySocketSockObject *s, void* Py_UNUSED(data))
{
int res;
Py_BEGIN_ALLOW_THREADS
res = connect(s->sock_fd,
SAS2SA(&s->sock_addr.storage),
s->sock_addr.addrlen);
Py_END_ALLOW_THREADS
return res == 0;
}

For non-blocking sockets with a timeout, sock_connect calls select in a loop, checking for writability after each EINPROGRESS, releasing the GIL on each select call.

Address family encoding: getsockaddrarg

getsockaddrarg converts a Python address object into a sockaddr struct. It dispatches on s->sock_family, handling AF_INET (2-tuple), AF_INET6 (4-tuple), AF_UNIX (string path), and AF_BLUETOOTH family variants.

// CPython: Modules/_socketmodule.c:1380 getsockaddrarg AF_INET
case AF_INET: {
struct sockaddr_in* addr = &addrbuf->in;
char *hostp;
int port, result;
if (!PyTuple_Check(args) || !PyArg_ParseTuple(args, "eti:getsockaddrarg",
"idna", &hostp, &port))
return 0;
...

gopy notes

Not yet ported. The Go standard library's net package covers the high-level interface. A direct port of _socketmodule.c would target module/socket/, providing socket.socket objects with Connect, Accept, Send, Recv methods calling into syscall or golang.org/x/net. The GIL-release pattern maps naturally to goroutine scheduling.

CPython 3.14 changes

3.14 added socket.SOCK_NONBLOCK and socket.SOCK_CLOEXEC on Linux, and improved getaddrinfo to respect the system hosts file ordering more faithfully. The socket.create_connection helper gained a local_addr parameter for bind-before-connect.