Dev Docs Architecture Overview

Netatalk Architecture Overview

Audited against Netatalk d63155e13 on 2026-10-10. This describes the current source checkout; older releases may differ.

Source tree

Directory Responsibility
etc/afpd AFP listener, session workers, command handlers, directory and metadata caches
etc/netatalk Controller, service supervision, Zeroconf registration
etc/uams Dynamically loaded authentication modules
etc/spotlight CNID, Localsearch, and Xapian search backends
libatalk Shared protocol, AppleDouble, CNID, Unicode, VFS, ACL, and utility code
include/atalk Shared structures and API declarations
bin Utilities, including dbd, nad, and afppasswd
test Unit tests, AFP command tests, integration scripts, and fuzzing
doc Manual, man pages, and generated developer documentation inputs

Build selection starts in meson.build and meson_options.txt. A source file’s presence does not mean every build includes it.

Process Model

netatalk supervises the afpd parent. The parent accepts DSI connections and forks a worker for each connection. Each worker owns its authentication state, open forks, mounted volumes, and caches. AppleTalk-enabled builds also provide AFP over ASP.

flowchart TD
    controller[netatalk controller] --> parent[afpd listener and IPC relay]
    client[AFP client] -->|TCP port 548 by default| parent
    parent -->|fork| worker[afpd session worker]
    worker --> filesystem[Filesystem and AppleDouble storage]
    worker --> sqlite[Embedded SQLite CNID]
    worker --> mysql[Optional external MySQL server]
    worker -->|control and cache hints| parent
    parent -->|hint pipe| worker
    controller -.->|Localsearch volumes only| dbus[Private D-Bus session]
Role Entry points and source
Controller main(), run_afpd(), timer_impl() in etc/netatalk/netatalk.c
AFP parent main(), dsi_start() in etc/afpd/main.c
Session creation dsi_getsession() in libatalk/dsi/dsi_getsess.c; accept/fork in libatalk/dsi/dsi_tcp.c
DSI worker afp_over_dsi() in etc/afpd/afp_dsi.c
AFP dispatch preauth_switch, postauth_switch, afp_switch in etc/afpd/switch.c
ASP worker afp_over_asp() in etc/afpd/afp_asp.c, built with AppleTalk support

Event loops and signals

The controller supports libevent or libev, selected by the Meson with-eventloop option (auto prefers libevent). Shared behavior resides in sigterm_impl(), sigquit_impl(), sighup_impl(), sigchld_impl(), and timer_impl(); library-specific callbacks wrap these functions.

The AFP parent uses poll() for listeners, child IPC, and the optional afpstats Unix socket. It reaps dead children before processing descriptors or flushing hints. Pending hints select a 50 ms poll timeout; otherwise the parent blocks indefinitely. This is a batching interval, not an unconditional 50 ms delivery deadline: more descriptor activity can postpone a timeout flush.

The DSI worker polls the client socket, hint pipe, and signal self-pipe. Signal handlers record requests and wake the loop; process_deferred_signals() performs session actions in main-loop context. The idle worker receives a temporary cache-access grant while the main thread waits in poll().

See AFP Daemon, Controller Daemon, and Network Protocols.

Session data and IPC

Structure Definition Ownership
AFPObj / struct afp_options include/atalk/globals.h Server/session context and parsed options
DSI include/atalk/dsi.h Transport buffers, socket, timer, session flags
server_child_t / afp_child_t include/atalk/server_child.h Parent’s PID-indexed child table and reconnect state
struct vol include/atalk/volume.h Volume configuration and per-session runtime handles
struct dir / struct path include/atalk/directory.h Cached identity, path, stat, and AppleDouble state
struct ofork etc/afpd/fork.h Open AFP fork reference, shared AppleDouble handle, virtual-fork state
struct adouble include/atalk/adouble.h Fork descriptors, parsed metadata, locks, reference counts

Each DSI worker has a bidirectional Unix socketpair for control and a parent-to-child hint pipe. The control protocol includes IPC_SESSIONTOKEN for an opaque reconnect token, in addition to login, state, volumes, client identity, reconnect, and cache-hint messages. The wire header is 14 bytes; a cache-hint payload adds 8 bytes. Definitions are in include/atalk/server_ipc.h.

Reconnect tokens are random 8-byte values, not encoded PIDs. The parent validates the token and requesting UID before transferring a socket to an existing session. See Authentication.

Caches and persistence

Worker caches accelerate different parts of a request:

Cache Implementation Behavior
Directory/file identity and stat etc/afpd/dircache.c ARC by default; LRU selectable; 65,536 live entries by default
AppleDouble metadata etc/afpd/ad_cache.c Inline in struct dir; invalidated with metadata/stat changes
Resource fork content etc/afpd/ad_cache.c Separate LRU and byte budget, 32 MiB by default
Parent-directory descriptors etc/afpd/pfd_cache.c 16 slots; accelerates validation using relative stat operations

These caches are per process. Ordinary cache hints are best effort, and filesystem validation remains necessary. multi protocol = yes adjusts coherency defaults for files changed through other services or local tools. A CNID table reset uses a separate hint that ends affected sessions so clients discard obsolete IDs.

Persistent IDs come from mandatory SQLite or optional MySQL, through libatalk/cnid/cnid.c. AppleDouble storage holds Mac metadata and resource forks; its disk format and platform storage differ from the CNID database.

See Caching Architecture, CNID Database, and Data Flow.

Optional services and execution modes

Spotlight is selected per volume through spotlight backend: cnid (default), localsearch, or xapian, subject to build availability. Only Localsearch needs the controller’s private D-Bus/indexer setup.

The normal server runs as root and changes effective identity after login. netatalk --single-user starts a restricted server as a non-root user, requires SRP and SQLite, and serves only that user’s identity. Its configuration, PID file, credential store, and CNID state require private user-owned locations.

AppleTalk services (atalkd, papd, timelord, a2boot, and macipgw) have separate service scripts. The controller does not supervise them. See AppleTalk Networking.

Audit findings and verification scope: Developer Documentation Audit.

Footnotes

Generated from the Netatalk GitHub Wiki

Last updated 2026-10-21