pstreamer / src / net_helper-udp.c @ 662a3ab9
History | View | Annotate | Download (7.24 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2010 Luca Abeni
|
3 |
* Copyright (c) 2010 Csaba Kiraly
|
4 |
* Copyright (c) 2010 Alessandro Russo
|
5 |
* Copyright (c) 2017 Luca Baldesi
|
6 |
*
|
7 |
* This is free software; see lgpl-2.1.txt
|
8 |
*/
|
9 |
|
10 |
#include <sys/types.h> |
11 |
#include <unistd.h> |
12 |
#include <errno.h> |
13 |
#include <stdlib.h> |
14 |
#include <stdint.h> |
15 |
#include <stdio.h> |
16 |
#include <string.h> |
17 |
#include <pstreamer_event.h> |
18 |
|
19 |
#ifndef _WIN32
|
20 |
#include <sys/socket.h> |
21 |
#include <netinet/in.h> |
22 |
#include <netdb.h> |
23 |
#include <arpa/inet.h> |
24 |
#else
|
25 |
#define _WIN32_WINNT 0x0501 /* WINNT>=0x501 (WindowsXP) for supporting getaddrinfo/freeaddrinfo.*/ |
26 |
#include "win32-net.h" |
27 |
#endif
|
28 |
|
29 |
#include "net_helper.h" |
30 |
|
31 |
struct nodeID {
|
32 |
struct sockaddr_storage addr;
|
33 |
uint16_t occurrences; |
34 |
int fd;
|
35 |
}; |
36 |
|
37 |
int wait4data(const struct nodeID *s, struct timeval *tout, int *user_fds) |
38 |
/* returns 0 if timeout expires
|
39 |
* returns -1 in case of error of the select function
|
40 |
* retruns 1 if the nodeID file descriptor is ready to be read
|
41 |
* (i.e., some data is ready from the network socket)
|
42 |
* returns 2 if some of the user_fds file descriptors is ready
|
43 |
*/
|
44 |
{ |
45 |
fd_set fds; |
46 |
int i, res, max_fd;
|
47 |
|
48 |
FD_ZERO(&fds); |
49 |
if (s && s->fd >= 0) { |
50 |
max_fd = s->fd; |
51 |
FD_SET(s->fd, &fds); |
52 |
} else {
|
53 |
max_fd = -1;
|
54 |
} |
55 |
if (user_fds) {
|
56 |
for (i = 0; user_fds[i] != -1; i++) { |
57 |
FD_SET(user_fds[i], &fds); |
58 |
if (user_fds[i] > max_fd) {
|
59 |
max_fd = user_fds[i]; |
60 |
} |
61 |
} |
62 |
} |
63 |
res = select(max_fd + 1, &fds, NULL, NULL, tout); |
64 |
if (res <= 0) { |
65 |
return res;
|
66 |
} |
67 |
if (s && FD_ISSET(s->fd, &fds)) {
|
68 |
return 1; |
69 |
} |
70 |
|
71 |
/* If execution arrives here, user_fds cannot be 0
|
72 |
(an FD is ready, and it's not s->fd) */
|
73 |
for (i = 0; user_fds[i] != -1; i++) { |
74 |
if (!FD_ISSET(user_fds[i], &fds)) {
|
75 |
user_fds[i] = -2;
|
76 |
} |
77 |
} |
78 |
|
79 |
return 2; |
80 |
} |
81 |
|
82 |
int register_network_fds(const struct nodeID *s, fd_register_f func, void *handler) |
83 |
{ |
84 |
if (s)
|
85 |
func(handler, s->fd, 'r');
|
86 |
return 0; |
87 |
} |
88 |
|
89 |
struct nodeID *create_node(const char *IPaddr, int port) |
90 |
{ |
91 |
struct nodeID *s = NULL; |
92 |
int error = 0; |
93 |
struct addrinfo hints, *result = NULL; |
94 |
|
95 |
if (IPaddr && port > 0) |
96 |
{ |
97 |
memset(&hints, 0, sizeof(hints)); |
98 |
hints.ai_family = AF_UNSPEC; |
99 |
hints.ai_flags = AI_NUMERICHOST; |
100 |
|
101 |
s = malloc(sizeof(struct nodeID)); |
102 |
memset(s, 0, sizeof(struct nodeID)); |
103 |
s->occurrences = 1;
|
104 |
s->fd = -1;
|
105 |
|
106 |
if ((error = getaddrinfo(IPaddr, NULL, &hints, &result)) == 0) |
107 |
{ |
108 |
s->addr.ss_family = result->ai_family; |
109 |
switch (result->ai_family) {
|
110 |
case (AF_INET):
|
111 |
((struct sockaddr_in *)&s->addr)->sin_port = htons(port);
|
112 |
error = inet_pton (result->ai_family, IPaddr, &((struct sockaddr_in *)&s->addr)->sin_addr);
|
113 |
if (error > 0) |
114 |
error = 0;
|
115 |
break;
|
116 |
case (AF_INET6):
|
117 |
((struct sockaddr_in6 *)&s->addr)->sin6_port = htons(port);
|
118 |
error = inet_pton (result->ai_family, IPaddr, &(((struct sockaddr_in6 *) &s->addr)->sin6_addr));
|
119 |
if (error > 0) |
120 |
error = 0;
|
121 |
break;
|
122 |
default:
|
123 |
fprintf(stderr, "Cannot resolve address family %d for '%s'\n", result->ai_family, IPaddr);
|
124 |
error = -1;
|
125 |
} |
126 |
} |
127 |
} |
128 |
if (error)
|
129 |
{ |
130 |
fprintf(stderr, "Cannot resolve hostname '%s'\n", IPaddr);
|
131 |
nodeid_free(s); |
132 |
s = NULL;
|
133 |
} |
134 |
if (result)
|
135 |
freeaddrinfo(result); |
136 |
|
137 |
return s;
|
138 |
} |
139 |
|
140 |
struct nodeID *net_helper_init(const char *my_addr, int port, const char *config) |
141 |
{ |
142 |
int res;
|
143 |
struct nodeID *myself = NULL;; |
144 |
|
145 |
if (my_addr && port > 0) |
146 |
{ |
147 |
myself = create_node(my_addr, port); |
148 |
if (myself)
|
149 |
myself->fd = socket(myself->addr.ss_family, SOCK_DGRAM, 0);
|
150 |
if (myself && myself->fd >= 0) |
151 |
switch (myself->addr.ss_family)
|
152 |
{ |
153 |
case (AF_INET):
|
154 |
res = bind(myself->fd, (struct sockaddr *)&myself->addr, sizeof(struct sockaddr_in)); |
155 |
break;
|
156 |
case (AF_INET6):
|
157 |
res = bind(myself->fd, (struct sockaddr *)&myself->addr, sizeof(struct sockaddr_in6)); |
158 |
break;
|
159 |
default:
|
160 |
fprintf(stderr, "Cannot resolve address family %d in bind\n", myself->addr.ss_family);
|
161 |
res = -1;
|
162 |
break;
|
163 |
} |
164 |
if (myself && (myself->fd < 0 || res < 0)) |
165 |
{ |
166 |
nodeid_free(myself); |
167 |
myself = NULL;
|
168 |
} |
169 |
|
170 |
} |
171 |
return myself;
|
172 |
} |
173 |
|
174 |
void bind_msg_type (uint8_t msgtype)
|
175 |
{ |
176 |
} |
177 |
|
178 |
int send_to_peer(const struct nodeID *from, const struct nodeID *to, const uint8_t *buffer_ptr, int buffer_size) |
179 |
{ |
180 |
return sendto(from->fd, buffer_ptr, buffer_size, MSG_CONFIRM, (const struct sockaddr *)&(to->addr), sizeof(struct sockaddr_storage)); |
181 |
} |
182 |
|
183 |
int recv_from_peer(const struct nodeID *local, struct nodeID **remote, uint8_t *buffer_ptr, int buffer_size) |
184 |
{ |
185 |
struct nodeID * node;
|
186 |
int res;
|
187 |
socklen_t len; |
188 |
|
189 |
node = malloc(sizeof(struct nodeID)); |
190 |
memset(node, 0, sizeof(struct nodeID)); |
191 |
node->occurrences = 1;
|
192 |
node->fd = -1;
|
193 |
len = sizeof(struct nodeID); |
194 |
|
195 |
res = recvfrom(local->fd, buffer_ptr, buffer_size, 0, (struct sockaddr *)&(node->addr), &len); |
196 |
|
197 |
if (res <=0 ) |
198 |
{ |
199 |
nodeid_free(node); |
200 |
node = NULL;
|
201 |
} |
202 |
*remote = node; |
203 |
|
204 |
return res;
|
205 |
} |
206 |
|
207 |
int node_addr(const struct nodeID *s, char *addr, int len) |
208 |
{ |
209 |
int n = -1; |
210 |
|
211 |
if (addr && len > 0) |
212 |
{ |
213 |
if (s)
|
214 |
{ |
215 |
n = nodeid_dump((uint8_t *) addr, s, len); |
216 |
if (n>0) |
217 |
addr[n-1] = '\0'; |
218 |
} else
|
219 |
n = snprintf(addr, len , "None");
|
220 |
} |
221 |
return n;
|
222 |
} |
223 |
|
224 |
struct nodeID *nodeid_dup(const struct nodeID *s) |
225 |
{ |
226 |
struct nodeID * n;
|
227 |
|
228 |
n = (struct nodeID *) s;
|
229 |
if (n)
|
230 |
n->occurrences++; |
231 |
return n;
|
232 |
} |
233 |
|
234 |
int nodeid_equal(const struct nodeID *s1, const struct nodeID *s2) |
235 |
{ |
236 |
if (s1 && s2)
|
237 |
return (nodeid_cmp(s1, s2) == 0) ? 1 : 0; |
238 |
return 0; |
239 |
} |
240 |
|
241 |
int nodeid_cmp(const struct nodeID *s1, const struct nodeID *s2) |
242 |
{ |
243 |
char ip1[INET6_ADDRSTRLEN], ip2[INET6_ADDRSTRLEN];
|
244 |
int res = 0; |
245 |
|
246 |
if (s1 && s2 && (s1 != s2))
|
247 |
{ |
248 |
node_ip(s1, ip1, INET6_ADDRSTRLEN); |
249 |
node_ip(s2, ip2, INET6_ADDRSTRLEN); |
250 |
res = strcmp(ip1, ip2); |
251 |
if (res == 0) |
252 |
res = node_port(s1) - node_port(s2); |
253 |
} else {
|
254 |
if (s1 && !s2)
|
255 |
res = 1;
|
256 |
if (s2 && !s1)
|
257 |
res = -1;
|
258 |
} |
259 |
return res;
|
260 |
} |
261 |
|
262 |
int nodeid_dump(uint8_t *b, const struct nodeID *s, size_t max_write_size) |
263 |
{ |
264 |
char ip[INET6_ADDRSTRLEN];
|
265 |
int port;
|
266 |
int res = -1; |
267 |
|
268 |
if (s && b)
|
269 |
{ |
270 |
node_ip(s, ip, INET6_ADDRSTRLEN); |
271 |
port = node_port(s); |
272 |
if (max_write_size >= strlen(ip) + 1 + 5) |
273 |
res = sprintf((char *)b, "%s:%d-", ip, port); |
274 |
} |
275 |
return res;
|
276 |
} |
277 |
|
278 |
struct nodeID *nodeid_undump(const uint8_t *b, int *len) |
279 |
{ |
280 |
char * ptr;
|
281 |
char * socket;
|
282 |
int port;
|
283 |
struct nodeID *res = NULL; |
284 |
|
285 |
if (b && len)
|
286 |
{ |
287 |
ptr = strchr((const char *) b, '-'); |
288 |
*len = ptr-(char *)b + 1; |
289 |
socket = malloc(sizeof(char) * (*len)); |
290 |
memmove(socket, b, sizeof(char) * (*len)); |
291 |
socket[(*len)-1] = '\0'; |
292 |
|
293 |
ptr = strrchr(socket, ':');
|
294 |
port = atoi(ptr+1);
|
295 |
|
296 |
*ptr = '\0';
|
297 |
|
298 |
res = create_node(socket, port); |
299 |
free(socket); |
300 |
} |
301 |
return res;
|
302 |
} |
303 |
|
304 |
void nodeid_free(struct nodeID *s) |
305 |
{ |
306 |
if (s)
|
307 |
{ |
308 |
s->occurrences--; |
309 |
if (s->occurrences == 0) |
310 |
{ |
311 |
if (s->fd >= 0) |
312 |
close(s->fd); |
313 |
free(s); |
314 |
} |
315 |
} |
316 |
} |
317 |
|
318 |
int node_ip(const struct nodeID *s, char *ip, int len) |
319 |
{ |
320 |
const char *res = NULL; |
321 |
|
322 |
switch (s->addr.ss_family)
|
323 |
{ |
324 |
case AF_INET:
|
325 |
res = inet_ntop(s->addr.ss_family, &((const struct sockaddr_in *)&s->addr)->sin_addr, ip, len); |
326 |
break;
|
327 |
case AF_INET6:
|
328 |
res = inet_ntop(s->addr.ss_family, &((const struct sockaddr_in6 *)&s->addr)->sin6_addr, ip, len); |
329 |
break;
|
330 |
} |
331 |
if (!res && len)
|
332 |
ip[0] = '\0'; |
333 |
|
334 |
return res ? 0 : -1; |
335 |
} |
336 |
|
337 |
int node_port(const struct nodeID *s) |
338 |
{ |
339 |
int res = -1; |
340 |
|
341 |
switch (s->addr.ss_family) {
|
342 |
case AF_INET:
|
343 |
res = ntohs(((const struct sockaddr_in *) &s->addr)->sin_port); |
344 |
break;
|
345 |
case AF_INET6:
|
346 |
res = ntohs(((const struct sockaddr_in6 *)&s->addr)->sin6_port); |
347 |
break;
|
348 |
} |
349 |
return res;
|
350 |
} |