1 /*
2 * Copyright (C) 2014 Steve Harris et al. (see AUTHORS)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * $Id$
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26
27 #if defined(WIN32) || defined(_MSC_VER)
28 #include <io.h>
29 #define snprintf _snprintf
30 #include <winsock2.h>
31 #include <ws2tcpip.h>
32 #include <iphlpapi.h>
33 #else
34 #include <unistd.h>
35 #include <netdb.h>
36 #include <sys/socket.h>
37 #include <arpa/inet.h>
38 #include <netinet/tcp.h>
39 #ifdef HAVE_GETIFADDRS
40 #include <ifaddrs.h>
41 #endif
42 #endif
43
44 #include "lo_types_internal.h"
45 #include "lo_internal.h"
46 #include "lo/lo.h"
47 #include "lo/lo_throw.h"
48
49 static void lo_address_set_flags(lo_address t, int flags);
50
lo_address_new_with_proto(int proto,const char * host,const char * port)51 lo_address lo_address_new_with_proto(int proto, const char *host,
52 const char *port)
53 {
54 lo_address a;
55
56 if (proto != LO_UDP && proto != LO_TCP && proto != LO_UNIX)
57 return NULL;
58
59 a = (lo_address) calloc(1, sizeof(struct _lo_address));
60 if (a == NULL)
61 return NULL;
62
63 a->ai = NULL;
64 a->ai_first = NULL;
65 a->socket = -1;
66 a->ownsocket = 1;
67 a->protocol = proto;
68 a->flags = (lo_proto_flags) 0;
69 switch (proto) {
70 default:
71 case LO_UDP:
72 case LO_TCP:
73 if (host) {
74 a->host = strdup(host);
75 } else {
76 a->host = strdup("localhost");
77 }
78 break;
79 case LO_UNIX:
80 a->host = strdup("localhost");
81 break;
82 }
83 if (port) {
84 a->port = strdup(port);
85 } else {
86 a->port = NULL;
87 }
88
89 a->ttl = -1;
90 a->addr.size = 0;
91 a->addr.iface = 0;
92 a->source_server = 0;
93 a->source_path = 0;
94
95 return a;
96 }
97
lo_address_new(const char * host,const char * port)98 lo_address lo_address_new(const char *host, const char *port)
99 {
100 return lo_address_new_with_proto(LO_UDP, host, port);
101 }
102
lo_address_new_from_url(const char * url)103 lo_address lo_address_new_from_url(const char *url)
104 {
105 lo_address a;
106 int protocol;
107 char *host, *port, *proto;
108
109 if (!url || !*url) {
110 return NULL;
111 }
112
113 protocol = lo_url_get_protocol_id(url);
114 if (protocol == LO_UDP || protocol == LO_TCP) {
115 host = lo_url_get_hostname(url);
116 port = lo_url_get_port(url);
117 a = lo_address_new_with_proto(protocol, host, port);
118 if (host)
119 free(host);
120 if (port)
121 free(port);
122 #if !defined(WIN32) && !defined(_MSC_VER)
123 } else if (protocol == LO_UNIX) {
124 port = lo_url_get_path(url);
125 a = lo_address_new_with_proto(LO_UNIX, NULL, port);
126 if (port)
127 free(port);
128 #endif
129 } else {
130 proto = lo_url_get_protocol(url);
131 fprintf(stderr,
132 PACKAGE_NAME ": protocol '%s' not supported by this "
133 "version\n", proto);
134 if (proto)
135 free(proto);
136
137 return NULL;
138 }
139
140 return a;
141 }
142
lo_address_resolve_source(lo_address a)143 static void lo_address_resolve_source(lo_address a)
144 {
145 char hostname[LO_HOST_SIZE];
146 char portname[32];
147 int err;
148 lo_server s = a->source_server;
149
150 if (a->protocol == LO_UDP && s && s->addr_len > 0)
151 {
152 err = getnameinfo((struct sockaddr *) &s->addr, s->addr_len,
153 hostname, sizeof(hostname),
154 portname, sizeof(portname),
155 NI_NUMERICHOST | NI_NUMERICSERV);
156 if (err) {
157 switch (err) {
158 case EAI_AGAIN:
159 lo_throw(s, err, "Try again", a->source_path);
160 break;
161 case EAI_BADFLAGS:
162 lo_throw(s, err, "Bad flags", a->source_path);
163 break;
164 case EAI_FAIL:
165 lo_throw(s, err, "Failed", a->source_path);
166 break;
167 case EAI_FAMILY:
168 lo_throw(s, err, "Cannot resolve address family",
169 a->source_path);
170 break;
171 case EAI_MEMORY:
172 lo_throw(s, err, "Out of memory", a->source_path);
173 break;
174 case EAI_NONAME:
175 lo_throw(s, err, "Cannot resolve", a->source_path);
176 break;
177 #if !defined(WIN32) && !defined(_MSC_VER)
178 case EAI_SYSTEM:
179 lo_throw(s, err, strerror(err), a->source_path);
180 break;
181 #endif
182 default:
183 lo_throw(s, err, "Unknown error", a->source_path);
184 break;
185 }
186
187 return;
188 }
189
190 a->host = strdup(hostname);
191 a->port = strdup(portname);
192 } else {
193 a->host = strdup("");
194 a->port = strdup("");
195 }
196 }
197
lo_address_get_hostname(lo_address a)198 const char *lo_address_get_hostname(lo_address a)
199 {
200 if (!a) {
201 return NULL;
202 }
203
204 if (!a->host)
205 lo_address_resolve_source(a);
206
207 return a->host;
208 }
209
lo_address_get_protocol(lo_address a)210 int lo_address_get_protocol(lo_address a)
211 {
212 if (!a) {
213 return -1;
214 }
215
216 return a->protocol;
217 }
218
lo_address_get_port(lo_address a)219 const char *lo_address_get_port(lo_address a)
220 {
221 if (!a) {
222 return NULL;
223 }
224
225 if (!a->host)
226 lo_address_resolve_source(a);
227
228 return a->port;
229 }
230
get_protocol_name(int proto)231 static const char *get_protocol_name(int proto)
232 {
233 switch (proto) {
234 case LO_UDP:
235 return "udp";
236 case LO_TCP:
237 return "tcp";
238 #if !defined(WIN32) && !defined(_MSC_VER)
239 case LO_UNIX:
240 return "unix";
241 #endif
242 }
243 return NULL;
244 }
245
246
lo_address_get_url(lo_address a)247 char *lo_address_get_url(lo_address a)
248 {
249 char *buf;
250 int ret = 0;
251 int needquote = 0;
252 const char *fmt;
253
254 if (!a->host)
255 lo_address_resolve_source(a);
256
257 if (!a->host)
258 return NULL;
259
260 needquote = strchr(a->host, ':') ? 1 : 0;
261
262 if (needquote) {
263 fmt = "osc.%s://[%s]:%s/";
264 } else {
265 fmt = "osc.%s://%s:%s/";
266 }
267 #ifndef _MSC_VER
268 ret = snprintf(NULL, 0, fmt,
269 get_protocol_name(a->protocol), a->host, a->port);
270 #endif
271 if (ret <= 0) {
272 /* this libc is not C99 compliant, guess a size */
273 ret = 1023;
274 }
275 buf = (char*) malloc((ret + 2) * sizeof(char));
276 snprintf(buf, ret + 1, fmt,
277 get_protocol_name(a->protocol), a->host, a->port);
278
279 if (a->protocol==LO_UNIX) {
280 buf[ret-1] = 0;
281 }
282
283 return buf;
284 }
285
lo_address_free(lo_address a)286 void lo_address_free(lo_address a)
287 {
288 if (a) {
289 if (a->socket != -1 && a->ownsocket) {
290 #ifdef SHUT_WR
291 shutdown(a->socket, SHUT_WR);
292 #endif
293 closesocket(a->socket);
294 }
295 lo_address_free_mem(a);
296 free(a);
297 }
298 }
299
lo_address_free_mem(lo_address a)300 void lo_address_free_mem(lo_address a)
301 {
302 if (a) {
303 if (a->host)
304 free(a->host);
305 if (a->port)
306 free(a->port);
307 if (a->ai_first)
308 freeaddrinfo(a->ai_first);
309 if (a->addr.iface)
310 free(a->addr.iface);
311
312 memset(a, 0, sizeof(struct _lo_address));
313 a->socket = -1;
314 }
315 }
316
lo_address_errno(lo_address a)317 int lo_address_errno(lo_address a)
318 {
319 return a->errnum;
320 }
321
lo_address_errstr(lo_address a)322 const char *lo_address_errstr(lo_address a)
323 {
324 char *msg;
325
326 if (a->errstr) {
327 return a->errstr;
328 }
329
330 if (a->errnum == 0)
331 return "Success";
332
333 msg = strerror(a->errnum);
334 if (msg) {
335 return msg;
336 } else {
337 return "unknown error";
338 }
339
340 return "unknown error";
341 }
342
lo_url_get_protocol(const char * url)343 char *lo_url_get_protocol(const char *url)
344 {
345 char *protocol, *ret;
346
347 if (!url) {
348 return NULL;
349 }
350
351 protocol = (char*) malloc(strlen(url));
352
353 if (sscanf(url, "osc://%s", protocol)) {
354 fprintf(stderr,
355 PACKAGE_NAME " warning: no protocol specified in URL, "
356 "assuming UDP.\n");
357 ret = strdup("udp");
358 } else if (sscanf(url, "osc.%[^:/[]", protocol)) {
359 ret = strdup(protocol);
360 } else {
361 ret = NULL;
362 }
363
364 free(protocol);
365
366 return ret;
367 }
368
lo_url_get_protocol_id(const char * url)369 int lo_url_get_protocol_id(const char *url)
370 {
371 if (!url) {
372 return -1;
373 }
374
375 if (!strncmp(url, "osc:", 4)) {
376 fprintf(stderr,
377 PACKAGE_NAME " warning: no protocol specified in URL, "
378 "assuming UDP.\n");
379 return LO_UDP; // should be LO_DEFAULT?
380 } else if (!strncmp(url, "osc.udp:", 8)) {
381 return LO_UDP;
382 } else if (!strncmp(url, "osc.tcp:", 8)) {
383 return LO_TCP;
384 } else if (!strncmp(url, "osc.unix:", 9)) {
385 return LO_UNIX;
386 }
387 return -1;
388 }
389
lo_url_get_hostname(const char * url)390 char *lo_url_get_hostname(const char *url)
391 {
392 char *hostname = (char*) malloc(strlen(url));
393
394 if (sscanf(url, "osc://%[^[:/]", hostname)) {
395 return hostname;
396 }
397 if (sscanf(url, "osc.%*[^:/]://[%[^]/]]", hostname)) {
398 return hostname;
399 }
400 if (sscanf(url, "osc.%*[^:/]://%[^[:/]", hostname)) {
401 return hostname;
402 }
403
404 /* doesnt look like an OSC URL */
405 free(hostname);
406
407 return NULL;
408 }
409
lo_url_get_port(const char * url)410 char *lo_url_get_port(const char *url)
411 {
412 char *port = (char*) malloc(strlen(url));
413
414 if (sscanf(url, "osc://%*[^:]:%[0-9]", port) > 0) {
415 return port;
416 }
417 if (sscanf(url, "osc.%*[^:]://%*[^:]:%[0-9]", port) > 0) {
418 return port;
419 }
420 if (sscanf(url, "osc://[%*[^]]]:%[0-9]", port) > 0) {
421 return port;
422 }
423 if (sscanf(url, "osc.%*[^:]://[%*[^]]]:%[0-9]", port) > 0) {
424 return port;
425 }
426 if (sscanf(url, "osc://:%[0-9]", port) > 0) {
427 return port;
428 }
429 if (sscanf(url, "osc.%*[^:]://:%[0-9]", port) > 0) {
430 return port;
431 }
432
433 /* doesnt look like an OSC URL with port number */
434 free(port);
435
436 return NULL;
437 }
438
lo_url_get_path(const char * url)439 char *lo_url_get_path(const char *url)
440 {
441 char *path = (char*) malloc(strlen(url));
442
443 if (sscanf(url, "osc://%*[^:]:%*[0-9]%s", path)) {
444 return path;
445 }
446 if (sscanf(url, "osc.%*[^:]://%*[^:]:%*[0-9]%s", path) == 1) {
447 return path;
448 }
449 if (sscanf(url, "osc.unix://%*[^/]%s", path)) {
450 int i = strlen(path)-1;
451 if (path[i]=='/') // remove trailing slash
452 path[i] = 0;
453 return path;
454 }
455 if (sscanf(url, "osc.%*[^:]://%s", path)) {
456 int i = strlen(path)-1;
457 if (path[i]=='/') // remove trailing slash
458 path[i] = 0;
459 return path;
460 }
461
462 /* doesnt look like an OSC URL with port number and path */
463 free(path);
464
465 return NULL;
466 }
467
lo_address_set_ttl(lo_address t,int ttl)468 void lo_address_set_ttl(lo_address t, int ttl)
469 {
470 if (t->protocol == LO_UDP)
471 t->ttl = ttl;
472 }
473
lo_address_get_ttl(lo_address t)474 int lo_address_get_ttl(lo_address t)
475 {
476 return t->ttl;
477 }
478
lo_address_set_tcp_nodelay(lo_address t,int enable)479 int lo_address_set_tcp_nodelay(lo_address t, int enable)
480 {
481 int r = (t->flags & LO_NODELAY) != 0;
482 lo_address_set_flags(t, enable
483 ? t->flags | LO_NODELAY
484 : t->flags & ~LO_NODELAY);
485 return r;
486 }
487
lo_address_set_stream_slip(lo_address t,int enable)488 int lo_address_set_stream_slip(lo_address t, int enable)
489 {
490 int r = (t->flags & LO_SLIP) != 0;
491 lo_address_set_flags(t, enable
492 ? t->flags | LO_SLIP
493 : t->flags & ~LO_SLIP);
494 return r;
495 }
496
497 static
lo_address_set_flags(lo_address t,int flags)498 void lo_address_set_flags(lo_address t, int flags)
499 {
500 if (((t->flags & LO_NODELAY) != (flags & LO_NODELAY))
501 && t->socket > 0)
502 {
503 int option = (t->flags & LO_NODELAY)!=0;
504 setsockopt(t->socket, IPPROTO_TCP, TCP_NODELAY,
505 (const char*)&option, sizeof(option));
506 }
507
508 t->flags = (lo_proto_flags) flags;
509 }
510
511 #ifdef ENABLE_IPV6
is_dotted_ipv4_address(const char * address)512 static int is_dotted_ipv4_address (const char* address)
513 {
514 int a[4];
515 return sscanf(address, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
516 }
517 #endif
518
lo_address_copy(lo_address to,lo_address from)519 void lo_address_copy(lo_address to, lo_address from)
520 {
521 /* Initialize all members that are not auto-initialized when the
522 * lo_address is used. (e.g. resolving addrinfo) */
523 memset(to, 0, sizeof(struct _lo_address));
524 to->socket = from->socket;
525 if (from->host) {
526 free(to->host);
527 to->host = strdup(from->host);
528 }
529 if (from->port) {
530 free(to->port);
531 to->port = strdup(from->port);
532 }
533 to->protocol = from->protocol;
534 to->ttl = from->ttl;
535 to->addr = from->addr;
536 if (from->addr.iface)
537 to->addr.iface = strdup(from->addr.iface);
538 }
539
lo_address_init_with_sockaddr(lo_address a,void * sa,size_t sa_len,int sock,int prot)540 void lo_address_init_with_sockaddr(lo_address a,
541 void *sa, size_t sa_len,
542 int sock, int prot)
543 {
544 int err = 0;
545 assert(a != NULL);
546 lo_address_free_mem(a);
547 a->host = (char*) malloc(INET_ADDRSTRLEN);
548 a->port = (char*) malloc(8);
549
550 err = getnameinfo((struct sockaddr *)sa, sa_len,
551 a->host, INET_ADDRSTRLEN, a->port, 8,
552 NI_NUMERICHOST | NI_NUMERICSERV);
553
554 if (err) {
555 free(a->host);
556 free(a->port);
557 a->host = a->port = 0;
558 }
559
560 a->socket = sock;
561 a->protocol = prot;
562 }
563
lo_address_resolve(lo_address a)564 int lo_address_resolve(lo_address a)
565 {
566 int ret;
567
568 if (a->protocol == LO_UDP || a->protocol == LO_TCP) {
569 struct addrinfo *ai=NULL;
570 struct addrinfo hints;
571 const char* host = lo_address_get_hostname(a);
572 #ifdef ENABLE_IPV6
573 char hosttmp[7+16+1]; // room for ipv6 prefix + a dotted quad
574 #endif
575
576 memset(&hints, 0, sizeof(hints));
577 #ifdef ENABLE_IPV6
578 hints.ai_family = PF_UNSPEC;
579
580 if (is_dotted_ipv4_address(host)) {
581 host = hosttmp;
582 strcpy(hosttmp, "::FFFF:");
583 strncpy(hosttmp + 7, lo_address_get_hostname(a), 16);
584 }
585 #else
586 hints.ai_family = PF_INET;
587 #endif
588 hints.ai_socktype =
589 a->protocol == LO_UDP ? SOCK_DGRAM : SOCK_STREAM;
590
591 if ((ret = getaddrinfo(host, lo_address_get_port(a), &hints, &ai))) {
592 a->errnum = ret;
593 a->errstr = gai_strerror(ret);
594 a->ai = NULL;
595 a->ai_first = NULL;
596 return -1;
597 }
598
599 a->ai = ai;
600 a->ai_first = ai;
601 }
602
603 return 0;
604 }
605
606 #if defined(WIN32) || defined(_MSC_VER) || defined(HAVE_GETIFADDRS)
607
lo_address_set_iface(lo_address t,const char * iface,const char * ip)608 int lo_address_set_iface(lo_address t, const char *iface, const char *ip)
609 {
610 int fam;
611 if (!t->ai) {
612 lo_address_resolve(t);
613 if (!t->ai)
614 return 2; // Need the address family to continue
615 }
616 fam = t->ai->ai_family;
617
618 return lo_inaddr_find_iface(&t->addr, fam, iface, ip);
619 }
620
lo_inaddr_find_iface(lo_inaddr t,int fam,const char * iface,const char * ip)621 int lo_inaddr_find_iface(lo_inaddr t, int fam,
622 const char *iface, const char *ip)
623 {
624 #if defined(WIN32) || defined(_MSC_VER)
625 ULONG size;
626 int tries;
627 PIP_ADAPTER_ADDRESSES paa, aa;
628 DWORD rc;
629 int found;
630 #endif
631
632 union {
633 struct in_addr addr;
634 #ifdef ENABLE_IPV6
635 struct in6_addr addr6;
636 #endif
637 } a;
638
639 if (ip) {
640 #ifdef HAVE_INET_PTON
641 int rc = inet_pton(fam, ip, &a);
642 if (rc!=1)
643 return (rc<0) ? 3 : 4;
644 #else
645 if (fam!=AF_INET6)
646 *((unsigned long*)&a.addr) = inet_addr(ip);
647 #endif
648 }
649
650 #if defined(WIN32) || defined(_MSC_VER)
651
652 /* Start with recommended 15k buffer for GetAdaptersAddresses. */
653 size = 15*1024/2;
654 tries = 3;
655 paa = malloc(size*2);
656 rc = ERROR_SUCCESS-1;
657 while (rc!=ERROR_SUCCESS && paa && tries-- > 0) {
658 size *= 2;
659 paa = realloc(paa, size);
660 rc = GetAdaptersAddresses(fam, 0, 0, paa, &size);
661 }
662 if (rc!=ERROR_SUCCESS)
663 return 2;
664
665 aa = paa;
666 found=0;
667 while (aa && rc==ERROR_SUCCESS) {
668 if (iface) {
669 if (strcmp(iface, aa->AdapterName)==0)
670 found = 1;
671 else {
672 WCHAR ifaceW[256];
673 MultiByteToWideChar(CP_ACP, 0, iface, strlen(iface),
674 ifaceW, 256);
675 if (lstrcmpW(ifaceW, aa->FriendlyName)==0)
676 found = 1;
677 }
678 }
679 if (ip) {
680 PIP_ADAPTER_UNICAST_ADDRESS pua = aa->FirstUnicastAddress;
681 while (pua && !found) {
682 if (fam==AF_INET) {
683 struct sockaddr_in *s =
684 (struct sockaddr_in*)pua->Address.lpSockaddr;
685 if (fam == s->sin_family
686 && memcmp(&a.addr, &s->sin_addr,
687 sizeof(struct in_addr))==0) {
688 memcpy(&t->a.addr, &s->sin_addr,
689 sizeof(struct in_addr));
690 found = 1;
691 }
692 }
693 #ifdef ENABLE_IPV6
694 else if (fam==AF_INET6) {
695 struct sockaddr_in6 *s =
696 (struct sockaddr_in6*)pua->Address.lpSockaddr;
697 if (fam == s->sin6_family
698 && memcmp(&a.addr6, &s->sin6_addr,
699 sizeof(struct in6_addr))==0) {
700 memcpy(&t->a.addr6, &s->sin6_addr,
701 sizeof(struct in6_addr));
702 found = 1;
703 }
704 }
705 #endif
706 pua = pua->Next;
707 }
708 }
709
710 if (aa && found) {
711 t->iface = strdup(aa->AdapterName);
712 if (!ip && aa->FirstUnicastAddress) {
713 PIP_ADAPTER_UNICAST_ADDRESS pua = aa->FirstUnicastAddress;
714 while (pua) {
715 struct sockaddr_in *s =
716 (struct sockaddr_in*)pua->Address.lpSockaddr;
717 if (s->sin_family==fam) {
718 if (fam==AF_INET) {
719 memcpy(&t->a.addr, &s->sin_addr,
720 sizeof(struct in_addr));
721 break;
722 }
723 #ifdef ENABLE_IPV6
724 else if (fam==AF_INET6) {
725 struct sockaddr_in6 *s6 =
726 (struct sockaddr_in6*)pua->Address.lpSockaddr;
727 memcpy(&t->a.addr6, &s6->sin6_addr,
728 sizeof(struct in6_addr));
729 break;
730 }
731 #endif
732 }
733 pua = pua->Next;
734 }
735 }
736 break;
737 }
738
739 aa = aa->Next;
740 }
741
742 if (paa) free(paa);
743
744 return !found;
745
746 #else // !WIN32
747
748 struct ifaddrs *ifa, *ifa_list;
749 if (getifaddrs(&ifa_list)==-1)
750 return 5;
751 ifa = ifa_list;
752
753 int found = 0;
754 while (ifa) {
755 if (!ifa->ifa_addr) {
756 ifa = ifa->ifa_next;
757 continue;
758 }
759 if (ip) {
760 if (ifa->ifa_addr->sa_family == AF_INET && fam == AF_INET)
761 {
762 if (memcmp(&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr,
763 &a.addr, sizeof(struct in_addr))==0) {
764 found = 1;
765 t->size = sizeof(struct in_addr);
766 memcpy(&t->a, &a, t->size);
767 break;
768 }
769 }
770 #ifdef ENABLE_IPV6
771 else if (ifa->ifa_addr->sa_family == AF_INET6 && fam == AF_INET6)
772 {
773 if (memcmp(&((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr,
774 &a.addr6, sizeof(struct in6_addr))==0) {
775 found = 1;
776 t->size = sizeof(struct in6_addr);
777 memcpy(&t->a, &a, t->size);
778 break;
779 }
780 }
781 #endif
782 }
783 if (iface) {
784 if (ifa->ifa_addr->sa_family == fam
785 && strcmp(ifa->ifa_name, iface)==0)
786 {
787 if (fam==AF_INET) {
788 found = 1;
789 t->size = sizeof(struct in_addr);
790 memcpy(&t->a, &((struct sockaddr_in*)
791 ifa->ifa_addr)->sin_addr,
792 t->size);
793 break;
794 }
795 #ifdef ENABLE_IPV6
796 else if (fam==AF_INET6) {
797 found = 1;
798 t->size = sizeof(struct in6_addr);
799 memcpy(&t->a, &((struct sockaddr_in6*)
800 ifa->ifa_addr)->sin6_addr,
801 t->size);
802 break;
803 }
804 #endif
805 }
806 }
807 ifa = ifa->ifa_next;
808 }
809
810 if (found && ifa->ifa_name) {
811 if (t->iface) free(t->iface);
812 t->iface = strdup(ifa->ifa_name);
813 }
814
815 freeifaddrs(ifa_list);
816 return !found;
817 #endif
818 }
819
lo_address_get_iface(lo_address t)820 const char* lo_address_get_iface(lo_address t)
821 {
822 if (t)
823 return t->addr.iface;
824 return 0;
825 }
826
827 #endif // HAVE_GETIFADDRS
828
829 /* vi:set ts=8 sts=4 sw=4: */
830