Skip to content

Day54 - UNIX Domain Socket Advanced IPC

Overview

This chapter extends the previous AF_UNIX middleware daemon implementation and explores advanced Linux local IPC concepts.

Topics include:

  • Abstract namespace UNIX sockets
  • Linux credential passing (SO_PEERCRED)
  • Permission control based on UID/GID
  • SOCK_STREAM vs SOCK_DGRAM
  • Datagram request/reply model
  • Datagram truncation behavior

Abstract Namespace UNIX Socket

Traditional UNIX domain sockets are pathname-based:

/tmp/mypoll.sock

These sockets exist inside the filesystem and require:

unlink(path)

before bind().

Linux additionally supports:

abstract namespace socket

which does not create filesystem entries.

Example:

addr.sun_path[0] = '\0';
memcpy(&addr.sun_path[1], "mypoll.sock", ...);

Characteristics:

  • Linux-specific extension
  • No filesystem inode
  • No unlink()
  • Automatically removed when process exits

Check active abstract sockets:

ss -xl

Example output:

u_str LISTEN 0 8 @mypoll.sock

sockaddr_un Length Calculation

Abstract sockets are not normal C strings.

Correct address length:

addr_len =
    offsetof(struct sockaddr_un, sun_path)
    + 1
    + strlen(SOCKET_NAME);

Where:

  • +1 represents the leading '\0'
  • remaining bytes are the abstract socket name

Using sizeof(struct sockaddr_un) is not recommended because unused bytes may become part of the socket name.


SO_PEERCRED

Linux supports retrieving peer credentials from AF_UNIX sockets.

Example:

struct ucred cred;

getsockopt(fd,
           SOL_SOCKET,
           SO_PEERCRED,
           &cred,
           &len);

Returned information:

  • PID
  • UID
  • GID

Example:

pid=1234 uid=1000 gid=1000

This enables:

  • Local IPC authentication
  • Permission control
  • Process tracing

Credential-Based Authorization

The daemon can restrict commands based on UID.

Example:

static bool client_is_privileged(const struct ucred *cred)
{
    return cred && cred->uid == 0;
}

Example authorization:

if (!client_is_privileged(&client->cred))
    return server_reply_perm_denied(q);

This model is commonly used in:

  • systemd
  • dbus-daemon
  • bluetoothd
  • Android services

SOCK_STREAM vs SOCK_DGRAM

SOCK_STREAM

Characteristics:

  • Connection-oriented
  • Ordered byte stream
  • Requires framing
  • Supports partial send/recv
  • Requires TX queue handling

Example issues:

  • Sticky packets
  • Partial reads
  • Backpressure

Typical APIs:

listen()
accept()
send()
recv()

SOCK_DGRAM

Characteristics:

  • Packet-oriented
  • Message boundary preserved
  • No connection lifecycle
  • No partial packet delivery
  • One send = one receive

Typical APIs:

sendto()
recvfrom()

DGRAM Request / Reply Flow

Client:

sendto(server)

Server:

recvfrom(client_addr)
sendto(client_addr)

No accept() or dedicated client fd is required.

Sender information is included inside each datagram packet.


Message Boundary Preservation

Example:

Client sends:

msg1
msg2
msg3

Server receives:

msg1
msg2
msg3

Packets are never merged.

This differs from SOCK_STREAM, where multiple messages may be combined into a single read.


Datagram Truncation

If a datagram packet exceeds the RX buffer size:

  • The packet is truncated
  • Remaining bytes are discarded
  • Next recvfrom() receives the next packet

Unlike stream sockets:

STREAM:
    remaining bytes stay in stream

DGRAM:
    remaining bytes are dropped

Example detection:

recvfrom(..., MSG_TRUNC, ...)

Typical handling:

  • Log warning
  • Drop packet
  • Continue server operation

Key Learning Points

  • Linux abstract namespace sockets
  • AF_UNIX credential passing
  • Local IPC authorization model
  • Packet-oriented communication
  • Datagram truncation semantics
  • STREAM vs DGRAM architecture differences