README.md (4168B)
1 # socket-util 2 3 A C library for common socket utilities including TCP/UDP/Unix socket creation and sockaddr manipulation. 4 5 ## Installation 6 7 This library can be installed using the [dep](https://github.com/finwo/dep) package manager: 8 9 ```bash 10 dep add finwo/socket-util 11 ``` 12 13 ## Usage 14 15 ```c 16 #include "socket-util.h" 17 18 int *fds = tcp_listen(":8080", NULL, NULL); 19 if (fds) { 20 // fds[0] = count, fds[1+] = socket fds 21 for (int i = 1; i <= fds[0]; i++) { 22 printf("Listening on fd %d\n", fds[i]); 23 } 24 free(fds); 25 } 26 ``` 27 28 ## Design Pattern: Config with Defaults 29 30 The `tcp_listen` and `udp_recv` functions are designed to read addresses from config files while providing programmatic fallback defaults: 31 32 ```c 33 int *fds = tcp_listen(config_address, default_host, default_port); 34 ``` 35 36 - **First argument** (`addr`): Read from config file - can be empty/NULL 37 - **Second argument** (`default_host`): Hardcoded fallback host 38 - **Third argument** (`default_port`): Hardcoded fallback port 39 40 This allows flexible configuration: 41 42 ```c 43 // Config provides ":8080" -> binds to 0.0.0.0:8080 44 int *fds = tcp_listen(":8080", NULL, NULL); 45 46 // Config provides "" (empty) -> uses hardcoded defaults 47 int *fds = tcp_listen("", "192.168.1.100", "5060"); 48 49 // Config provides ":0" -> binds to random port, caller must detect actual port 50 int *fds = tcp_listen(":0", NULL, "0"); 51 ``` 52 53 ## Features 54 55 ### TCP Listening 56 57 ```c 58 // Simple: port from config, no defaults 59 int *fds = tcp_listen(":8080", NULL, NULL); 60 61 // Config-driven with defaults 62 int *fds = tcp_listen(config->sip_host, "0.0.0.0", "5060"); 63 64 // Dual-stack (IPv4 + IPv6) 65 int *fds = tcp_listen(":5060", NULL, NULL); 66 67 // IPv4 only 68 int *fds = tcp_listen("0.0.0.0:5060", NULL, NULL); 69 70 // IPv6 only 71 int *fds = tcp_listen("[::]:5060", NULL, NULL); 72 ``` 73 74 ### UDP Receiving 75 76 ```c 77 // Simple: port from config 78 int *fds = udp_recv(":5060", NULL, NULL); 79 80 // With defaults 81 int *fds = udp_recv(config->rtp_host, "0.0.0.0", "10000"); 82 ``` 83 84 ### Unix Domain Sockets 85 86 ```c 87 // Stream socket 88 int *fds = unix_listen("/run/mydaemon.sock", SOCK_STREAM, NULL); 89 90 // With ownership 91 int *fds = unix_listen("/run/mydaemon.sock", SOCK_STREAM, "daemonuser"); 92 93 // Datagram socket with group 94 int *fds = unix_listen("/run/mydaemon.sock", SOCK_DGRAM, "daemonuser:daemogroup"); 95 ``` 96 97 ### Socket Address Conversion 98 99 ```c 100 struct sockaddr_in addr; 101 addr.sin_family = AF_INET; 102 addr.sin_port = htons(8080); 103 inet_pton(AF_INET, "192.168.1.1", &addr.sin_addr); 104 105 char buf[INET6_ADDRSTRLEN + 8]; 106 sockaddr_to_string((struct sockaddr *)&addr, buf, sizeof(buf)); 107 // buf = "192.168.1.1:8080" 108 ``` 109 110 ### String to Socket Address 111 112 ```c 113 struct sockaddr_storage addr; 114 int result = string_to_sockaddr("192.168.1.1:8080", &addr); 115 // result = 0 on success, -1 on error 116 117 result = string_to_sockaddr("[::1]:3000", &addr); 118 // For IPv6, wrap address in brackets 119 ``` 120 121 ### Compare Socket Addresses 122 123 ```c 124 struct sockaddr_in a, b; 125 a.sin_family = AF_INET; 126 b.sin_family = AF_INET; 127 // ... set addresses ... 128 129 if (sockaddr_equal((struct sockaddr *)&a, (struct sockaddr *)&b)) { 130 // Addresses are equal 131 } 132 ``` 133 134 ### Merge File Descriptor Arrays 135 136 ```c 137 int *arr1 = malloc(sizeof(int) * 3); 138 arr1[0] = 2; 139 arr1[1] = 5; 140 arr1[2] = 10; 141 142 int *arr2 = malloc(sizeof(int) * 2); 143 arr2[0] = 1; 144 arr2[1] = 3; 145 146 int *arrays[] = { arr1, arr2 }; 147 int *merged = merge_fd_arrays(arrays, 2); 148 // merged[0] = 3, merged[1] = 5, merged[2] = 10, merged[3] = 3 149 // Note: original arrays are freed 150 ``` 151 152 ### Set Non-blocking 153 154 ```c 155 int fd = socket(AF_INET, SOCK_STREAM, 0); 156 set_socket_nonblocking(fd, 1); // Set non-blocking 157 set_socket_nonblocking(fd, 0); // Set blocking 158 ``` 159 160 ## Address Format 161 162 The address parsing supports: 163 164 - Port only: `:8080`, `8080` (uses defaults for host) 165 - IPv4: `192.168.1.1:8080` 166 - IPv6: `[::1]:8080`, `[2001:db8::1]:443` 167 - With defaults: `8080` with default host `0.0.0.0` 168 169 ## Return Value Conventions 170 171 Functions returning `int *` (arrays): 172 - Returns `NULL` on error 173 - Index 0 contains the count 174 - Indices 1+ contain the values 175 - Caller is responsible for freeing the array 176 177 Functions returning `int`: 178 - Returns 0 on success 179 - Returns -1 on error 180 181 ## License 182 183 Copyright (c) 2026 finwo. See LICENSE.md for details.