UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
nat.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2020-2021 CESNET z.s.p.o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41#include "config_unix.h"
42#include "config_win32.h"
43
44#include <pthread.h>
45
46#ifdef HAVE_NATPMP
47#define ENABLE_STRNATPMPERR 1
48#define STATICLIB 1
49#include <natpmp.h>
50#endif // defined HAVE_NATPMP
51#ifdef HAVE_PCP
52#include <pcp-client/pcp.h>
53#endif // defined HAVE_PCP
54
55#include "debug.h"
56#include "rtp/net_udp.h" // socket_error
57#include "utils/color_out.h"
58#include "utils/nat.h"
59#include "utils/net.h"
60
61#define DEFAULT_ALLOCATION_TIMEOUT_S 1800
62#define DEFAULT_NAT_PMP_TIMEOUT 5
63#define MOD_NAME "[NAT] "
64#define PREALLOCATE_S 30
65
74 union {
75#ifdef HAVE_PCP
76 struct pcp_state {
77 pcp_ctx_t *ctx;
78 pcp_flow_t *audio_flow;
79 pcp_flow_t *video_flow;
80 } pcp_state;
81#endif // defined HAVE_PCP
86
90 pthread_mutex_t keepalive_mutex;
91 pthread_cond_t keepalive_cv;
92};
93
94static bool setup_pcp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime);
95static void done_pcp(struct ug_nat_traverse *state);
96static bool setup_nat_pmp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime);
97static void done_nat_pmp(struct ug_nat_traverse *state);
98
99static const struct nat_traverse_info_t {
100 const char *name_short;
101 const char *name_long;
102 bool (*init)(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime);
103 void (*done)(struct ug_nat_traverse *state);
104} nat_traverse_info[] = {
105 [ UG_NAT_TRAVERSE_PCP ] = { "pcp", "PCP", setup_pcp, done_pcp },
106 [ UG_NAT_TRAVERSE_NAT_PMP ] = { "natpmp", "NAT PMP", setup_nat_pmp, done_nat_pmp },
108
109#ifdef HAVE_PCP
110static int check_flow_info(pcp_flow_t* f)
111{
112 size_t cnt=0;
113 pcp_flow_info_t *info_buf = NULL;
114 pcp_flow_info_t *ret = pcp_flow_get_info(f,&cnt);
115 int ret_val = 2;
116 info_buf=ret;
117 for (; cnt>0; cnt--, ret++) {
118 switch(ret->result)
119 {
120 case pcp_state_succeeded:
121 printf("\nFlow signaling succeeded.\n");
122 ret_val = 0;
123 break;
124 case pcp_state_short_lifetime_error:
125 printf("\nFlow signaling failed. Short lifetime error received.\n");
126 ret_val = 3;
127 break;
128 case pcp_state_failed:
129 printf("\nFlow signaling failed.\n");
130 ret_val = 4;
131 break;
132 case pcp_state_processing:
133 printf("\nFlow signaling processing.\n");
134 continue;
135 case pcp_state_partial_result:
136 printf("\nFlow signaling partial result.\n");
137 continue;
138 }
139 break;
140 }
141
142 if (info_buf) {
143 free(info_buf);
144 }
145
146 return ret_val;
147}
148
149static const char* decode_fresult(pcp_fstate_e s)
150{
151 switch (s) {
152 case pcp_state_short_lifetime_error:
153 return "slerr";
154 case pcp_state_succeeded:
155 return "succ";
156 case pcp_state_failed:
157 return "fail";
158 default:
159 return "proc";
160 }
161}
162
163#ifdef _WIN32
164static char *ctime_r(const time_t *timep, char *buf)
165{
166 ctime_s(buf, 26, timep);
167 return buf;
168}
169#endif
170
171static void print_ext_addr(pcp_flow_t* f)
172{
173 size_t cnt=0;
174 pcp_flow_info_t *info_buf = NULL;
175 pcp_flow_info_t *ret = pcp_flow_get_info(f,&cnt);
176 info_buf=ret;
177
178 printf("%-20s %-4s %-20s %5s %-20s %5s %-20s %5s %3s %5s %s\n",
179 "PCP Server IP",
180 "Prot",
181 "Int. IP", "port",
182 "Dst. IP", "port",
183 "Ext. IP", "port",
184 "Res", "State","Ends");
185 for (; cnt>0; cnt--, ret++) {
186 char ntop_buffs[4][INET6_ADDRSTRLEN];
187 char timebuf[32];
188
189 printf("%-20s %-4s %-20s %5hu %-20s %5hu %-20s %5hu %3d %5s %s",
190 inet_ntop(AF_INET6, &ret->pcp_server_ip, ntop_buffs[0],
191 sizeof(ntop_buffs[0])),
192 ret->protocol == IPPROTO_TCP ? "TCP" : (
193 ret->protocol == IPPROTO_UDP ? "UDP" : "UNK"),
194 inet_ntop(AF_INET6, &ret->int_ip, ntop_buffs[1],
195 sizeof(ntop_buffs[1])),
196 ntohs(ret->int_port),
197 inet_ntop(AF_INET6, &ret->dst_ip, ntop_buffs[2],
198 sizeof(ntop_buffs[2])),
199 ntohs(ret->dst_port),
200 inet_ntop(AF_INET6, &ret->ext_ip, ntop_buffs[3],
201 sizeof(ntop_buffs[3])),
202 ntohs(ret->ext_port),
203 ret->pcp_result_code,
204 decode_fresult(ret->result),
205 ret->recv_lifetime_end == 0 ? " -\n" :
206 ctime_r(&ret->recv_lifetime_end, timebuf));
207 }
208 if (info_buf) {
209 free(info_buf);
210 }
211}
212#endif // defined HAVE_PCP
213
214static void done_pcp(struct ug_nat_traverse *state)
215{
216#ifdef HAVE_PCP
217 struct pcp_state *s = &state->nat_state.pcp_state;
218 pcp_terminate(s->ctx, 1);
219#else
220 UNUSED(state);
221#endif
222}
223
224#define PCP_WAIT_MS 500
225
226#define NAT_HANDLE_ERROR(msg) { if (fd != -1) CLOSESOCKET(fd); socket_error(msg); return false; }
227#define NAT_ASSERT_EQ(expr, val) { int rc = expr; if (rc != (val)) NAT_HANDLE_ERROR(#expr) }
228#define NAT_ASSERT_NEQ(expr, val) { int rc = expr; if (rc == (val)) NAT_HANDLE_ERROR(#expr) }
229static bool get_outbound_ip(struct sockaddr_in *out) {
230 struct sockaddr_in dst = { 0 };
231 socklen_t src_len = sizeof *out;
232
233 dst.sin_family = AF_INET;
234 dst.sin_port = htons(80);
235 int fd = -1;
236 NAT_ASSERT_EQ(inet_pton(AF_INET, "93.184.216.34", &dst.sin_addr.s_addr), 1);
237 fd = socket(AF_INET, SOCK_DGRAM, 0);
238 NAT_ASSERT_NEQ(fd, -1);
239 NAT_ASSERT_EQ(connect(fd, (struct sockaddr *) &dst, sizeof dst), 0);
240 NAT_ASSERT_EQ(getsockname(fd, (struct sockaddr *) out, &src_len), 0);
241 CLOSESOCKET(fd);
242
243 return true;
244}
245
246static bool setup_pcp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime)
247{
248#ifdef HAVE_PCP
249 struct pcp_state *s = &state->nat_state.pcp_state;
250 struct sockaddr_in src = { 0 };
251
252 s->ctx = pcp_init(ENABLE_AUTODISCOVERY, NULL);
253 // handle errors
254
255 // get our outbound IP address
256 if (!get_outbound_ip(&src)) {
257 log_msg(LOG_LEVEL_ERROR, MOD_NAME "PCP - cannot get outbound address!\n");
258 return false;
259 }
260
261 bool ret = true;
262 if (video_rx_port) {
263 src.sin_port = htons(video_rx_port);
264 s->video_flow = pcp_new_flow(s->ctx, (struct sockaddr*) &src, NULL, NULL, IPPROTO_UDP, lifetime, NULL);
265 if (s->video_flow == NULL) {
266 ret = false;
267 }
268 }
269 if (audio_rx_port) {
270 src.sin_port = htons(audio_rx_port);
271 s->audio_flow = pcp_new_flow(s->ctx, (struct sockaddr*) &src, NULL, NULL, IPPROTO_UDP, lifetime, NULL);
272 if (s->audio_flow == NULL) {
273 ret = false;
274 }
275 }
276 if (!ret) {
277 log_msg(LOG_LEVEL_ERROR, MOD_NAME "PCP - cannot create flow!\n");
279 return false;
280 }
281 if (video_rx_port != 0) {
282 pcp_wait(s->video_flow, PCP_WAIT_MS, 0);
283 ret = ret && check_flow_info(s->video_flow) == 0;
284 if (ret) {
285 print_ext_addr(s->video_flow);
286 } else {
287 log_msg(LOG_LEVEL_ERROR, MOD_NAME "PCP - cannot create video flow!\n");
288 }
289 }
290 if (audio_rx_port != 0) {
291 pcp_wait(s->audio_flow, PCP_WAIT_MS, 0);
292 ret = ret && check_flow_info(s->audio_flow) == 0;
293 if (ret) {
294 print_ext_addr(s->audio_flow);
295 } else {
296 log_msg(LOG_LEVEL_ERROR, MOD_NAME "PCP - cannot create video flow!\n");
297 }
298 }
299
300 if (!ret) {
302 }
303
304 return ret;
305#else
306 UNUSED(state);
307 UNUSED(video_rx_port);
308 UNUSED(audio_rx_port);
309 UNUSED(lifetime);
310 log_msg(LOG_LEVEL_WARNING, MOD_NAME "PCP support not compiled in!\n");
311 return false;
312#endif // defined HAVE_PCP
313}
314
315#ifdef HAVE_NATPMP
316static bool nat_pmp_add_mapping(natpmp_t *natpmp, int privateport, int publicport, int lifetime)
317{
318 if (privateport == 0 && publicport == 0) {
319 return true;
320 }
321
322 int r = 0;
323 /* sendnewportmappingrequest() */
324 r = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_UDP,
325 privateport, publicport,
326 lifetime);
328 "NAT PMP - sendnewportmappingrequest returned %d (%s)\n",
329 r, r == 12 ? "SUCCESS" : "FAILED");
330 if (r < 0) {
331 return false;
332 }
333
334 natpmpresp_t response = { 0 };
335 time_t t0 = time(NULL);
336 do {
337 fd_set fds;
338 struct timeval timeout = { 0 };
339 FD_ZERO(&fds);
340 FD_SET((fd_t) natpmp->s, &fds);
341 r = getnatpmprequesttimeout(natpmp, &timeout);
342 if (r != 0) {
343 log_msg(LOG_LEVEL_ERROR, MOD_NAME "NAT PMP - getnatpmprequesttimeout returned %d (%s)\n",
344 r, strnatpmperr(r));
345 break;
346 }
347 select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
348 r = readnatpmpresponseorretry(natpmp, &response);
349 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "NAT PMP - readnatpmpresponseorretry returned %d (%s)\n",
350 r, r == 0 ? "OK" : (r == NATPMP_TRYAGAIN ? "TRY AGAIN" : "FAILED"));
351 } while (r == NATPMP_TRYAGAIN && time(NULL) - t0 < DEFAULT_NAT_PMP_TIMEOUT);
352 if(r<0) {
353 log_msg(LOG_LEVEL_ERROR, MOD_NAME "NAT PMP - readnatpmpresponseorretry() failed : %s\n",
354 strnatpmperr(r));
355 return false;
356 }
357
358 log_msg(LOG_LEVEL_INFO, MOD_NAME "NAT PMP - Mapped public port %hu protocol %s to local port %hu "
359 "liftime %u\n",
360 response.pnu.newportmapping.mappedpublicport,
361 response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
362 (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" :
363 "UNKNOWN"),
364 response.pnu.newportmapping.privateport,
365 response.pnu.newportmapping.lifetime);
366 log_msg(LOG_LEVEL_DEBUG, MOD_NAME "NAT PMP - epoch = %u\n", response.epoch);
367
368 return true;
369}
370#endif // defined HAVE_NATPMP
371
372static bool setup_nat_pmp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime)
373{
374 UNUSED(state);
375#ifdef HAVE_NATPMP
376 struct in_addr gateway_in_use = { 0 };
377 natpmp_t natpmp;
378 int r = 0;
379 r = initnatpmp(&natpmp, 0, 0);
380 log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE, MOD_NAME "NAT PMP - initnatpmp returned %d (%s)\n", r,
381 r ? "FAILED" : "SUCCESS");
382 if (r < 0) {
383 return false;
384 }
385 gateway_in_use.s_addr = natpmp.gateway;
386 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "NAT PMP - using gateway: %s\n", inet_ntoa(gateway_in_use));
387
388 /* sendpublicaddressrequest() */
389 r = sendpublicaddressrequest(&natpmp);
390 log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE, MOD_NAME "NAT PMP - sendpublicaddressrequest returned %d (%s)\n",
391 r, r == 2 ? "SUCCESS" : "FAILED");
392 if (r < 0) {
393 return false;
394 }
395
396 natpmpresp_t response;
397 do {
398 fd_set fds;
399 struct timeval timeout;
400 FD_ZERO(&fds);
401 FD_SET((fd_t) natpmp.s, &fds);
402 getnatpmprequesttimeout(&natpmp, &timeout);
403 r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
404 if(r<0) {
405 log_msg(LOG_LEVEL_ERROR, MOD_NAME "NAT PMP - select()\n");
406 return false;
407 }
408 r = readnatpmpresponseorretry(&natpmp, &response);
409 int sav_errno = errno;
410 log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE, MOD_NAME "NAT PMP - readnatpmpresponseorretry returned %d (%s)\n",
411 r, r == 0 ? "OK" : ( r== NATPMP_TRYAGAIN ? "TRY AGAIN" : "FAILED"));
412 if (r < 0 && r != NATPMP_TRYAGAIN) {
413 log_msg(LOG_LEVEL_ERROR, MOD_NAME "NAT PMP - readnatpmpresponseorretry() failed : %s\n",
414 strnatpmperr(r));
415 log_msg(LOG_LEVEL_ERROR, MOD_NAME "NAT PMP - errno=%d '%s'\n",
416 sav_errno, strerror(sav_errno));
417 }
418 } while(r==NATPMP_TRYAGAIN);
419
420 if (r < 0) {
421 return false;
422 }
423
424 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "NAT PMP - Public IP address: %s\n", inet_ntoa(response.pnu.publicaddress.addr));
425 log_msg(LOG_LEVEL_DEBUG, MOD_NAME "NAT PMP - epoch = %u\n", response.epoch);
426
427 if (!nat_pmp_add_mapping(&natpmp, video_rx_port, video_rx_port, lifetime) ||
428 !nat_pmp_add_mapping(&natpmp, audio_rx_port, audio_rx_port, lifetime)) {
429 return false;
430 }
431
432 r = closenatpmp(&natpmp);
433 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "NAT PMP - closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED");
434 return r >= 0;
435#else
436 UNUSED(video_rx_port);
437 UNUSED(audio_rx_port);
438 UNUSED(lifetime);
439 log_msg(LOG_LEVEL_WARNING, MOD_NAME "NAT-PMP support not compiled in!\n");
440 return false;
441#endif // defined HAVE_NATPMP
442}
443
444static void done_nat_pmp(struct ug_nat_traverse *state) {
445 setup_nat_pmp(state, state->video_rx_port, state->audio_rx_port, 0);
446}
447
448static void *nat_traverse_keepalive(void *state) {
449 struct ug_nat_traverse *s = state;
450
451 struct timespec timeout = { .tv_sec = time(NULL) + s->allocation_duration - PREALLOCATE_S, .tv_nsec = 0 };
452
453 while (1) {
454 pthread_mutex_lock(&s->keepalive_mutex);
455 int rc = 0;
456 if (!s->keepalive_should_exit) {
457 rc = pthread_cond_timedwait(&s->keepalive_cv, &s->keepalive_mutex, &timeout);
458 }
459 pthread_mutex_unlock(&s->keepalive_mutex);
460 if (s->keepalive_should_exit) {
461 break;
462 }
463
464 if (rc != ETIMEDOUT) {
465 perror(__func__);
466 continue;
467 }
468
470 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Mapping renewed successfully for %d seconds.\n", s->allocation_duration);
471 timeout.tv_sec = time(NULL) + s->allocation_duration - PREALLOCATE_S;
472 } else {
473 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Mapping renewal failed! Trying again in 5 seconds\n");
474 timeout.tv_sec = time(NULL) + 5;
475 }
476 }
477
478 return NULL;
479}
480
487struct ug_nat_traverse *start_nat_traverse(const char *config, const char *remote_host, int video_rx_port, int audio_rx_port)
488{
489 if (config == NULL) {
490 if ((video_rx_port != 0 || audio_rx_port != 0) && (!is_host_private(remote_host) && !is_host_loopback(remote_host))) {
491 struct sockaddr_in out;
492 if (get_outbound_ip(&out) && is_addr_private((struct sockaddr *) &out)) {
493 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Private outbound IPv4 address detected and binding as a receiver. Consider adding '-N' option for NAT traversal.\n");
494 }
495
496 }
497 return calloc(1, sizeof(struct ug_nat_traverse));
498 }
499
500 assert(video_rx_port >= 0 && video_rx_port <= 65535 && audio_rx_port >= 0 && audio_rx_port <= 65535);
501
502 if (strcmp(config, "help") == 0) {
503 printf("Usage:\n");
504 color_printf(TERM_BOLD TERM_FG_RED "\t-N" TERM_FG_RESET "[protocol[:renewal-interval]]\n" TERM_RESET);
505 printf("where:\n");
506 color_printf(TERM_BOLD "\tprotocol" TERM_RESET " - one of:");
507 for (int i = UG_NAT_TRAVERSE_FIRST; i <= UG_NAT_TRAVERSE_LAST; ++i) {
509 }
510 printf("\n");
511 color_printf(TERM_BOLD "\trenewal-interval" TERM_RESET " - mapping renew interval (in seconds, min: %d)\n", PREALLOCATE_S + 1);
512 return NULL;
513 }
514
515 struct ug_nat_traverse *s = calloc(1, sizeof(struct ug_nat_traverse));
519
520 bool not_found = true;
521 char protocol[strlen(config) + 1];
522 strcpy(protocol, config);
523 if (strchr(protocol, ':') != NULL) {
524 s->allocation_duration = atoi(strchr(protocol, ':') + 1);
525 if (s->allocation_duration < PREALLOCATE_S + 1) {
526 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong renewal interval: %s, minimal: %d\n", strchr(protocol, ':') + 1, PREALLOCATE_S + 1);
527 free(s);
528 return NULL;
529 }
530 *strchr(protocol, ':') = '\0';
531 }
532 for (int i = UG_NAT_TRAVERSE_FIRST; i <= UG_NAT_TRAVERSE_LAST; ++i) {
533 if (strlen(protocol) > 0 && strcmp(nat_traverse_info[i].name_short, protocol) != 0) {
534 continue;
535 }
536 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Trying: %s\n", nat_traverse_info[i].name_long);
537 not_found = false;
539 s->traverse = i;
540 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Set NAT traversal with %s for %d seconds (auto-renewed). Sender can send to external IP address.\n", nat_traverse_info[i].name_long, s->allocation_duration);
541 break;
542 }
543 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%s initialization failed!\n", nat_traverse_info[i].name_long);
544 }
545
546 if (s->traverse == UG_NAT_TRAVERSE_NONE) {
547 if (not_found) {
548 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong module name: %s.\n", protocol);
549 } else {
550 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not initialize any NAT traversal.\n");
551 }
552 free(s);
553 return NULL;
554 }
555
556 int rc = 0;
557 rc |= pthread_mutex_init(&s->keepalive_mutex, NULL);
558 rc |= pthread_cond_init(&s->keepalive_cv, NULL);
559 rc |= pthread_create(&s->keepalive_thread, NULL, nat_traverse_keepalive, s);
560 assert(rc == 0);
561
562 s->initialized = true;
563
564 return s;
565}
566
568{
569 if (s == NULL || s->initialized == false) {
570 free(s);
571 return;
572 }
573
574 pthread_mutex_lock(&s->keepalive_mutex);
575 s->keepalive_should_exit = true;
576 pthread_mutex_unlock(&s->keepalive_mutex);
577 pthread_cond_signal(&s->keepalive_cv);
578 pthread_join(s->keepalive_thread, NULL);
579
580 pthread_mutex_destroy(&s->keepalive_mutex);
581 pthread_cond_destroy(&s->keepalive_cv);
582
585 }
586
587 free(s);
588}
589
590/* vim: set expandtab sw=8: */
#define UNUSED(x)
void ** state
static af_result_code init(struct module *parent, const char *cfg, void **state)
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_RESET
Definition color_out.h:47
#define TERM_FG_RESET
Definition color_out.h:59
int fd_t
#define CLOSESOCKET
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
static bool setup_nat_pmp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime)
Definition nat.c:372
void stop_nat_traverse(struct ug_nat_traverse *s)
Definition nat.c:567
static const struct nat_traverse_info_t nat_traverse_info[]
struct ug_nat_traverse * start_nat_traverse(const char *config, const char *remote_host, int video_rx_port, int audio_rx_port)
Definition nat.c:487
static bool get_outbound_ip(struct sockaddr_in *out)
Definition nat.c:229
#define DEFAULT_ALLOCATION_TIMEOUT_S
Definition nat.c:61
#define NAT_ASSERT_EQ(expr, val)
Definition nat.c:227
#define NAT_ASSERT_NEQ(expr, val)
Definition nat.c:228
static void * nat_traverse_keepalive(void *state)
Definition nat.c:448
static bool setup_pcp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime)
Definition nat.c:246
#define PCP_WAIT_MS
Definition nat.c:224
static void done_nat_pmp(struct ug_nat_traverse *state)
Definition nat.c:444
#define DEFAULT_NAT_PMP_TIMEOUT
Definition nat.c:62
#define PREALLOCATE_S
number of seconds that repeated allocation is performed before timeout
Definition nat.c:64
#define MOD_NAME
Definition nat.c:63
static void done_pcp(struct ug_nat_traverse *state)
Definition nat.c:214
bool is_addr_private(struct sockaddr *sa)
Definition net.c:139
bool is_host_private(const char *hostname)
Definition net.c:187
bool is_host_loopback(const char *hostname)
Definition net.c:174
const char * name_long
for output
Definition nat.c:101
bool(* init)(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime)
Definition nat.c:102
const char * name_short
for command-line specifiction
Definition nat.c:100
void(* done)(struct ug_nat_traverse *state)
Definition nat.c:103
pthread_cond_t keepalive_cv
Definition nat.c:91
int allocation_duration
Definition nat.c:85
pthread_t keepalive_thread
Definition nat.c:88
bool keepalive_should_exit
Definition nat.c:89
enum ug_nat_traverse::traverse_t traverse
@ UG_NAT_TRAVERSE_PCP
Definition nat.c:69
@ UG_NAT_TRAVERSE_FIRST
Definition nat.c:70
@ UG_NAT_TRAVERSE_NONE
Definition nat.c:68
@ UG_NAT_TRAVERSE_NAT_PMP
Definition nat.c:71
@ UG_NAT_TRAVERSE_LAST
Definition nat.c:72
pthread_mutex_t keepalive_mutex
Definition nat.c:90
bool initialized
whether the state was initialized
Definition nat.c:87
int video_rx_port
Definition nat.c:84
union ug_nat_traverse::@62 nat_state
int audio_rx_port
Definition nat.c:83