static struct intf_config *if_addr_parse(char *s) { str name; char *c; sockaddr_t addr, adv; struct intf_config *ifa; /* name */ c = strchr(s, '/'); if (c) { *c++ = 0; str_init(&name, s); s = c; } else str_init(&name, "default"); /* advertised address */ c = strchr(s, '!'); if (c) *c++ = 0; /* address */ if (sockaddr_parse_any(&addr, s)) return NULL; adv = addr; if (c) { if (sockaddr_parse_any(&adv, c)) return NULL; } ifa = g_slice_alloc0(sizeof(*ifa)); ifa->name = name; ifa->address.addr = addr; ifa->address.advertised = adv; ifa->port_min = port_min; ifa->port_max = port_max; return ifa; }
static int if_addr_parse(GQueue *q, char *s, struct ifaddrs *ifas) { str name; char *c; sockaddr_t *addr, adv; GQueue addrs = G_QUEUE_INIT; struct intf_config *ifa; /* name */ c = strchr(s, '/'); if (c) { *c++ = 0; str_init(&name, s); s = c; } else str_init(&name, "default"); /* advertised address */ c = strchr(s, '!'); if (c) *c++ = 0; /* address */ addr = g_slice_alloc(sizeof(*addr)); if (!sockaddr_parse_any(addr, s)) { if (is_addr_unspecified(addr)) return -1; g_queue_push_tail(&addrs, addr); } else { // could be an interface name? ilog(LOG_DEBUG, "Could not parse '%s' as network address, checking to see if " "it's an interface", s); for (struct ifaddrs *ifa = ifas; ifa; ifa = ifa->ifa_next) { if (strcmp(ifa->ifa_name, s)) continue; if (!(ifa->ifa_flags & IFF_UP)) continue; if (!ifa->ifa_addr) continue; if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *sin = (void *) ifa->ifa_addr; addr->family = __get_socket_family_enum(SF_IP4); addr->u.ipv4 = sin->sin_addr; } else if (ifa->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *sin = (void *) ifa->ifa_addr; if (sin->sin6_scope_id) continue; // link-local addr->family = __get_socket_family_enum(SF_IP6); addr->u.ipv6 = sin->sin6_addr; } else continue; // got one ilog(LOG_DEBUG, "Determined address %s for interface '%s'", sockaddr_print_buf(addr), s); g_queue_push_tail(&addrs, addr); addr = g_slice_alloc(sizeof(*addr)); } // free last unused entry g_slice_free1(sizeof(*addr), addr); } if (!addrs.length) // nothing found return -1; ZERO(adv); if (c) { if (sockaddr_parse_any(&adv, c)) return -1; if (is_addr_unspecified(&adv)) return -1; } while ((addr = g_queue_pop_head(&addrs))) { ifa = g_slice_alloc0(sizeof(*ifa)); ifa->name = name; ifa->local_address.addr = *addr; ifa->local_address.type = socktype_udp; ifa->advertised_address.addr = adv; if (is_addr_unspecified(&ifa->advertised_address.addr)) ifa->advertised_address.addr = *addr; ifa->advertised_address.type = ifa->local_address.type; ifa->port_min = rtpe_config.port_min; ifa->port_max = rtpe_config.port_max; // handle "base:suffix" separation for round-robin selection ifa->name_rr_spec = ifa->name; str_token(&ifa->name_base, &ifa->name_rr_spec, ':'); // sets name_rr_spec to null string if no ':' found g_queue_push_tail(q, ifa); g_slice_free1(sizeof(*addr), addr); } return 0; }