Skip to content
/linux-syscalls

Network · Section 2

accept(2)

Pull the next pending connection off a listening socket's queue.

Signature

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen);
sockfd
Listening socket descriptor (previously listen()ed).
addr
If non-NULL, the kernel writes the peer's sockaddr here. Cast appropriately (sockaddr_in for INET, sockaddr_in6, sockaddr_un, …).
addrlen
Pointer to a socklen_t. In: size of the buffer. Out: size of the actual address (may be larger than the buffer — the address is truncated).

Description

accept() extracts the first pending connection from the queue of a listening socket and returns a new connected socket — a separate file descriptor that can be read/written like any other. The original listening sockfd is unchanged and continues to accept further connections. If the queue is empty and the socket is blocking, accept() blocks; if non-blocking it returns -1/EAGAIN. The peer address is written to *addr / *addrlen if non-NULL — addr can be NULL when you don't care. Prefer accept4() over accept() in new code: it lets you set SOCK_CLOEXEC and SOCK_NONBLOCK atomically at accept time, eliminating an fd-leak race window across execve().

Architecture mapping

ArchitectureNumberABIEntry point
x64 (x86_64)43commonsys_accept
ARM64 (aarch64)202sys_accept

Kernel history

Introduced in Linux 1.0.

  1. 1.0

    accept() has been part of Linux since 1.0 with BSD semantics.

  2. 2.6.28

    accept4() was added with explicit flags (SOCK_CLOEXEC, SOCK_NONBLOCK) so callers can set those on the new socket atomically, closing race windows that previously required a separate fcntl().

seccomp & containers

Docker default profile

Allowed

Podman default profile

Allowed

accept() / accept4() are on every default profile. As with other socket-API calls, there's no useful argument-filter — the upstream socket() and bind() filters define the surface. For workloads that should never be a server (one-shot init containers, batch jobs), denying accept() / accept4() at the seccomp layer is a small belt-and-braces over also denying listen().

libseccomp

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept),  0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4), 0);

strace example

$ strace -e accept,accept4 nc -l 127.0.0.1 1234
accept4(3, {sa_family=AF_INET, sin_port=htons(57338), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_CLOEXEC) = 4

strace shows the peer address decoded (sin_port, sin_addr). For a misbehaving server, a long-running accept() with no return is a stuck-on-EAGAIN-and-not-polling pattern; an instant ECONNABORTED return rate points at client-side TLS handshake failures upstream. -e network filters to the family.

Security & observability

accept() returning new connected sockets is the canonical entry point for any incoming network traffic. eBPF tracepoint sys_exit_accept fires with the new fd; correlating to the peer sockaddr (from the same call) gives instant attribution of every connection — used by Falco, Tracee, and most container EDRs. fd-exhaustion attacks (the 'slowloris' family) starve the accept loop; monitoring EMFILE / ENFILE return rate is the canary. The double-close-on-accept race that haunted multi-threaded servers in the 2000s is mitigated by always using accept4(SOCK_CLOEXEC).

Errors

EAGAIN
The socket is non-blocking and no connections are queued. Wait via poll/epoll for POLLIN before retrying.
EBADF
ECONNABORTED
A queued connection was aborted before accept() could pick it up (the client RST'd or timed out).
EINTR
Interrupted by a signal before a connection arrived.
EINVAL
EMFILE
Per-process fd limit reached — common cause of mysterious 'server stops accepting' on busy hosts. Raise RLIMIT_NOFILE.
ENFILE
System-wide fd limit reached.
ENOTSOCK
EOPNOTSUPP
EPERM
EPROTO
Protocol-level error (e.g. TLS-ish glitches when a kernel offload module is involved).

Related syscalls