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