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