libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
xtc_net.h
1/*-
2 * Copyright (c) 2026, The XTC Project
3 * Use of this source code is governed by the ISC License,
4 * a copy of which is in the file LICENSE in the top-level directory
5 * of this distribution.
6 *
7 * src/inc/xtc_net.h
8 * Networking helpers built on top of xtc_io. These are the
9 * first slice of M19.1: TCP knobs + Unix domain sockets +
10 * cred-passing. Future passes will add accept scaling
11 * (SO_REUSEPORT distribution), TCP_USER_TIMEOUT, congestion
12 * algorithm selection, etc.
13 *
14 * The socket family is identified by xtc_net_family_t; xtc owns
15 * the fd and exposes it for direct use with xtc_io_reg_fd /
16 * xtc_io_poll. None of these calls block -- caller-driven I/O
17 * is the contract.
18 */
19
20#ifndef XTC_NET_H
21#define XTC_NET_H
22
23#include <stddef.h>
24#include <stdint.h>
25
26#include "xtc.h"
27
28typedef enum xtc_net_family {
29 XTC_NET_INET = 0,
30 XTC_NET_INET6 = 1,
31 XTC_NET_UNIX = 2
32} xtc_net_family_t;
33
34/* TCP-level knobs. Defaults pick reasonable server-side values:
35 * TCP_NODELAY=1, SO_REUSEADDR=1, KEEPALIVE off (caller opts in). */
36typedef struct xtc_tcp_opts {
37 int nodelay; /* TCP_NODELAY: 1 = disable Nagle */
38 int reuseaddr; /* SO_REUSEADDR */
39 int reuseport; /* SO_REUSEPORT (Linux/BSD; falls back to no-op) */
40 int keepalive; /* SO_KEEPALIVE */
41 int keepidle_s; /* TCP_KEEPIDLE in seconds (Linux); 0 = OS default */
42 int keepintvl_s; /* TCP_KEEPINTVL in seconds (Linux); 0 = OS default */
43 int keepcnt; /* TCP_KEEPCNT (Linux); 0 = OS default */
44 int user_timeout_ms; /* TCP_USER_TIMEOUT in ms (Linux); 0 = OS default */
46
47#define XTC_TCP_OPTS_DEFAULT { \
48 .nodelay = 1, .reuseaddr = 1, .reuseport = 0, .keepalive = 0, \
49 .keepidle_s = 0, .keepintvl_s = 0, .keepcnt = 0, .user_timeout_ms = 0 \
50}
51
52/*
53 * PUBLIC: int xtc_net_listen __P((xtc_net_family_t, const char *, int, const xtc_tcp_opts_t *, int *));
54 * PUBLIC: int xtc_net_dial __P((xtc_net_family_t, const char *, int, const xtc_tcp_opts_t *, int *));
55 * PUBLIC: int xtc_net_apply_tcp_opts __P((int, const xtc_tcp_opts_t *));
56 * PUBLIC: int xtc_net_setnonblock __P((int));
57 * PUBLIC: void xtc_net_close __P((int));
58 *
59 * PUBLIC: int xtc_net_unix_listen __P((const char *, int *));
60 * PUBLIC: int xtc_net_unix_dial __P((const char *, int *));
61 * PUBLIC: int xtc_net_unix_send_creds __P((int, const void *, size_t));
62 * PUBLIC: int xtc_net_unix_recv_creds __P((int, void *, size_t, uint32_t *, uint32_t *, size_t *));
63 *
64 * PUBLIC: int xtc_net_udp_socket __P((xtc_net_family_t, const char *, int, int *));
65 * PUBLIC: int xtc_net_udp_sendto __P((int, const void *, size_t, const char *, int));
66 * PUBLIC: int xtc_net_udp_recvfrom __P((int, void *, size_t, char *, size_t, int *, size_t *));
67 *
68 * PUBLIC: int xtc_dns_resolve __P((const char *, int, xtc_net_family_t, char *, size_t));
69 */
70
71/* TCP listen socket. `host` may be NULL/"" for any-address. Returns
72 * the listening fd; caller registers it with xtc_io_reg_fd for accept
73 * readiness. Backlog defaults to 128 if 0. */
74int xtc_net_listen(xtc_net_family_t fam, const char *host, int port,
75 const xtc_tcp_opts_t *opts, int *out_fd);
76
77/* TCP connect to host:port. Returns the fd in out_fd. The connect
78 * is non-blocking; caller polls for writability to detect completion. */
79int xtc_net_dial(xtc_net_family_t fam, const char *host, int port,
80 const xtc_tcp_opts_t *opts, int *out_fd);
81
82/* Apply TCP knobs to an already-open socket. */
83int xtc_net_apply_tcp_opts(int fd, const xtc_tcp_opts_t *opts);
84
85/* Set O_NONBLOCK + FD_CLOEXEC. */
86int xtc_net_setnonblock(int fd);
87
88/* Close (always succeeds). */
89void xtc_net_close(int fd);
90
91/* Unix domain sockets -- SOCK_STREAM. */
92int xtc_net_unix_listen(const char *path, int *out_fd);
93int xtc_net_unix_dial (const char *path, int *out_fd);
94
95/* Send a message + the sender's credentials (uid/gid/pid) over a
96 * UNIX socket via SCM_CREDENTIALS / LOCAL_PEERCRED. The receiver
97 * extracts the credentials with xtc_net_unix_recv_creds. */
98int xtc_net_unix_send_creds(int fd, const void *buf, size_t buflen);
99int xtc_net_unix_recv_creds(int fd, void *buf, size_t buflen,
100 uint32_t *out_uid, uint32_t *out_gid,
101 size_t *out_n);
102
103/* ---- UDP ----------------------------------------------------- */
104
105/* Open a UDP datagram socket bound to (host, port). host=NULL
106 * means INADDR_ANY / in6addr_any. port=0 means kernel-assigned.
107 * Returns the fd in non-blocking + cloexec mode. */
108int xtc_net_udp_socket(xtc_net_family_t fam, const char *host,
109 int port, int *out_fd);
110
111/* Send a single datagram to host:port. Returns XTC_OK on full
112 * send, XTC_E_AGAIN if the kernel buffer is full (caller should
113 * poll for writability). */
114int xtc_net_udp_sendto(int fd, const void *buf, size_t len,
115 const char *host, int port);
116
117/* Receive a single datagram. out_host/out_host_size receive the
118 * peer's address as a printable string. out_port and out_n are
119 * filled in. Returns XTC_OK or XTC_E_AGAIN. */
120int xtc_net_udp_recvfrom(int fd, void *buf, size_t buflen,
121 char *out_host, size_t out_host_size,
122 int *out_port, size_t *out_n);
123
124/* ---- DNS resolution ------------------------------------------
125 *
126 * xtc_dns_resolve resolves a hostname to a printable address
127 * string. The current implementation uses getaddrinfo(3) on a
128 * blocking thread; the calling proc / fiber blocks during the
129 * lookup. For genuine async resolution -- and to avoid blocking
130 * the loop -- run the call from a dedicated lookup proc whose
131 * thread is allowed to block. A future revision will integrate
132 * a c-ares-style fully async resolver.
133 */
134int xtc_dns_resolve(const char *hostname, int port,
135 xtc_net_family_t fam,
136 char *out_addr, size_t out_addr_size);
137
138/* ---- length-framed transport --------------------------------
139 *
140 * A 4-byte big-endian length prefix + payload. On a non-blocking fd
141 * these yield the calling fiber (via the loop) on partial I/O instead
142 * of blocking, so many connections share one loop; off a loop they
143 * fall back to poll(2). Set the fd non-blocking (xtc_net_setnonblock)
144 * for the loop-friendly behaviour.
145 *
146 * xtc_net_recv_frame allocates the frame with the xtc allocator (free
147 * it with xtc_free) and rejects a claimed length above max_len
148 * (max_len 0 = no cap) with XTC_E_RANGE -- so a peer cannot force an
149 * unbounded allocation. Returns XTC_E_AGAIN on timeout, XTC_E_INVAL
150 * if the peer closed mid-frame. A zero-length frame returns XTC_OK
151 * with *out == NULL.
152 */
153int xtc_net_send_frame(int fd, const void *buf, size_t len);
154int xtc_net_recv_frame(int fd, void **out, size_t *out_len,
155 size_t max_len, int64_t timeout_ns);
156
157#endif /* XTC_NET_H */