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
| Architecture | Number | ABI | Entry point |
|---|---|---|---|
| x64 (x86_64) | 43 | common | sys_accept |
| ARM64 (aarch64) | 202 | — | sys_accept |
Kernel history
Introduced in Linux 1.0.
1.0
accept() has been part of Linux since 1.0 with BSD semantics.
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) = 4strace 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).