-
Notifications
You must be signed in to change notification settings - Fork 23
/
rdaddr.h
188 lines (161 loc) · 6.15 KB
/
rdaddr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
* librd - Rapid Development C library
*
* Copyright (c) 2012-2013, Magnus Edenhill
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
/**
* rd_sockaddr_inx_t is a union for either ipv4 or ipv6 sockaddrs.
* It provides conveniant abstraction of AF_INET* agnostic operations.
*/
typedef union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
} rd_sockaddr_inx_t;
#define sinx_family in.sin_family
#define sinx_addr in.sin_addr
#define RD_SOCKADDR_INX_LEN(sinx) \
((sinx)->sinx_family == AF_INET ? sizeof(struct sockaddr_in) : \
(sinx)->sinx_family == AF_INET6 ? sizeof(struct sockaddr_in6): \
sizeof(rd_sockaddr_inx_t))
#define RD_SOCKADDR_INX_PORT(sinx) \
((sinx)->sinx_family == AF_INET ? (sinx)->in.sin_port : \
(sinx)->sinx_family == AF_INET6 ? (sinx)->in6.sin6_port : 0)
#define RD_SOCKADDR_INX_PORT_SET(sinx,port) do { \
if ((sinx)->sinx_family == AF_INET) \
(sinx)->in.sin_port = port; \
else if ((sinx)->sinx_family == AF_INET6) \
(sinx)->in6.sin6_port = port; \
} while (0)
#define RD_SOCKADDR_INX_CMP(a,b) \
(!(RD_SOCKADDR_INX_LEN(a) == RD_SOCKADDR_INX_LEN(b) && \
!memcmp((a), (b), RD_SOCKADDR_INX_LEN(a))))
/**
* Returns a thread-local temporary string (may be called up to 32 times
* without buffer wrapping) containing the human string representation
* of the sockaddr (which should be AF_INET or AF_INET6 at this point).
* If the RD_SOCKADDR2STR_F_PORT is provided the port number will be
* appended to the string.
* IPv6 address enveloping ("[addr]:port") will also be performed
* if .._F_PORT is set.
*/
#define RD_SOCKADDR2STR_F_PORT 0x1 /* Append the port. */
#define RD_SOCKADDR2STR_F_RESOLVE 0x2 /* Try to resolve address to hostname. */
#define RD_SOCKADDR2STR_F_FAMILY 0x4 /* Prepend address family. */
#define RD_SOCKADDR2STR_F_NICE /* Nice and friendly output */ \
(RD_SOCKADDR2STR_F_PORT | RD_SOCKADDR2STR_F_RESOLVE)
const char *rd_sockaddr2str (const void *addr, int flags);
/**
* Splits a node:service definition up into their node and svc counterparts
* suitable for passing to getaddrinfo().
* Returns NULL on success (and temporarily available pointers in '*node'
* and '*svc') or error string on failure.
*
* Thread-safe but returned buffers in '*node' and '*svc' are only
* usable until the next call to rd_addrinfo_prepare() in the same thread.
*/
const char *rd_addrinfo_prepare (const char *nodesvc,
char **node, char **svc);
typedef struct rd_sockaddr_list_s {
int rsal_cnt;
int rsal_curr;
rd_sockaddr_inx_t rsal_addr[0];
} rd_sockaddr_list_t;
/**
* Returns the next address from a sockaddr list and updates
* the current-index to point to it.
*
* Typical usage is for round-robin connection attempts or similar:
* while (1) {
* rd_sockaddr_inx_t *sinx = rd_sockaddr_list_next(my_server_list);
* if (do_connect((struct sockaddr *)sinx) == -1) {
* sleep(1);
* continue;
* }
* ...
* }
*
*/
static inline rd_sockaddr_inx_t *
rd_sockaddr_list_next (rd_sockaddr_list_t *rsal) RD_UNUSED;
static inline rd_sockaddr_inx_t *
rd_sockaddr_list_next (rd_sockaddr_list_t *rsal) {
rsal->rsal_curr = (rsal->rsal_curr + 1) % rsal->rsal_cnt;
return &rsal->rsal_addr[rsal->rsal_curr];
}
#define RD_SOCKADDR_LIST_FOREACH(sinx, rsal) \
for ((sinx) = &(rsal)->rsal_addr[0] ; \
(sinx) < &(rsal)->rsal_addr[(rsal)->rsal_len] ; \
(sinx)++)
/**
* Wrapper for getaddrinfo(3) that performs these additional tasks:
* - Input is a combined "<node>[:<svc>]" string, with support for
* IPv6 enveloping ("[addr]:port").
* - Returns a rd_sockaddr_list_t which must be freed with
* rd_sockaddr_list_destroy() when done with it.
* - Automatically shuffles the returned address list to provide
* round-robin (unless RD_AI_NOSHUFFLE is provided in 'flags').
*
* Thread-safe.
*/
#define RD_AI_NOSHUFFLE 0x10000000 /* Dont shuffle returned address list.
* FIXME: Guessing non-used bits like this
* is a bad idea. */
rd_sockaddr_list_t *rd_getaddrinfo (const char *nodesvc, const char *defsvc,
int flags, int family,
int socktype, int protocol,
const char **errstr);
/**
* Frees a sockaddr list.
*
* Thread-safe.
*/
void rd_sockaddr_list_destroy (rd_sockaddr_list_t *rsal);
/**
* Returns the human readable name of a socket family.
*/
static const char *rd_family2str (int af) RD_UNUSED;
static const char *rd_family2str (int af) {
static const char *names[] = {
[AF_LOCAL] = "local",
[AF_INET] = "inet",
[AF_INET6] = "inet6",
[AF_NETLINK] = "netlink",
#ifndef __linux__
[AF_ROUTE] = "route",
#endif
[AF_PACKET] = "packet",
[AF_BLUETOOTH] = "bluetooth",
};
if (unlikely(af >= RD_ARRAYSIZE(names))) {
static __thread char tmp[16];
snprintf(tmp, sizeof(tmp), "af-%i", af);
return tmp;
}
return names[af];
}