1 /* Socket utilities, including parsing and sockaddr juggling.
3 * From: Rick van Rein <rick@openfortress.nl>
21 # define DPRINTF printf
27 #ifndef PART_OF_KXOVER
33 /* Given a socket address, determine its length.
35 * This function does not fail.
39 socklen_t sockaddrlen (const struct sockaddr *sa) {
40 assert ((sa->sa_family == AF_INET6) || (sa->sa_family == AF_INET));
41 if (sa->sa_family == AF_INET6) {
42 return sizeof (struct sockaddr_in6);
44 return sizeof (struct sockaddr_in );
49 /* Store a raw address from a given family in a socket address,
50 * together with a port that may be set to 0 as a catch-all.
52 bool socket_address (sa_family_t af, uint8_t *addr, uint16_t portnr, struct sockaddr *sa) {
54 memset (sa, 0, sockaddrlen (sa));
58 memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr, addr, 16);
59 ((struct sockaddr_in6 *) sa)->sin6_port = htons (portnr);
62 DPRINTF ("DEBUG: socket address (%d.%d.%d.%d, %d)\n", addr [0], addr [1], addr [2], addr [3], portnr);
63 memcpy (&((struct sockaddr_in *) sa)->sin_addr, addr, 4);
64 ((struct sockaddr_in *) sa)->sin_port = htons (portnr);
74 /* Parse an address and port, and store them in a sockaddr of
75 * type AF_INET or AF_INET6. The space provided is large enough
76 * to hold either, as it is defined as a union.
78 * The opt_port may be NULL, in which case the port is set to 0
79 * in the returned sockaddr; otherwise, its value is rejected
82 * We always try IPv6 address parsing first, but fallback to
83 * IPv4 if we have to, but that fallback is deprecated. The
84 * port will be syntax-checked and range-checked.
86 * Return true on success, or false with kxerrno set on error.
88 bool socket_parse (char *addr, char *opt_port, struct sockaddr *out_sa) {
90 // Optional port parsing
92 if (opt_port != NULL) {
93 long p = strtol (opt_port, &opt_port, 10);
94 if (*opt_port != '\0') {
98 if ((p == LONG_MIN) || (p == LONG_MAX) || (p <= 0) || (p > 65535)) {
103 portnr = (uint16_t) p;
106 // IPv6 address parsing
107 uint8_t raw_addr [16];
108 switch (inet_pton (AF_INET6, addr, raw_addr)) {
110 return socket_address (AF_INET6, raw_addr, portnr, out_sa);
117 // IPv4 address parsing
118 switch (inet_pton (AF_INET, addr, raw_addr)) {
120 return socket_address (AF_INET, raw_addr, portnr, out_sa);
127 // Report EINVAL as an error condition
133 /* Open a connection as a client, to the given address. Do not bind locally.
135 * Set contype to one SOCK_DGRAM, SOCK_STREAM or SOCK_SEQPACKET.
137 * The resulting socket is written to out_sox.
139 * Return true on success, or false with kxerrno set on failure.
140 * On error, *out_sox is set to -1.
142 bool socket_client (const struct sockaddr *peer, int contype, int *out_sox) {
144 sox = socket (peer->sa_family, contype, 0);
148 if (connect (sox, peer, sockaddrlen (peer)) != 0) {
151 #ifdef PART_OF_KXOVER
152 int soxflags = fcntl (sox, F_GETFL, 0);
153 if (fcntl (sox, F_SETFL, soxflags | O_NONBLOCK) != 0) {
168 /* Open a listening socket as a server, at the given address.
170 * Set contype to one of SOCK_DGRAM, SOCK_STREAM or SOCK_SEQPACKET.
172 * The resulting socket is written to out_sox.
174 * Return true on success, or false with kxerrno set on failure.
175 * On error, *out_sox is set to -1.
177 bool socket_server (const struct sockaddr *mine, int contype, int *out_sox) {
179 sox = socket (mine->sa_family, contype, 0);
183 if (bind (sox, mine, sockaddrlen (mine)) != 0) {
186 if ((contype == SOCK_STREAM) || (contype == SOCK_SEQPACKET)) {
187 if (listen (sox, 10) != 0) {
191 #ifdef PART_OF_KXOVER
192 int soxflags = fcntl (sox, F_GETFL, 0);
193 if (fcntl (sox, F_SETFL, soxflags | O_NONBLOCK) != 0) {