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