diff --git a/daemon/Makefile b/daemon/Makefile index 8ef84b3af..33a9e7cfb 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -63,8 +63,8 @@ endif SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \ bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \ - crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c rtcp_xr.c - + crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c socket.c \ + media_socket.c rtcp_xr.c OBJS= $(SRCS:.c=.o) diff --git a/daemon/aux.h b/daemon/aux.h index 615a4474d..8bb367e61 100644 --- a/daemon/aux.h +++ b/daemon/aux.h @@ -40,15 +40,6 @@ -/*** TYPES ***/ - -struct endpoint { - struct in6_addr ip46; - u_int16_t port; -}; - - - /*** GLOBALS ***/ extern __thread struct timeval g_now; @@ -191,22 +182,6 @@ INLINE const char *__get_enum_array_text(const char * const *array, unsigned int -/*** SOCKET/FD HELPERS ***/ - -INLINE void nonblock(int fd) { - fcntl(fd, F_SETFL, O_NONBLOCK); -} -INLINE void reuseaddr(int fd) { - int one = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); -} -INLINE void ipv6only(int fd, int yn) { - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yn, sizeof(yn)); -} - - - - /*** GENERIC HELPERS ***/ INLINE char chrtoupper(char x) { @@ -250,223 +225,28 @@ INLINE int rlim(int res, rlim_t val) { #define DF IPF ":%u" #define DP(x) IPP((x).sin_addr.s_addr), ntohs((x).sin_port) -INLINE void in4_to_6(struct in6_addr *o, u_int32_t ip) { - o->s6_addr32[0] = 0; - o->s6_addr32[1] = 0; - o->s6_addr32[2] = htonl(0xffff); - o->s6_addr32[3] = ip; -} -INLINE u_int32_t in6_to_4(const struct in6_addr *a) { - return a->s6_addr32[3]; -} - -INLINE void smart_ntop(char *o, const struct in6_addr *a, size_t len) { - const char *r; +/* XXX to be removed */ - if (IN6_IS_ADDR_V4MAPPED(a)) - r = inet_ntop(AF_INET, &(a->s6_addr32[3]), o, len); - else - r = inet_ntop(AF_INET6, a, o, len); - - if (!r) - *o = '\0'; -} - -INLINE char *smart_ntop_buf(const struct in6_addr *a) { - char *buf = get_thread_buf(); - smart_ntop(buf, a, THREAD_BUF_SIZE); - return buf; -} - -INLINE char *smart_ntop_p(char *o, const struct in6_addr *a, size_t len) { - int l; - - if (IN6_IS_ADDR_V4MAPPED(a)) { - if (inet_ntop(AF_INET, &(a->s6_addr32[3]), o, len)) - return o + strlen(o); - *o = '\0'; - return NULL; - } - else { - *o = '['; - if (!inet_ntop(AF_INET6, a, o+1, len-2)) { - *o = '\0'; - return NULL; - } - l = strlen(o); - o[l] = ']'; - o[l+1] = '\0'; - return o + (l + 1); - } -} - -INLINE char *smart_ntop_p_buf(const struct in6_addr *a) { - char *buf = get_thread_buf(); - smart_ntop_p(buf, a, THREAD_BUF_SIZE); - return buf; -} - -INLINE void smart_ntop_ap(char *o, const struct in6_addr *a, unsigned int port, size_t len) { - char *e; - - e = smart_ntop_p(o, a, len); - if (!e) - return; - if (len - (e - o) < 7) - return; - sprintf(e, ":%u", port); -} - -INLINE void smart_ntop_port(char *o, const struct sockaddr_in6 *a, size_t len) { - return smart_ntop_ap(o, &a->sin6_addr, ntohs(a->sin6_port), len); -} - -INLINE char *smart_ntop_port_buf(const struct sockaddr_in6 *a) { - char *buf = get_thread_buf(); - smart_ntop_port(buf, a, THREAD_BUF_SIZE); - return buf; -} - -INLINE char *smart_ntop_ap_buf(const struct in6_addr *a, unsigned int port) { - char *buf = get_thread_buf(); - smart_ntop_ap(buf, a, port, THREAD_BUF_SIZE); - return buf; -} - -INLINE char *smart_ntop_ep_buf(const struct endpoint *ep) { - char *buf = get_thread_buf(); - smart_ntop_ap(buf, &ep->ip46, ep->port, THREAD_BUF_SIZE); - return buf; -} - -INLINE int smart_pton(int af, char *src, void *dst) { - char *p; - int ret; - - if (af == AF_INET6) { - if (src[0] == '[' && (p = strchr(src, ']'))) { - *p = '\0'; - ret = inet_pton(af, src+1, dst); - *p = ']'; - return ret; - } - } - return inet_pton(af, src, dst); -} - -INLINE int pton_46(struct in6_addr *dst, const char *src, int *family) { - u_int32_t in4; - - if (inet_pton(AF_INET6, src, dst) == 1) { - if (family) - *family = AF_INET6; - return 0; - } - in4 = inet_addr(src); - if (in4 == INADDR_NONE) - return -1; - in4_to_6(dst, in4); - if (family) - *family = AF_INET; - return 0; -} - -INLINE int parse_ip_port(u_int32_t *ip, u_int16_t *port, char *s) { - char *p = NULL; - int ret = -1; - - p = strchr(s, ':'); - if (p) { - *p++ = 0; - *ip = inet_addr(s); - if (*ip == -1) - goto out; - *port = atoi(p); - } - else { - *ip = 0; - if (strchr(s, '.')) - goto out; - *port = atoi(s); - } - if (!*port) - goto out; - - ret = 0; - -out: - if (p) - *--p = ':'; - return ret; -} - -INLINE int parse_ip6_port(struct in6_addr *ip6, u_int16_t *port, char *s) { - u_int32_t ip; - char *p; - - if (!parse_ip_port(&ip, port, s)) { - if (ip) - in4_to_6(ip6, ip); - else - *ip6 = in6addr_any; - return 0; - } - if (*s != '[') - return -1; - p = strstr(s, "]:"); - if (!p) - return -1; - *p = '\0'; - if (inet_pton(AF_INET6, s+1, ip6) != 1) - goto fail; - *p = ']'; - *port = atoi(p+2); - if (!*port) - return -1; - - return 0; - -fail: - *p = ']'; - return -1; -} - -INLINE int is_addr_unspecified(const struct in6_addr *a) { - if (a->s6_addr32[0]) - return 0; - if (a->s6_addr32[1]) - return 0; - if (a->s6_addr32[3]) - return 0; - if (a->s6_addr32[2] == 0 || a->s6_addr32[2] == htonl(0xffff)) - return 1; - return 0; -} - -INLINE int family_from_address(const struct in6_addr *a) { - if (IN6_IS_ADDR_V4MAPPED(a)) - return AF_INET; - return AF_INET6; -} +#include "socket.h" -INLINE void msg_mh_src(const struct in6_addr *src, struct msghdr *mh) { +INLINE void msg_mh_src(const sockaddr_t *src, struct msghdr *mh) { struct cmsghdr *ch; struct in_pktinfo *pi; struct in6_pktinfo *pi6; - struct sockaddr_in6 *sin6; + //struct sockaddr_in6 *sin6; - sin6 = mh->msg_name; + //sin6 = mh->msg_name; ch = CMSG_FIRSTHDR(mh); ZERO(*ch); - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + if (src->family->af == AF_INET) { ch->cmsg_len = CMSG_LEN(sizeof(*pi)); ch->cmsg_level = IPPROTO_IP; ch->cmsg_type = IP_PKTINFO; pi = (void *) CMSG_DATA(ch); ZERO(*pi); - pi->ipi_spec_dst.s_addr = in6_to_4(src); + pi->ipi_spec_dst = src->u.ipv4; mh->msg_controllen = CMSG_SPACE(sizeof(*pi)); } @@ -477,7 +257,7 @@ INLINE void msg_mh_src(const struct in6_addr *src, struct msghdr *mh) { pi6 = (void *) CMSG_DATA(ch); ZERO(*pi6); - pi6->ipi6_addr = *src; + pi6->ipi6_addr = src->u.ipv6; mh->msg_controllen = CMSG_SPACE(sizeof(*pi6)); } diff --git a/daemon/call.c b/daemon/call.c index fe5879126..85ae62842 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -327,7 +327,6 @@ static void __stream_unconfirm(struct packet_stream *ps); static void stream_unconfirm(struct packet_stream *ps); static void __monologue_destroy(struct call_monologue *monologue); static int monologue_destroy(struct call_monologue *ml); -static struct interface_address *get_interface_address(struct local_interface *lif, int family); @@ -339,7 +338,7 @@ static void stream_fd_closed(int fd, void *p, uintptr_t u) { int i; socklen_t j; - assert(sfd->fd.fd == fd); + assert(sfd->socket.fd == fd); c = sfd->call; if (!c) return; @@ -354,12 +353,16 @@ static void stream_fd_closed(int fd, void *p, uintptr_t u) { -INLINE void __re_address_translate(struct re_address *o, const struct endpoint *ep) { - o->family = family_from_address(&ep->ip46); +/* XXX unify this */ +INLINE void __re_address_translate(struct re_address *o, const sockaddr_t *address) { + o->family = address->family->af; if (o->family == AF_INET) - o->u.ipv4 = in6_to_4(&ep->ip46); + o->u.ipv4 = address->u.ipv4.s_addr; else - memcpy(o->u.ipv6, &ep->ip46, sizeof(o->u.ipv6)); + memcpy(o->u.ipv6, &address->u.ipv6, sizeof(o->u.ipv6)); +} +INLINE void __re_address_translate_ep(struct re_address *o, const endpoint_t *ep) { + __re_address_translate(o, &ep->address); o->port = ep->port; } @@ -379,7 +382,7 @@ void kernelize(struct packet_stream *stream) { struct call *call = stream->call; struct callmaster *cm = call->callmaster; struct packet_stream *sink = NULL; - struct interface_address *ifa; + struct local_intf *ifa; const char *nk_warn_msg; if (PS_ISSET(stream, KERNELIZED)) @@ -404,7 +407,7 @@ void kernelize(struct packet_stream *stream) { determine_handler(stream, sink); - if (is_addr_unspecified(&sink->advertised_endpoint.ip46) + if (is_addr_unspecified(&sink->advertised_endpoint.address) || !sink->advertised_endpoint.port) goto no_kernel; nk_warn_msg = "protocol not supported by kernel module"; @@ -416,7 +419,7 @@ void kernelize(struct packet_stream *stream) { if (PS_ISSET2(stream, STRICT_SOURCE, MEDIA_HANDOVER)) { mutex_lock(&stream->out_lock); - __re_address_translate(&reti.expected_src, &stream->endpoint); + __re_address_translate_ep(&reti.expected_src, &stream->endpoint); mutex_unlock(&stream->out_lock); if (PS_ISSET(stream, STRICT_SOURCE)) reti.src_mismatch = MSM_DROP; @@ -426,24 +429,18 @@ void kernelize(struct packet_stream *stream) { mutex_lock(&sink->out_lock); - reti.target_port = stream->sfd->fd.localport; + reti.target_port = stream->sfd->socket.local.port; reti.tos = call->tos; reti.rtcp_mux = MEDIA_ISSET(stream->media, RTCP_MUX); reti.dtls = MEDIA_ISSET(stream->media, DTLS); reti.stun = stream->media->ice_agent ? 1 : 0; - __re_address_translate(&reti.dst_addr, &sink->endpoint); - - reti.src_addr.family = reti.dst_addr.family; - reti.src_addr.port = sink->sfd->fd.localport; + ifa = g_atomic_pointer_get(&sink->media->local_intf); + __re_address_translate_ep(&reti.dst_addr, &sink->endpoint); + __re_address_translate(&reti.src_addr, &ifa->spec->address.addr); + reti.src_addr.port = sink->sfd->socket.local.port; reti.ssrc = sink->crypto.ssrc; - ifa = g_atomic_pointer_get(&sink->media->local_address); - if (reti.src_addr.family == AF_INET) - reti.src_addr.u.ipv4 = in6_to_4(&ifa->addr); - else - memcpy(reti.src_addr.u.ipv6, &ifa->addr, sizeof(reti.src_addr.u.ipv6)); - stream->handler->in->kernel(&reti.decrypt, stream); stream->handler->out->kernel(&reti.encrypt, sink); @@ -597,15 +594,15 @@ noop: } void stream_msg_mh_src(struct packet_stream *ps, struct msghdr *mh) { - struct interface_address *ifa; + struct local_intf *ifa; - ifa = g_atomic_pointer_get(&ps->media->local_address); - msg_mh_src(&ifa->addr, mh); + ifa = g_atomic_pointer_get(&ps->media->local_intf); + msg_mh_src(&ifa->spec->address.addr, mh); } /* XXX split this function into pieces */ /* called lock-free */ -static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsin, struct in6_addr *dst) { +static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin, const sockaddr_t *dst) { struct packet_stream *stream, *sink = NULL, *in_srtp, *out_srtp; @@ -613,7 +610,6 @@ static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsi int ret = 0, update = 0, stun_ret = 0, handler_ret = 0, muxed_rtcp = 0, rtcp = 0, unk = 0; int i; - struct sockaddr_in6 sin6; struct msghdr mh; struct iovec iov; unsigned char buf[256]; @@ -623,13 +619,13 @@ static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsi char *addr; struct endpoint endpoint; rewrite_func rwf_in, rwf_out; - struct interface_address *loc_addr; + struct local_intf *loc_addr; struct rtp_header *rtp_h; struct rtp_stats *rtp_s; call = sfd->call; cm = call->callmaster; - addr = smart_ntop_port_buf(fsin); + addr = endpoint_print_buf(fsin); rwlock_lock_r(&call->master_lock); @@ -803,8 +799,7 @@ loop_ok: if (PS_ISSET(stream, CONFIRMED)) { /* see if we need to compare the source address with the known endpoint */ if (PS_ISSET2(stream, STRICT_SOURCE, MEDIA_HANDOVER)) { - endpoint.ip46 = fsin->sin6_addr; - endpoint.port = ntohs(fsin->sin6_port); + endpoint = *fsin; mutex_lock(&stream->out_lock); int tmp = memcmp(&endpoint, &stream->endpoint, sizeof(endpoint)); @@ -839,28 +834,28 @@ update_peerinfo: mutex_lock(&stream->out_lock); update_addr: endpoint = stream->endpoint; - stream->endpoint.ip46 = fsin->sin6_addr; - stream->endpoint.port = ntohs(fsin->sin6_port); + stream->endpoint = *fsin; if (memcmp(&endpoint, &stream->endpoint, sizeof(endpoint))) update = 1; mutex_unlock(&stream->out_lock); /* check the destination address of the received packet against what we think our * local interface to use is */ - loc_addr = g_atomic_pointer_get(&media->local_address); - if (dst && memcmp(dst, &loc_addr->addr, sizeof(*dst))) { - struct interface_address *ifa; - ifa = get_interface_from_address(media->interface, dst); - if (!ifa) { - ilog(LOG_ERROR, "No matching local interface for destination address %s found", - smart_ntop_buf(dst)); - goto drop; - } - if (g_atomic_pointer_compare_and_exchange(&media->local_address, loc_addr, ifa)) { - ilog(LOG_INFO, "Switching local interface to %s", - smart_ntop_buf(dst)); - update = 1; - } + loc_addr = g_atomic_pointer_get(&media->local_intf); + if (dst && !sockaddr_eq(dst, &loc_addr->spec->address.addr)) { + // XXX restore this +// struct interface_address *ifa; +// ifa = get_interface_from_address(media->logical_intf, dst); +// if (!ifa) { +// ilog(LOG_ERROR, "No matching local interface for destination address %s found", +// smart_ntop_buf(dst)); +// goto drop; +// } +// if (g_atomic_pointer_compare_and_exchange(&media->local_address, loc_addr, ifa)) { +// ilog(LOG_INFO, "Switching local interface to %s", +// smart_ntop_buf(dst)); +// update = 1; +// } } @@ -877,7 +872,7 @@ forward: if (!sink || !sink->advertised_endpoint.port - || (is_addr_unspecified(&sink->advertised_endpoint.ip46) + || (is_addr_unspecified(&sink->advertised_endpoint.address) && !is_trickle_ice_address(&sink->advertised_endpoint)) || stun_ret || handler_ret < 0) goto drop; @@ -886,13 +881,6 @@ forward: mh.msg_control = buf; mh.msg_controllen = sizeof(buf); - ZERO(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = sink->endpoint.ip46; - sin6.sin6_port = htons(sink->endpoint.port); - mh.msg_name = &sin6; - mh.msg_namelen = sizeof(sin6); - mutex_unlock(&sink->out_lock); stream_msg_mh_src(sink, &mh); @@ -904,7 +892,7 @@ forward: mh.msg_iov = &iov; mh.msg_iovlen = 1; - ret = sendmsg(sink->sfd->fd.fd, &mh, 0); + ret = socket_sendmsg(&sink->sfd->socket, &mh, &sink->endpoint); if (ret == -1) { ret = 0; /* temp for address family mismatches */ @@ -960,10 +948,12 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { char control[128]; struct cmsghdr *cmh; struct in6_pktinfo *pi6; - struct in6_addr dst_buf, *dst; - struct in_pktinfo *pi; + struct in6_addr /*dst_buf,*/ *dst; + //struct in_pktinfo *pi; + endpoint_t ep; + sockaddr_t sa; - if (sfd->fd.fd != fd) + if (sfd->socket.fd != fd) goto out; log_info_stream_fd(sfd); @@ -1006,12 +996,13 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { dst = &pi6->ipi6_addr; goto got_dst; } - if (cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO) { - pi = (void *) CMSG_DATA(cmh); - in4_to_6(&dst_buf, pi->ipi_addr.s_addr); - dst = &dst_buf; - goto got_dst; - } + // XXX +// if (cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO) { +// pi = (void *) CMSG_DATA(cmh); +// in4_to_6(&dst_buf, pi->ipi_addr.s_addr); +// dst = &dst_buf; +// goto got_dst; +// } } ilog(LOG_WARNING, "No pkt_info present in received UDP packet, cannot handle packet"); @@ -1019,7 +1010,11 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { got_dst: str_init_len(&s, buf + RTP_BUFFER_HEAD_ROOM, ret); - ret = stream_packet(sfd, &s, &sin6_src, dst); + // XXX + ep.port = ntohs(sin6_src.sin6_port); + ep.address.u.ipv6 = sin6_src.sin6_addr; + sa.u.ipv6 = *dst; + ret = stream_packet(sfd, &s, &ep, &sa); if (ret < 0) { ilog(LOG_WARNING, "Write error on RTP socket: %s", strerror(-ret)); call_destroy(sfd->call); @@ -1132,9 +1127,9 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { if (css == CSS_ICE) timestamp = &ps->media->ice_agent->last_activity; - if (hlp->ports[sfd->fd.localport]) + if (hlp->ports[sfd->socket.local.port]) goto next; - hlp->ports[sfd->fd.localport] = sfd; + hlp->ports[sfd->socket.local.port] = sfd; obj_hold(sfd); no_sfd: @@ -1320,7 +1315,7 @@ void kill_calls_timer(GSList *list, struct callmaster *m) { if (url_prefix) { snprintf(url_buf, sizeof(url_buf), "%s%s%s", - url_prefix, smart_ntop_p_buf(&ca->created_from_addr.sin6_addr), + url_prefix, sockaddr_print_buf(&ca->created_from_addr), url_suffix); } else @@ -1524,7 +1519,7 @@ struct callmaster *callmaster_new(struct poller *p) { c->totalstats.started = poller_now; mutex_init(&c->cngs_lock); - c->cngs_hash = g_hash_table_new(in6_addr_hash, in6_addr_eq); + c->cngs_hash = g_hash_table_new(g_sockaddr_hash, g_sockaddr_eq); return c; @@ -1535,103 +1530,25 @@ fail: -static void __set_tos(int fd, const struct call *c) { - int tos; - - setsockopt(fd, IPPROTO_IP, IP_TOS, &c->tos, sizeof(c->tos)); -#ifdef IPV6_TCLASS - tos = c->tos; - setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); -#else -#warning "Will not set IPv6 traffic class" -#endif -} - -static void __get_pktinfo(int fd) { - int x; - x = 1; - setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &x, sizeof(x)); - setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &x, sizeof(x)); -} - -static int get_port6(struct udp_fd *r, u_int16_t p, const struct call *c) { - int fd; - struct sockaddr_in6 sin; - - fd = socket(AF_INET6, SOCK_DGRAM, 0); - if (fd < 0) - return -1; - - nonblock(fd); - reuseaddr(fd); - ipv6only(fd, 0); - __set_tos(fd, c); - __get_pktinfo(fd); - - ZERO(sin); - sin.sin6_family = AF_INET6; - sin.sin6_port = htons(p); - if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) - goto fail; - - r->fd = fd; - - return 0; - -fail: - close(fd); - return -1; -} - -static int get_port(struct udp_fd *r, u_int16_t p, const struct call *c) { - int ret; - struct callmaster *m = c->callmaster; - - assert(r->fd == -1); - - __C_DBG("attempting to open port %u", p); - - if (bit_array_set(m->ports_used, p)) { - __C_DBG("port in use"); - return -1; - } - __C_DBG("port locked"); - - ret = get_port6(r, p, c); - - if (ret) { - __C_DBG("couldn't open port"); - bit_array_clear(m->ports_used, p); - return ret; - } - - r->localport = p; - - return 0; -} - -static void release_port(struct udp_fd *r, struct callmaster *m) { - if (r->fd == -1 || !r->localport) - return; - __C_DBG("releasing port %u", r->localport); - bit_array_clear(m->ports_used, r->localport); - close(r->fd); - r->fd = -1; - r->localport = 0; -} - -int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_start_port, const struct call *c) { +int __get_consecutive_ports(socket_t *array, int array_len, int wanted_start_port, + const struct call_media *media) +{ int i, j, cycle = 0; - struct udp_fd *it; + socket_t *it; int port; - struct callmaster *m = c->callmaster; + struct intf_spec *spec; + struct port_pool *pp; + const struct call *c = media->call; + const struct local_intf *lif = g_atomic_pointer_get(&media->local_intf); memset(array, -1, sizeof(*array) * array_len); + spec = lif->spec; + pp = &spec->port_pool; if (wanted_start_port > 0) port = wanted_start_port; else { - port = g_atomic_int_get(&m->lastport); + port = g_atomic_int_get(&pp->last_used); #if PORT_RANDOM_MIN && PORT_RANDOM_MAX port += PORT_RANDOM_MIN + (random() % (PORT_RANDOM_MAX - PORT_RANDOM_MIN)); #endif @@ -1639,8 +1556,8 @@ int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_star while (1) { if (!wanted_start_port) { - if (port < m->conf.port_min) - port = m->conf.port_min; + if (port < pp->min) + port = pp->min; if ((port & 1)) port++; } @@ -1648,30 +1565,30 @@ int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_star for (i = 0; i < array_len; i++) { it = &array[i]; - if (!wanted_start_port && port > m->conf.port_max) { + if (!wanted_start_port && port > pp->max) { port = 0; cycle++; goto release_restart; } - if (get_port(it, port++, c)) + if (get_port(it, port++, lif, c)) goto release_restart; } break; release_restart: for (j = 0; j < i; j++) - release_port(&array[j], m); + release_port(&array[j], lif); if (cycle >= 2 || wanted_start_port > 0) goto fail; } /* success */ - g_atomic_int_set(&m->lastport, port); + g_atomic_int_set(&pp->last_used, port); ilog(LOG_DEBUG, "Opened ports %u..%u for media relay", - array[0].localport, array[array_len - 1].localport); + array[0].local.port, array[array_len - 1].local.port); return 0; fail: @@ -1719,27 +1636,28 @@ static struct call_media *__get_media(struct call_monologue *ml, GList **it, con static void stream_fd_free(void *p) { struct stream_fd *f = p; - struct callmaster *m = f->call->callmaster; - release_port(&f->fd, m); + release_port(&f->socket, f->local_intf); crypto_cleanup(&f->crypto); dtls_connection_cleanup(&f->dtls); obj_put(f->call); } -struct stream_fd *__stream_fd_new(struct udp_fd *fd, struct call *call) { +struct stream_fd *__stream_fd_new(socket_t *fd, struct call_media *media) { + struct call *call = media->call; struct stream_fd *sfd; struct poller_item pi; struct poller *po = call->callmaster->poller; sfd = obj_alloc0("stream_fd", sizeof(*sfd), stream_fd_free); - sfd->fd = *fd; + sfd->socket = *fd; sfd->call = obj_get(call); + sfd->local_intf = g_atomic_pointer_get(&media->local_intf); call->stream_fds = g_slist_prepend(call->stream_fds, sfd); /* hand over ref */ ZERO(pi); - pi.fd = sfd->fd.fd; + pi.fd = sfd->socket.fd; pi.obj = &sfd->obj; pi.readable = stream_fd_readable; pi.closed = stream_fd_closed; @@ -1754,10 +1672,9 @@ static struct endpoint_map *__get_endpoint_map(struct call_media *media, unsigne { GSList *l; struct endpoint_map *em; - struct udp_fd fd_arr[16]; + socket_t fd_arr[16]; unsigned int i; struct stream_fd *sfd; - struct call *call = media->call; for (l = media->endpoint_maps; l; l = l->next) { em = l->data; @@ -1772,15 +1689,15 @@ static struct endpoint_map *__get_endpoint_map(struct call_media *media, unsigne if (!ep) /* creating wildcard map */ break; /* handle zero endpoint address */ - if (is_addr_unspecified(&ep->ip46) || is_addr_unspecified(&em->endpoint.ip46)) { + if (is_addr_unspecified(&ep->address) || is_addr_unspecified(&em->endpoint.address)) { if (ep->port != em->endpoint.port) continue; } else if (memcmp(&em->endpoint, ep, sizeof(*ep))) continue; if (em->sfds.length >= num_ports) { - if (is_addr_unspecified(&em->endpoint.ip46)) - em->endpoint.ip46 = ep->ip46; + if (is_addr_unspecified(&em->endpoint.address)) + em->endpoint.address = ep->address; return em; } /* endpoint matches, but not enough ports. flush existing ports @@ -1802,12 +1719,12 @@ static struct endpoint_map *__get_endpoint_map(struct call_media *media, unsigne alloc: if (num_ports > G_N_ELEMENTS(fd_arr)) return NULL; - if (__get_consecutive_ports(fd_arr, num_ports, 0, media->call)) + if (__get_consecutive_ports(fd_arr, num_ports, 0, media)) return NULL; __C_DBG("allocating stream_fds for %u ports", num_ports); for (i = 0; i < num_ports; i++) { - sfd = __stream_fd_new(&fd_arr[i], call); + sfd = __stream_fd_new(&fd_arr[i], media); g_queue_push_tail(&em->sfds, sfd); /* not referenced */ } @@ -2337,7 +2254,7 @@ static void __set_all_tos(struct call *c) { for (l = c->stream_fds; l; l = l->next) { sfd = l->data; - __set_tos(sfd->fd.fd, c); + set_tos(sfd->socket.fd, c->tos); } } @@ -2365,32 +2282,32 @@ static void __tos_change(struct call *call, const struct sdp_ng_flags *flags) { static void __init_interface(struct call_media *media, const str *ifname) { /* we're holding master_lock in W mode here, so we can safely ignore the * atomic ops */ - struct interface_address *ifa = (void *) media->local_address; + struct local_intf *ifa = (void *) media->local_intf; - if (!media->interface || !ifa) + if (!media->logical_intf || !ifa) goto get; if (!ifname || !ifname->s) return; - if (!str_cmp_str(&media->interface->name, ifname)) + if (!str_cmp_str(&media->logical_intf->name, ifname)) return; get: - media->interface = get_local_interface(media->call->callmaster, ifname, media->desired_family); - if (!media->interface) { + media->logical_intf = get_logical_interface(ifname, media->desired_family); + if (!media->logical_intf) { /* legacy support */ if (!str_cmp(ifname, "internal")) - media->desired_family = AF_INET; + media->desired_family = __get_socket_family_enum(SF_IP4); else if (!str_cmp(ifname, "external")) - media->desired_family = AF_INET6; + media->desired_family = __get_socket_family_enum(SF_IP6); else ilog(LOG_WARNING, "Interface '"STR_FORMAT"' not found, using default", STR_FMT(ifname)); - media->interface = get_local_interface(media->call->callmaster, NULL, media->desired_family); + media->logical_intf = get_logical_interface(NULL, media->desired_family); } - media->local_address = ifa = get_interface_address(media->interface, media->desired_family); + media->local_intf = ifa = get_interface_address(media->logical_intf, media->desired_family); if (!ifa) { ilog(LOG_WARNING, "No usable address in interface '"STR_FORMAT"' found, using default", STR_FMT(ifname)); - media->local_address = ifa = get_any_interface_address(media->interface, media->desired_family); - media->desired_family = family_from_address(&ifa->addr); + media->local_intf = ifa = get_any_interface_address(media->logical_intf, media->desired_family); + media->desired_family = ifa->spec->address.addr.family; } } @@ -2547,7 +2464,7 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams, __generate_crypto(flags, media, other_media); /* deduct address family from stream parameters received */ - other_media->desired_family = family_from_address(&sp->rtp_endpoint.ip46); + other_media->desired_family = sp->rtp_endpoint.address.family; /* for outgoing SDP, use "direction"/DF or default to what was offered */ if (!media->desired_family) media->desired_family = other_media->desired_family; @@ -2585,7 +2502,7 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams, __disable_streams(other_media, num_ports); goto init; } - if (is_addr_unspecified(&sp->rtp_endpoint.ip46) && !is_trickle_ice_address(&sp->rtp_endpoint)) { + if (is_addr_unspecified(&sp->rtp_endpoint.address) && !is_trickle_ice_address(&sp->rtp_endpoint)) { /* Zero endpoint address, equivalent to setting the media stream * to sendonly or inactive */ MEDIA_CLEAR(media, RECV); @@ -2636,7 +2553,7 @@ static void __unkernelize(struct packet_stream *p) { return; if (p->call->callmaster->conf.kernelfd >= 0) - kernel_del_stream(p->call->callmaster->conf.kernelfd, p->sfd->fd.localport); + kernel_del_stream(p->call->callmaster->conf.kernelfd, p->sfd->socket.local.port); PS_CLEAR(p, KERNELIZED); } @@ -2811,7 +2728,7 @@ void call_destroy(struct call *c) { if (PS_ISSET(ps, FALLBACK_RTCP)) continue; - char *addr = smart_ntop_p_buf(&ps->endpoint.ip46); + char *addr = sockaddr_print_buf(&ps->endpoint.address); if (_log_facility_cdr) { const char* protocol = (!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? "rtcp" : "rtp"; @@ -2828,7 +2745,8 @@ void call_destroy(struct call *c) { "ml%i_midx%u_%s_in_tos_tclass=%" PRIu8 ", ", cdrlinecnt, md->index, protocol, addr, cdrlinecnt, md->index, protocol, ps->endpoint.port, - cdrlinecnt, md->index, protocol, (unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0), + cdrlinecnt, md->index, protocol, + (ps->sfd ? ps->sfd->socket.local.port : 0), cdrlinecnt, md->index, protocol, atomic64_get(&ps->stats.packets), cdrlinecnt, md->index, protocol, @@ -2881,7 +2799,8 @@ void call_destroy(struct call *c) { "ml%i_midx%u_%s_in_tos_tclass=%" PRIu8 ", ", cdrlinecnt, md->index, protocol, addr, cdrlinecnt, md->index, protocol, ps->endpoint.port, - cdrlinecnt, md->index, protocol, (unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0), + cdrlinecnt, md->index, protocol, + (ps->sfd ? ps->sfd->socket.local.port : 0), cdrlinecnt, md->index, protocol, atomic64_get(&ps->stats.packets), cdrlinecnt, md->index, protocol, @@ -2897,9 +2816,9 @@ void call_destroy(struct call *c) { } } - ilog(LOG_INFO, "--------- Port %5u <> %15s:%-5hu%s, " + ilog(LOG_INFO, "--------- Port %5u <> %15s:%-5u%s, " ""UINT64F" p, "UINT64F" b, "UINT64F" e, "UINT64F" last_packet", - (unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0), + (unsigned int) (ps->sfd ? ps->sfd->socket.local.port : 0), addr, ps->endpoint.port, (!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "", atomic64_get(&ps->stats.packets), @@ -3017,7 +2936,7 @@ void call_destroy(struct call *c) { while (c->stream_fds) { sfd = c->stream_fds->data; c->stream_fds = g_slist_delete_link(c->stream_fds, c->stream_fds); - poller_del_item(p, sfd->fd.fd); + poller_del_item(p, sfd->socket.fd); obj_put(sfd); } @@ -3026,10 +2945,10 @@ void call_destroy(struct call *c) { +/* XXX unify and move these */ static int call_stream_address4(char *o, struct packet_stream *ps, enum stream_address_format format, - int *len, struct interface_address *ifa) + int *len, struct local_intf *ifa) { - u_int32_t ip4; int l = 0; if (format == SAF_NG) { @@ -3037,14 +2956,13 @@ static int call_stream_address4(char *o, struct packet_stream *ps, enum stream_a l = 4; } - if (is_addr_unspecified(&ps->advertised_endpoint.ip46) + if (is_addr_unspecified(&ps->advertised_endpoint.address) && !is_trickle_ice_address(&ps->advertised_endpoint)) { strcpy(o + l, "0.0.0.0"); l += 7; } else { - ip4 = in6_to_4(&ifa->advertised); - l += sprintf(o + l, IPF, IPP(ip4)); + l += sprintf(o + l, "%s", sockaddr_print_buf(&ifa->spec->address.advertised)); } *len = l; @@ -3052,7 +2970,7 @@ static int call_stream_address4(char *o, struct packet_stream *ps, enum stream_a } static int call_stream_address6(char *o, struct packet_stream *ps, enum stream_address_format format, - int *len, struct interface_address *ifa) + int *len, struct local_intf *ifa) { int l = 0; @@ -3061,14 +2979,13 @@ static int call_stream_address6(char *o, struct packet_stream *ps, enum stream_a l += 4; } - if (is_addr_unspecified(&ps->advertised_endpoint.ip46) + if (is_addr_unspecified(&ps->advertised_endpoint.address) && !is_trickle_ice_address(&ps->advertised_endpoint)) { strcpy(o + l, "::"); l += 2; } else { - inet_ntop(AF_INET6, &ifa->advertised, o + l, 45); /* lies ... */ - l += strlen(o + l); + l += sprintf(o + l, "%s", sockaddr_print_buf(&ifa->spec->address.advertised)); } *len = l; @@ -3077,23 +2994,23 @@ static int call_stream_address6(char *o, struct packet_stream *ps, enum stream_a int call_stream_address46(char *o, struct packet_stream *ps, enum stream_address_format format, - int *len, struct interface_address *ifa) + int *len, struct local_intf *ifa) { struct packet_stream *sink; sink = packet_stream_sink(ps); - if (ifa->family == AF_INET) + if (ifa->spec->address.addr.family->af == AF_INET) /* XXX fix */ return call_stream_address4(o, sink, format, len, ifa); return call_stream_address6(o, sink, format, len, ifa); } int call_stream_address(char *o, struct packet_stream *ps, enum stream_address_format format, int *len) { - struct interface_address *ifa; + struct local_intf *ifa; struct call_media *media; media = ps->media; - ifa = g_atomic_pointer_get(&media->local_address); + ifa = g_atomic_pointer_get(&media->local_intf); if (!ifa) return -1; @@ -3642,115 +3559,3 @@ const struct transport_protocol *transport_protocol(const str *s) { out: return NULL; } - -static unsigned int __local_interface_hash(const void *p) { - const struct local_interface *lif = p; - return str_hash(&lif->name) ^ lif->preferred_family; -} -static int __local_interface_eq(const void *a, const void *b) { - const struct local_interface *A = a, *B = b; - return str_equal(&A->name, &B->name) && A->preferred_family == B->preferred_family; -} -static GQueue *__interface_list_for_family(struct callmaster *m, int family) { - return (family == AF_INET6) ? &m->interface_list_v6 : &m->interface_list_v4; -} -static void __interface_append(struct callmaster *m, struct interface_address *ifa, int family) { - struct local_interface *lif; - GQueue *q; - struct interface_address *ifc; - - lif = get_local_interface(m, &ifa->interface_name, family); - - if (!lif) { - lif = g_slice_alloc0(sizeof(*lif)); - lif->name = ifa->interface_name; - lif->preferred_family = family; - lif->addr_hash = g_hash_table_new(in6_addr_hash, in6_addr_eq); - g_hash_table_insert(m->interfaces, lif, lif); - if (ifa->family == family) { - q = __interface_list_for_family(m, family); - g_queue_push_tail(q, lif); - } - } - - if (!ifa->ice_foundation.s) - ice_foundation(ifa); - - ifc = g_slice_alloc(sizeof(*ifc)); - *ifc = *ifa; - ifc->preference = lif->list.length; - - g_queue_push_tail(&lif->list, ifc); - g_hash_table_insert(lif->addr_hash, &ifc->addr, ifc); -} - -/* XXX interface handling should go somewhere else */ -void callmaster_config_init(struct callmaster *m) { - GList *l; - struct interface_address *ifa; - - m->interfaces = g_hash_table_new(__local_interface_hash, __local_interface_eq); - - /* build primary lists first */ - for (l = m->conf.interfaces->head; l; l = l->next) { - ifa = l->data; - __interface_append(m, ifa, ifa->family); - } - - /* then append to each other as lower-preference alternatives */ - for (l = m->conf.interfaces->head; l; l = l->next) { - ifa = l->data; - if (ifa->family == AF_INET) - __interface_append(m, ifa, AF_INET6); - else if (ifa->family == AF_INET6) - __interface_append(m, ifa, AF_INET); - else - abort(); - } -} - -struct local_interface *get_local_interface(struct callmaster *m, const str *name, int family) { - struct local_interface d, *lif; - - if (!name || !name->s) { - GQueue *q; - q = __interface_list_for_family(m, family); - if (q->head) - return q->head->data; - q = __interface_list_for_family(m, AF_INET); - if (q->head) - return q->head->data; - q = __interface_list_for_family(m, AF_INET6); - if (q->head) - return q->head->data; - return NULL; - } - - d.name = *name; - d.preferred_family = family; - - lif = g_hash_table_lookup(m->interfaces, &d); - return lif; -} - -static struct interface_address *get_interface_address(struct local_interface *lif, int family) { - const GQueue *q; - - q = &lif->list; - if (!q->head) - return NULL; - return q->head->data; -} - -/* safety fallback */ -struct interface_address *get_any_interface_address(struct local_interface *lif, int family) { - struct interface_address *ifa; - - ifa = get_interface_address(lif, family); - if (ifa) - return ifa; - ifa = get_interface_address(lif, AF_INET); - if (ifa) - return ifa; - return get_interface_address(lif, AF_INET6); -} diff --git a/daemon/call.h b/daemon/call.h index e6ea9df55..043143e39 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -16,6 +16,8 @@ #include "compat.h" #include "control_ng.h" #include "aux.h" +#include "socket.h" +#include "media_socket.h" enum termination_reason { UNKNOWN=0, @@ -236,10 +238,6 @@ struct totalstats { struct timeval total_average_call_dur; }; -struct udp_fd { - int fd; - u_int16_t localport; -}; struct stream_params { unsigned int index; /* starting with 1 */ str type; @@ -250,7 +248,7 @@ struct stream_params { struct crypto_params crypto; unsigned int sdes_tag; str direction[2]; - int desired_family; + sockfamily_t *desired_family; struct dtls_fingerprint fingerprint; unsigned int sp_flags; GQueue rtp_payload_types; /* slice-alloc'd */ @@ -259,15 +257,6 @@ struct stream_params { str ice_pwd; }; -struct stream_fd { - struct obj obj; - struct udp_fd fd; /* RO */ - struct call *call; /* RO */ - struct packet_stream *stream; /* LOCK: call->master_lock */ - struct crypto_context crypto; /* IN direction, LOCK: stream->in_lock */ - struct dtls_connection dtls; /* LOCK: stream->in_lock */ -}; - struct endpoint_map { struct endpoint endpoint; GQueue sfds; @@ -334,13 +323,13 @@ struct call_media { unsigned int index; /* RO */ str type; /* RO */ const struct transport_protocol *protocol; - int desired_family; - struct local_interface *interface; + sockfamily_t *desired_family; + const struct logical_intf *logical_intf; /* local_address is protected by call->master_lock in W mode, but may * still be modified if the lock is held in R mode, therefore we use * atomic ops to access it when holding an R lock. */ - volatile struct interface_address *local_address; + const volatile struct local_intf *local_intf; struct ice_agent *ice_agent; @@ -402,31 +391,12 @@ struct call { time_t ml_deleted; unsigned char tos; char *created_from; - struct sockaddr_in6 created_from_addr; -}; - -struct local_interface { - str name; - int preferred_family; - GQueue list; /* struct interface_address */ - GHashTable *addr_hash; -}; -struct interface_address { - str interface_name; - int family; - struct in6_addr addr; - struct in6_addr advertised; - str ice_foundation; - char foundation_buf[16]; - unsigned int preference; /* starting with 0 */ + sockaddr_t created_from_addr; }; struct callmaster_config { int kernelfd; int kernelid; - GQueue *interfaces; /* struct interface_address */ - int port_min; - int port_max; unsigned int timeout; unsigned int silent_timeout; unsigned int delete_delay; @@ -434,8 +404,7 @@ struct callmaster_config { char *b2b_url; unsigned char default_tos; enum xmlrpc_format fmt; - u_int32_t graphite_ip; - u_int16_t graphite_port; + endpoint_t graphite_ep; int graphite_interval; }; @@ -445,13 +414,6 @@ struct callmaster { rwlock_t hashlock; GHashTable *callhash; - GHashTable *interfaces; /* struct local_interface */ - GQueue interface_list_v4; /* ditto */ - GQueue interface_list_v6; /* ditto */ - - volatile unsigned int lastport; - BIT_ARRAY_DECLARE(ports_used, 0x10000); - /* XXX rework these */ struct stats statsps; /* per second stats, running timer */ struct stats stats; /* copied from statsps once a second */ @@ -478,7 +440,6 @@ struct call_stats { struct callmaster *callmaster_new(struct poller *); -void callmaster_config_init(struct callmaster *); void stream_msg_mh_src(struct packet_stream *, struct msghdr *); void callmaster_get_all_calls(struct callmaster *m, GQueue *q); @@ -487,8 +448,8 @@ void calls_dump_redis(struct callmaster *); struct call_monologue *__monologue_create(struct call *call); void __monologue_tag(struct call_monologue *ml, const str *tag); void __monologue_viabranch(struct call_monologue *ml, const str *viabranch); -struct stream_fd *__stream_fd_new(struct udp_fd *fd, struct call *call); -int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_start_port, const struct call *c); +struct stream_fd *__stream_fd_new(socket_t *fd, struct call_media *); +int __get_consecutive_ports(socket_t *array, int array_len, int wanted_start_port, const struct call_media *); struct packet_stream *__packet_stream_new(struct call *call); @@ -507,14 +468,7 @@ void call_media_unkernelize(struct call_media *media); void kernelize(struct packet_stream *); int call_stream_address(char *, struct packet_stream *, enum stream_address_format, int *); int call_stream_address46(char *o, struct packet_stream *ps, enum stream_address_format format, - int *len, struct interface_address *ifa); -struct local_interface *get_local_interface(struct callmaster *m, const str *name, int familiy); -INLINE struct interface_address *get_interface_from_address(struct local_interface *lif, - const struct in6_addr *addr) -{ - return g_hash_table_lookup(lif->addr_hash, addr); -} -struct interface_address *get_any_interface_address(struct local_interface *lif, int family); + int *len, struct local_intf *ifa); const struct transport_protocol *transport_protocol(const str *s); @@ -570,7 +524,7 @@ INLINE str *call_str_init_dup(struct call *c, char *s) { return call_str_dup(c, &t); } INLINE void callmaster_exclude_port(struct callmaster *m, u_int16_t p) { - bit_array_set(m->ports_used, p); + //bit_array_set(m->ports_used, p); /* XXX fix */ } INLINE struct packet_stream *packet_stream_sink(struct packet_stream *ps) { struct packet_stream *ret; diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index ef361ccef..a89183900 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -66,7 +66,7 @@ found: if (format == SAF_TCP) call_stream_address_gstring(o, ps, format); - port = ps->sfd ? ps->sfd->fd.localport : 0; + port = ps->sfd ? ps->sfd->socket.local.port : 0; g_string_append_printf(o, (format == 1) ? "%i " : " %i", port); if (format == SAF_UDP) { @@ -83,7 +83,6 @@ out: } static int addr_parse_udp(struct stream_params *sp, char **out) { - u_int32_t ip4; const char *cp; char c; int i; @@ -95,13 +94,11 @@ static int addr_parse_udp(struct stream_params *sp, char **out) { sp->protocol = &transport_protocols[PROTO_RTP_AVP]; if (out[RE_UDP_UL_ADDR4] && *out[RE_UDP_UL_ADDR4]) { - ip4 = inet_addr(out[RE_UDP_UL_ADDR4]); - if (ip4 == -1) + if (sockaddr_parse_any(&sp->rtp_endpoint.address, out[RE_UDP_UL_ADDR4])) goto fail; - in4_to_6(&sp->rtp_endpoint.ip46, ip4); } else if (out[RE_UDP_UL_ADDR6] && *out[RE_UDP_UL_ADDR6]) { - if (inet_pton(AF_INET6, out[RE_UDP_UL_ADDR6], &sp->rtp_endpoint.ip46) != 1) + if (sockaddr_parse_any(&sp->rtp_endpoint.address, out[RE_UDP_UL_ADDR4])) goto fail; } else @@ -137,7 +134,7 @@ fail: } static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_opmode opmode, const char* addr, - const struct sockaddr_in6 *sin) + const endpoint_t *sin) { struct call *c; struct call_monologue *monologue; @@ -162,7 +159,7 @@ static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_o if (!c->created_from && addr) { c->created_from = call_strdup(c, addr); - c->created_from_addr = *sin; + c->created_from_addr = sin->address; } monologue = call_get_mono_dialogue(c, &fromtag, &totag, NULL); @@ -213,7 +210,7 @@ out: return ret; } -str *call_update_udp(char **out, struct callmaster *m, const char* addr, const struct sockaddr_in6 *sin) { +str *call_update_udp(char **out, struct callmaster *m, const char* addr, const endpoint_t *sin) { return call_update_lookup_udp(out, m, OP_OFFER, addr, sin); } str *call_lookup_udp(char **out, struct callmaster *m) { @@ -236,7 +233,6 @@ static void info_parse(const char *s, GHashTable *ih, struct callmaster *m) { static int streams_parse_func(char **a, void **ret, void *p) { struct stream_params *sp; - u_int32_t ip; int *i; i = p; @@ -246,12 +242,9 @@ static int streams_parse_func(char **a, void **ret, void *p) { SP_SET(sp, RECV); sp->protocol = &transport_protocols[PROTO_RTP_AVP]; - ip = inet_addr(a[0]); - if (ip == -1) + if (endpoint_parse_port_any(&sp->rtp_endpoint, a[0], atoi(a[1]))) goto fail; - in4_to_6(&sp->rtp_endpoint.ip46, ip); - sp->rtp_endpoint.port = atoi(a[1]); sp->index = ++(*i); sp->consecutive_ports = 1; @@ -638,13 +631,13 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu out->transport_protocol = transport_protocol(&out->transport_protocol_str); bencode_get_alt(input, "media-address", "media address", &out->media_address); if (bencode_get_alt(input, "address-family", "address family", &out->address_family_str)) - out->address_family = address_family(&out->address_family_str); + out->address_family = get_socket_family_rfc(&out->address_family_str); out->tos = bencode_dictionary_get_integer(input, "TOS", 256); } static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, enum call_opmode opmode, const char* addr, - const struct sockaddr_in6 *sin) + const endpoint_t *sin) { str sdp, fromtag, totag = STR_NULL, callid, viabranch; char *errstr; @@ -687,7 +680,7 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster if (!call->created_from && addr) { call->created_from = call_strdup(call, addr); - call->created_from_addr = *sin; + call->created_from_addr = sin->address; } /* At least the random ICE strings are contained within the call struct, so we * need to hold a ref until we're done sending the reply */ @@ -736,7 +729,7 @@ out: } const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, const char* addr, - const struct sockaddr_in6 *sin) + const endpoint_t *sin) { return call_offer_answer_ng(input, m, output, OP_OFFER, addr, sin); } @@ -797,18 +790,11 @@ static void ng_stats(bencode_item_t *d, const struct stats *s, struct stats *tot atomic64_add_na(&totals->errors, atomic64_get(&s->errors)); } -static void ng_stats_endpoint(bencode_item_t *dict, const struct endpoint *ep) { - char buf[64]; - - if (IN6_IS_ADDR_V4MAPPED(&ep->ip46)) { - bencode_dictionary_add_string(dict, "family", "IPv4"); - inet_ntop(AF_INET, &(ep->ip46.s6_addr32[3]), buf, sizeof(buf)); - } - else { - bencode_dictionary_add_string(dict, "family", "IPv6"); - inet_ntop(AF_INET6, &ep->ip46, buf, sizeof(buf)); - } - bencode_dictionary_add_string_dup(dict, "address", buf); +static void ng_stats_endpoint(bencode_item_t *dict, const endpoint_t *ep) { + if (!ep->address.family) + return; + bencode_dictionary_add_string(dict, "family", ep->address.family->name); + bencode_dictionary_add_string_dup(dict, "address", sockaddr_print_buf(&ep->address)); bencode_dictionary_add_integer(dict, "port", ep->port); } @@ -826,7 +812,7 @@ static void ng_stats_stream(bencode_item_t *list, const struct packet_stream *ps dict = bencode_list_add_dictionary(list); if (ps->sfd) - bencode_dictionary_add_integer(dict, "local port", ps->sfd->fd.localport); + bencode_dictionary_add_integer(dict, "local port", ps->sfd->socket.local.port); ng_stats_endpoint(bencode_dictionary_add_dictionary(dict, "endpoint"), &ps->endpoint); ng_stats_endpoint(bencode_dictionary_add_dictionary(dict, "advertised endpoint"), &ps->advertised_endpoint); diff --git a/daemon/call_interfaces.h b/daemon/call_interfaces.h index 12db76fab..55f1d9a4a 100644 --- a/daemon/call_interfaces.h +++ b/daemon/call_interfaces.h @@ -6,6 +6,7 @@ #include #include "str.h" #include "bencode.h" +#include "socket.h" @@ -25,13 +26,13 @@ str *call_lookup_tcp(char **, struct callmaster *); void call_delete_tcp(char **, struct callmaster *); void calls_status_tcp(struct callmaster *, struct control_stream *); -str *call_update_udp(char **, struct callmaster *, const char*, const struct sockaddr_in6 *); +str *call_update_udp(char **, struct callmaster *, const char*, const endpoint_t *); str *call_lookup_udp(char **, struct callmaster *); str *call_delete_udp(char **, struct callmaster *); str *call_query_udp(char **, struct callmaster *); const char *call_offer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *, const char*, - const struct sockaddr_in6 *); + const endpoint_t *); const char *call_answer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); const char *call_delete_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); const char *call_query_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); diff --git a/daemon/cli.c b/daemon/cli.c index be4d46ea0..719b2c5b8 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -13,6 +13,7 @@ #include "log.h" #include "call.h" #include "cli.h" +#include "socket.h" #include "rtpengine_config.h" @@ -78,7 +79,7 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m struct control_ng_stats* cur = l->data; printlen = snprintf(replybuffer,(outbufend-replybuffer), " %10s | %10u | %10u | %10u | %10u | %10u | %10u | %10u \n", - smart_ntop_p_buf(&cur->proxy), + sockaddr_print_buf(&cur->proxy), cur->offer, cur->answer, cur->delete, @@ -180,11 +181,11 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m (double) ps->stats.delay_max / 1000000); } #else - printlen = snprintf(replybuffer,(outbufend-replybuffer), "------ Media #%u, port %5u <> %15s:%-5hu%s, " + printlen = snprintf(replybuffer,(outbufend-replybuffer), "------ Media #%u, port %5u <> %15s:%-5u%s, " ""UINT64F" p, "UINT64F" b, "UINT64F" e, "UINT64F" last_packet\n", md->index, - (unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0), - smart_ntop_p_buf(&ps->endpoint.ip46), ps->endpoint.port, + (unsigned int) (ps->sfd ? ps->sfd->socket.local.port : 0), + sockaddr_print_buf(&ps->endpoint.address), ps->endpoint.port, (!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "", atomic64_get(&ps->stats.packets), atomic64_get(&ps->stats.bytes), @@ -387,40 +388,28 @@ static void control_closed(int fd, void *p, uintptr_t u) { abort(); } -struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m) { +struct cli *cli_new(struct poller *p, const endpoint_t *ep, struct callmaster *m) { struct cli *c; - int fd; - struct sockaddr_in sin; + socket_t sock; struct poller_item i; if (!p || !m) return NULL; - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - return NULL; - - nonblock(fd); - reuseaddr(fd); - - ZERO(sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = ip; - sin.sin_port = htons(port); - if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) - goto fail; + if (open_socket(&sock, SOCK_STREAM, ep->port, &ep->address)) + return NULL; - if (listen(fd, 5)) + if (listen(sock.fd, 5)) goto fail; c = obj_alloc0("cli_udp", sizeof(*c), NULL); - c->fd = fd; + c->sock = sock; c->poller = p; c->callmaster = m; mutex_init(&c->lock); ZERO(i); - i.fd = fd; + i.fd = sock.fd; i.closed = control_closed; i.readable = cli_incoming; i.obj = &c->obj; @@ -433,6 +422,6 @@ struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callm fail2: obj_put(c); fail: - close(fd); + close_socket(&sock); return NULL; } diff --git a/daemon/cli.h b/daemon/cli.h index af562107a..e5065b4ca 100644 --- a/daemon/cli.h +++ b/daemon/cli.h @@ -1,18 +1,19 @@ #ifndef CLI_UDP_H_ #define CLI_UDP_H_ -#include +#include "socket.h" +#include "obj.h" struct cli { struct obj obj; struct callmaster *callmaster; - int fd; + socket_t sock; struct poller *poller; mutex_t lock; }; -struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m); +struct cli *cli_new(struct poller *p, const endpoint_t *, struct callmaster *m); #endif /* CLI_UDP_H_ */ diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 29ee575e7..70f6392c7 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -11,6 +11,7 @@ #include "call.h" #include "sdp.h" #include "call_interfaces.h" +#include "socket.h" static void pretty_print(bencode_item_t *el, GString *s) { @@ -58,7 +59,7 @@ static void pretty_print(bencode_item_t *el, GString *s) { } } -struct control_ng_stats* get_control_ng_stats(struct control_ng* c, const struct in6_addr *addr) { +struct control_ng_stats* get_control_ng_stats(struct control_ng* c, const sockaddr_t *addr) { struct callmaster *m = c->callmaster; struct control_ng_stats* cur; @@ -67,14 +68,14 @@ struct control_ng_stats* get_control_ng_stats(struct control_ng* c, const struct if (!cur) { cur = g_slice_alloc0(sizeof(struct control_ng_stats)); cur->proxy = *addr; - ilog(LOG_DEBUG,"Adding a proxy for control ng stats:%s", smart_ntop_p_buf(addr)); + ilog(LOG_DEBUG,"Adding a proxy for control ng stats:%s", sockaddr_print_buf(addr)); g_hash_table_insert(m->cngs_hash, &cur->proxy, cur); } mutex_unlock(&m->cngs_lock); return cur; } -static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 *sin, char *addr) { +static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin, char *addr) { struct control_ng *c = (void *) obj; bencode_buffer_t bencbuf; bencode_item_t *dict, *resp; @@ -84,7 +85,7 @@ static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 * struct iovec iov[3]; GString *log_str; - struct control_ng_stats* cur = get_control_ng_stats(c,&sin->sin6_addr); + struct control_ng_stats* cur = get_control_ng_stats(c,&sin->address); str_chr_str(&data, buf, ' '); if (!data.s || data.s == buf->s) { @@ -196,8 +197,6 @@ send_resp: send_only: ZERO(mh); - mh.msg_name = sin; - mh.msg_namelen = sizeof(*sin); mh.msg_iov = iov; mh.msg_iovlen = 3; @@ -208,7 +207,7 @@ send_only: iov[2].iov_base = to_send->s; iov[2].iov_len = to_send->len; - sendmsg(c->udp_listener.fd, &mh, 0); + socket_sendmsg(&c->udp_listener.sock, &mh, sin); if (resp) cookie_cache_insert(&c->cookie_cache, &cookie, &reply); @@ -224,7 +223,7 @@ out: -struct control_ng *control_ng_new(struct poller *p, struct in6_addr ip, u_int16_t port, struct callmaster *m) { +struct control_ng *control_ng_new(struct poller *p, const endpoint_t *ep, struct callmaster *m) { struct control_ng *c; if (!p || !m) @@ -235,7 +234,7 @@ struct control_ng *control_ng_new(struct poller *p, struct in6_addr ip, u_int16_ c->callmaster = m; cookie_cache_init(&c->cookie_cache); - if (udp_listener_init(&c->udp_listener, p, ip, port, control_ng_incoming, &c->obj)) + if (udp_listener_init(&c->udp_listener, p, ep, control_ng_incoming, &c->obj)) goto fail2; return c; diff --git a/daemon/control_ng.h b/daemon/control_ng.h index 611ab51e0..8020643f0 100644 --- a/daemon/control_ng.h +++ b/daemon/control_ng.h @@ -4,13 +4,14 @@ #include "obj.h" #include "cookie_cache.h" #include "udp_listener.h" +#include "socket.h" struct poller; struct callmaster; struct control_ng_stats { - struct in6_addr proxy; + sockaddr_t proxy; int ping; int offer; int answer; @@ -27,6 +28,6 @@ struct control_ng { struct udp_listener udp_listener; }; -struct control_ng *control_ng_new(struct poller *, struct in6_addr, u_int16_t, struct callmaster *); +struct control_ng *control_ng_new(struct poller *, const endpoint_t *, struct callmaster *); #endif diff --git a/daemon/control_tcp.c b/daemon/control_tcp.c index 06ff565dd..e21d6b2f2 100644 --- a/daemon/control_tcp.c +++ b/daemon/control_tcp.c @@ -16,6 +16,7 @@ #include "log.h" #include "call.h" #include "call_interfaces.h" +#include "socket.h" @@ -271,11 +272,10 @@ fail: } -struct control_tcp *control_tcp_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m) { - int fd; +struct control_tcp *control_tcp_new(struct poller *p, const endpoint_t *ep, struct callmaster *m) { + socket_t sock; struct control_tcp *c; struct poller_item i; - struct sockaddr_in sin; const char *errptr; int erroff; @@ -284,21 +284,10 @@ struct control_tcp *control_tcp_new(struct poller *p, u_int32_t ip, u_int16_t po if (!m) return NULL; - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) + if (open_socket(&sock, SOCK_STREAM, ep->port, &ep->address)) return NULL; - nonblock(fd); - reuseaddr(fd); - - ZERO(sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = ip; - sin.sin_port = htons(port); - if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) - goto fail; - - if (listen(fd, 5)) + if (listen(sock.fd, 5)) goto fail; @@ -310,13 +299,13 @@ struct control_tcp *control_tcp_new(struct poller *p, u_int32_t ip, u_int16_t po PCRE_DOLLAR_ENDONLY | PCRE_DOTALL, &errptr, &erroff, NULL); c->parse_ree = pcre_study(c->parse_re, 0, &errptr); - c->fd = fd; + c->fd = sock.fd; c->poller = p; c->callmaster = m; mutex_init(&c->lock); ZERO(i); - i.fd = fd; + i.fd = sock.fd; i.closed = control_closed; i.readable = control_incoming; i.obj = &c->obj; @@ -329,7 +318,7 @@ struct control_tcp *control_tcp_new(struct poller *p, u_int32_t ip, u_int16_t po fail2: obj_put(c); fail: - close(fd); + close_socket(&sock); return NULL; } diff --git a/daemon/control_tcp.h b/daemon/control_tcp.h index b595fd304..06b3c298f 100644 --- a/daemon/control_tcp.h +++ b/daemon/control_tcp.h @@ -11,6 +11,7 @@ #include "obj.h" #include "aux.h" +#include "socket.h" #define RE_TCP_RL_CMD 1 @@ -35,7 +36,7 @@ struct control_stream; -struct control_tcp *control_tcp_new(struct poller *, u_int32_t, u_int16_t, struct callmaster *); +struct control_tcp *control_tcp_new(struct poller *, const endpoint_t *, struct callmaster *); void control_stream_printf(struct control_stream *, const char *, ...) __attribute__ ((format (printf, 2, 3))); diff --git a/daemon/control_udp.c b/daemon/control_udp.c index 0fcf218ed..ae9996e77 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -17,9 +17,10 @@ #include "call.h" #include "udp_listener.h" #include "call_interfaces.h" +#include "socket.h" -static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 *sin, char *addr) { +static void control_udp_incoming(struct obj *obj, str *buf, const endpoint_t *sin, char *addr) { struct control_udp *u = (void *) obj; int ret; int ovec[100]; @@ -40,9 +41,8 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 pcre_get_substring_list(buf->s, ovec, ret, (const char ***) &out); + /* XXX abstraction for iovec sending */ ZERO(mh); - mh.msg_name = sin; - mh.msg_namelen = sizeof(*sin); mh.msg_iov = iov; iov[0].iov_base = (void *) out[RE_UDP_COOKIE]; @@ -62,7 +62,7 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 mh.msg_iovlen = 2; } - sendmsg(u->udp_listener.fd, &mh, 0); + socket_sendmsg(&u->udp_listener.sock, &mh, sin); pcre_free(out); @@ -77,7 +77,7 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 reply = cookie_cache_lookup(&u->cookie_cache, &cookie); if (reply) { ilog(LOG_INFO, "Detected command from udp:%s as a duplicate", addr); - sendto(u->udp_listener.fd, reply->s, reply->len, 0, (struct sockaddr *) sin, sizeof(*sin)); + socket_sendto(&u->udp_listener.sock, reply->s, reply->len, sin); free(reply); goto out; } @@ -97,8 +97,6 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 reply = call_query_udp(out, u->callmaster); else if (chrtoupper(out[RE_UDP_V_CMD][0]) == 'V') { ZERO(mh); - mh.msg_name = sin; - mh.msg_namelen = sizeof(*sin); mh.msg_iov = iov; mh.msg_iovlen = 2; @@ -124,11 +122,11 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 iov[2].iov_len = 9; mh.msg_iovlen++; } - sendmsg(u->udp_listener.fd, &mh, 0); + socket_sendmsg(&u->udp_listener.sock, &mh, sin); } if (reply) { - sendto(u->udp_listener.fd, reply->s, reply->len, 0, (struct sockaddr *) sin, sizeof(*sin)); + socket_sendto(&u->udp_listener.sock, reply->s, reply->len, sin); cookie_cache_insert(&u->cookie_cache, &cookie, reply); free(reply); } @@ -140,7 +138,7 @@ out: log_info_clear(); } -struct control_udp *control_udp_new(struct poller *p, struct in6_addr ip, u_int16_t port, struct callmaster *m) { +struct control_udp *control_udp_new(struct poller *p, const endpoint_t *ep, struct callmaster *m) { struct control_udp *c; const char *errptr; int erroff; @@ -172,7 +170,7 @@ struct control_udp *control_udp_new(struct poller *p, struct in6_addr ip, u_int1 cookie_cache_init(&c->cookie_cache); - if (udp_listener_init(&c->udp_listener, p, ip, port, control_udp_incoming, &c->obj)) + if (udp_listener_init(&c->udp_listener, p, ep, control_udp_incoming, &c->obj)) goto fail2; return c; diff --git a/daemon/control_udp.h b/daemon/control_udp.h index a4cb6a54a..f38faf938 100644 --- a/daemon/control_udp.h +++ b/daemon/control_udp.h @@ -13,6 +13,7 @@ #include "aux.h" #include "cookie_cache.h" #include "udp_listener.h" +#include "socket.h" @@ -60,7 +61,7 @@ struct control_udp { -struct control_udp *control_udp_new(struct poller *, struct in6_addr, u_int16_t, struct callmaster *); +struct control_udp *control_udp_new(struct poller *, const endpoint_t *, struct callmaster *); diff --git a/daemon/dtls.c b/daemon/dtls.c index 3e25bd09b..2c9d902f8 100644 --- a/daemon/dtls.c +++ b/daemon/dtls.c @@ -628,13 +628,12 @@ error: } /* called with call locked in W or R with ps->in_lock held */ -int dtls(struct packet_stream *ps, const str *s, struct sockaddr_in6 *fsin) { +int dtls(struct packet_stream *ps, const str *s, const endpoint_t *fsin) { struct dtls_connection *d; int ret; unsigned char buf[0x10000], ctrl[256]; struct msghdr mh; struct iovec iov; - struct sockaddr_in6 sin; if (!ps || !ps->sfd) return 0; @@ -665,7 +664,7 @@ int dtls(struct packet_stream *ps, const str *s, struct sockaddr_in6 *fsin) { ret = try_connect(d); if (ret == -1) { - ilog(LOG_ERROR, "DTLS error on local port %hu", ps->sfd->fd.localport); + ilog(LOG_ERROR, "DTLS error on local port %u", ps->sfd->socket.local.port); /* fatal error */ dtls_connection_cleanup(d); return 0; @@ -703,19 +702,12 @@ int dtls(struct packet_stream *ps, const str *s, struct sockaddr_in6 *fsin) { buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - if (!fsin) { - ZERO(sin); - sin.sin6_family = AF_INET6; - sin.sin6_addr = ps->endpoint.ip46; - sin.sin6_port = htons(ps->endpoint.port); - fsin = &sin; - } + if (!fsin) + fsin = &ps->endpoint; ZERO(mh); mh.msg_control = ctrl; mh.msg_controllen = sizeof(ctrl); - mh.msg_name = fsin; - mh.msg_namelen = sizeof(*fsin); mh.msg_iov = &iov; mh.msg_iovlen = 1; @@ -725,7 +717,7 @@ int dtls(struct packet_stream *ps, const str *s, struct sockaddr_in6 *fsin) { stream_msg_mh_src(ps, &mh); - sendmsg(ps->sfd->fd.fd, &mh, 0); + socket_sendmsg(&ps->sfd->socket, &mh, fsin); return 0; } @@ -733,7 +725,6 @@ int dtls(struct packet_stream *ps, const str *s, struct sockaddr_in6 *fsin) { /* call must be locked */ void dtls_shutdown(struct packet_stream *ps) { struct dtls_connection *d; - struct sockaddr_in6 sin; if (!ps || !ps->sfd) return; @@ -745,13 +736,8 @@ void dtls_shutdown(struct packet_stream *ps) { return; if (d->connected && d->ssl) { - ZERO(sin); - sin.sin6_family = AF_INET6; - sin.sin6_addr = ps->endpoint.ip46; - sin.sin6_port = htons(ps->endpoint.port); - SSL_shutdown(d->ssl); - dtls(ps, NULL, &sin); + dtls(ps, NULL, &ps->endpoint); } dtls_connection_cleanup(d); diff --git a/daemon/dtls.h b/daemon/dtls.h index e4223615c..17f1541a9 100644 --- a/daemon/dtls.h +++ b/daemon/dtls.h @@ -11,6 +11,7 @@ #include "compat.h" #include "str.h" #include "obj.h" +#include "socket.h" @@ -65,7 +66,7 @@ const struct dtls_hash_func *dtls_find_hash_func(const str *); struct dtls_cert *dtls_cert(void); int dtls_connection_init(struct packet_stream *, int active, struct dtls_cert *cert); -int dtls(struct packet_stream *, const str *s, struct sockaddr_in6 *sin); +int dtls(struct packet_stream *, const str *s, const endpoint_t *sin); void dtls_connection_cleanup(struct dtls_connection *); void dtls_shutdown(struct packet_stream *ps); diff --git a/daemon/graphite.c b/daemon/graphite.c index 82e8adcff..45a41e8ef 100644 --- a/daemon/graphite.c +++ b/daemon/graphite.c @@ -18,11 +18,11 @@ #include "log.h" #include "call.h" #include "graphite.h" +#include "socket.h" -static int graphite_sock=-1; +static socket_t graphite_sock; +static const endpoint_t *graphite_ep; static int connectinprogress=0; -static u_int32_t graphite_ipaddress; -static int graphite_port=0; static struct callmaster* cm=0; //struct totalstats totalstats_prev; static time_t next_run; @@ -33,65 +33,33 @@ void set_prefix(char* prefix) { graphite_prefix = prefix; } -int connect_to_graphite_server(u_int32_t ipaddress, int port) { +int connect_to_graphite_server(const endpoint_t *ep) { + graphite_ep = ep; + int rc; - if (graphite_sock>0) - close(graphite_sock); + ilog(LOG_INFO, "Connecting to graphite server %s", endpoint_print_buf(ep)); - graphite_sock=-1; - - int rc=0; - struct sockaddr_in sin; - memset(&sin,0,sizeof(sin)); - int val=1; - - graphite_ipaddress = ipaddress; - graphite_port = port; - - graphite_sock = socket(AF_INET, SOCK_STREAM,0); - if(graphite_sock<0) { - ilog(LOG_ERROR,"Couldn't make socket for connecting to graphite.Reason:%s\n",strerror(errno)); + rc = connect_socket_nb(&graphite_sock, SOCK_STREAM, ep); + if (rc == -1) { + ilog(LOG_ERROR,"Couldn't make socket for connecting to graphite."); return -1; } - - sin.sin_family=AF_INET; - sin.sin_addr.s_addr=graphite_ipaddress; - sin.sin_port=htons(graphite_port); - - rc = setsockopt(graphite_sock,SOL_SOCKET,SO_REUSEADDR, &val,sizeof(val)); - if(rc<0) { - ilog(LOG_ERROR,"Couldn't set sockopt for graphite descriptor."); - goto error; - } - - nonblock(graphite_sock); - - struct in_addr ip; - ip.s_addr = graphite_ipaddress; - ilog(LOG_INFO, "Connecting to graphite server %s at port:%i with fd:%i",inet_ntoa(ip),graphite_port,graphite_sock); - rc = connect(graphite_sock, (struct sockaddr *)&sin, sizeof(sin)); - if (rc==-1) { - ilog(LOG_WARN, "Connection information:%s\n",strerror(errno)); - if (errno==EINPROGRESS) { - connectinprogress=1; - return 0; - } - goto error; + if (rc == 0) + ilog(LOG_INFO, "Graphite server connected."); + else { + /* EINPROGRESS */ + ilog(LOG_INFO, "Connection to graphite is in progress."); + connectinprogress = 1; } return 0; - -error: - close(graphite_sock); - graphite_sock = -1; - return -1; } int send_graphite_data() { int rc=0; - if (graphite_sock < 0) { + if (graphite_sock.fd < 0) { ilog(LOG_ERROR,"Graphite socket is not connected."); return -1; } @@ -146,7 +114,7 @@ int send_graphite_data() { if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s.",graphite_prefix); ptr += rc; } rc = sprintf(ptr,"%s.totals.timeout_sess "UINT64F" %llu\n",hostname, atomic64_get_na(&ts.total_timeout_sess),(unsigned long long)g_now.tv_sec); ptr += rc; - rc = write(graphite_sock, data_to_send, ptr - data_to_send); + rc = write(graphite_sock.fd, data_to_send, ptr - data_to_send); if (rc<0) { ilog(LOG_ERROR,"Could not write to graphite socket. Disconnecting graphite server."); goto error; @@ -154,7 +122,7 @@ int send_graphite_data() { return 0; error: - close(graphite_sock); graphite_sock=-1; + close_socket(&graphite_sock); return -1; } @@ -167,33 +135,30 @@ void graphite_loop_run(struct callmaster* callmaster, int seconds) { int optval=0; socklen_t optlen=sizeof(optval); - if (connectinprogress && graphite_sock>0) { - FD_SET(graphite_sock,&wfds); + if (connectinprogress && graphite_sock.fd >= 0) { + FD_SET(graphite_sock.fd,&wfds); tv.tv_sec = 0; tv.tv_usec = 1000000; - rc = select (graphite_sock+1, NULL, &wfds, NULL, &tv); + rc = select (graphite_sock.fd+1, NULL, &wfds, NULL, &tv); if ((rc == -1) && (errno == EINTR)) { ilog(LOG_ERROR,"Error on the socket."); - close(graphite_sock); - graphite_sock=-1;connectinprogress=0; + close_socket(&graphite_sock); return; } else if (rc==0) { // timeout return; } else { - if (!FD_ISSET(graphite_sock,&wfds)) { + if (!FD_ISSET(graphite_sock.fd,&wfds)) { ilog(LOG_WARN,"fd active but not the graphite fd."); - close(graphite_sock); - graphite_sock=-1;connectinprogress=0; + close_socket(&graphite_sock); return; } - rc = getsockopt(graphite_sock, SOL_SOCKET, SO_ERROR, &optval, &optlen); + rc = getsockopt(graphite_sock.fd, SOL_SOCKET, SO_ERROR, &optval, &optlen); if (rc) ilog(LOG_ERROR,"getsockopt failure."); if (optval != 0) { - ilog(LOG_ERROR,"Socket connect failed. fd: %i, Reason: %s\n",graphite_sock, strerror(optval)); - close(graphite_sock); - graphite_sock=-1;connectinprogress=0; + ilog(LOG_ERROR,"Socket connect failed. fd: %i, Reason: %s\n",graphite_sock.fd, strerror(optval)); + close_socket(&graphite_sock); return; } ilog(LOG_INFO, "Graphite server connected."); @@ -213,15 +178,11 @@ void graphite_loop_run(struct callmaster* callmaster, int seconds) { if (!cm) cm = callmaster; - if (graphite_sock < 0 && !connectinprogress) { - rc = connect_to_graphite_server(graphite_ipaddress, graphite_port); - if (rc) { - close(graphite_sock); - graphite_sock=-1; - } + if (graphite_sock.fd < 0 && !connectinprogress) { + rc = connect_to_graphite_server(graphite_ep); } - if (graphite_sock>0 && !connectinprogress) { + if (graphite_sock.fd >= 0 && !connectinprogress) { rc = send_graphite_data(); if (rc<0) { ilog(LOG_ERROR,"Sending graphite data failed."); @@ -238,7 +199,7 @@ void graphite_loop(void *d) { cm->conf.graphite_interval=1; } - connect_to_graphite_server(cm->conf.graphite_ip,cm->conf.graphite_port); + connect_to_graphite_server(&cm->conf.graphite_ep); while (!g_shutdown) graphite_loop_run(cm,cm->conf.graphite_interval); // time in seconds diff --git a/daemon/graphite.h b/daemon/graphite.h index 67cf1b575..d5fb40fa4 100644 --- a/daemon/graphite.h +++ b/daemon/graphite.h @@ -10,7 +10,7 @@ #include "call.h" -int connect_to_graphite_server(u_int32_t ipaddress, int port); +int connect_to_graphite_server(const endpoint_t *ep); int send_graphite_data(); void graphite_loop_run(struct callmaster* cm, int seconds); void set_prefix(char* prefix); diff --git a/daemon/ice.c b/daemon/ice.c index 346a4602e..46452632f 100644 --- a/daemon/ice.c +++ b/daemon/ice.c @@ -28,7 +28,7 @@ #define PAIR_FORMAT STR_FORMAT":"STR_FORMAT":%lu" #define PAIR_FMT(p) \ - STR_FMT(&(p)->local_address->ice_foundation), \ + STR_FMT(&(p)->local_intf->spec->ice_foundation), \ STR_FMT(&(p)->remote_candidate->foundation), \ (p)->remote_candidate->component_id @@ -39,7 +39,7 @@ static void __ice_agent_free(void *p); static void create_random_ice_string(struct call *call, str *s, int len); static void __do_ice_checks(struct ice_agent *ag); static struct ice_candidate_pair *__pair_lookup(struct ice_agent *, struct ice_candidate *cand, - struct interface_address *ifa); + const struct local_intf *ifa); static void __recalc_pair_prios(struct ice_agent *ag); static void __role_change(struct ice_agent *ag, int new_controlling); static void __get_complete_components(GQueue *out, struct ice_agent *ag, GTree *t, unsigned int); @@ -88,18 +88,6 @@ enum ice_candidate_type ice_candidate_type(const str *s) { return ICT_UNKNOWN; } -enum ice_transport ice_transport(const str *s) { - if (!str_cmp(s, "udp")) - return ITP_UDP; -// if (!str_cmp(s, "tcp")) -// return ITP_TCP; - if (!str_cmp(s, "UDP")) - return ITP_UDP; -// if (!str_cmp(s, "TCP")) -// return ITP_TCP; - return ITP_UNKNOWN; -} - int ice_has_related(enum ice_candidate_type t) { if (t == ICT_HOST) return 0; @@ -109,7 +97,7 @@ int ice_has_related(enum ice_candidate_type t) { -static u_int64_t __ice_pair_priority(struct interface_address *ifa, struct ice_candidate *cand, +static u_int64_t __ice_pair_priority(const struct local_intf *ifa, struct ice_candidate *cand, int controlling) { u_int64_t g, d; @@ -126,7 +114,7 @@ static u_int64_t __ice_pair_priority(struct interface_address *ifa, struct ice_c return (MIN(g,d) << 32) + (MAX(g,d) << 1) + (g > d ? 1 : 0); } static void __do_ice_pair_priority(struct ice_candidate_pair *pair) { - pair->pair_priority = __ice_pair_priority(pair->local_address, pair->remote_candidate, + pair->pair_priority = __ice_pair_priority(pair->local_intf, pair->remote_candidate, AGENT_ISSET(pair->agent, CONTROLLING)); } static void __new_stun_transaction(struct ice_candidate_pair *pair) { @@ -144,19 +132,19 @@ static void __all_pairs_list(struct ice_agent *ag) { } /* agent must be locked */ -static struct ice_candidate_pair *__pair_candidate(struct interface_address *addr, struct ice_agent *ag, +static struct ice_candidate_pair *__pair_candidate(const struct local_intf *addr, struct ice_agent *ag, struct ice_candidate *cand, struct packet_stream *ps) { struct ice_candidate_pair *pair; - if (addr->family != family_from_address(&cand->endpoint.ip46)) + if (addr->spec->address.addr.family != cand->endpoint.address.family) return NULL; pair = g_slice_alloc0(sizeof(*pair)); pair->agent = ag; pair->remote_candidate = cand; - pair->local_address = addr; + pair->local_intf = addr; pair->packet_stream = ps; if (cand->component_id != 1) PAIR_SET(pair, FROZEN); @@ -168,7 +156,8 @@ static struct ice_candidate_pair *__pair_candidate(struct interface_address *add g_tree_insert(ag->all_pairs, pair, pair); ilog(LOG_DEBUG, "Created candidate pair "PAIR_FORMAT" between %s and %s, type %s", PAIR_FMT(pair), - smart_ntop_buf(&addr->addr), smart_ntop_ep_buf(&cand->endpoint), + sockaddr_print_buf(&addr->spec->address.addr), + endpoint_print_buf(&cand->endpoint), ice_candidate_type_str(cand->type)); return pair; @@ -176,22 +165,21 @@ static struct ice_candidate_pair *__pair_candidate(struct interface_address *add static unsigned int __pair_hash(const void *p) { const struct ice_candidate_pair *pair = p; - return g_direct_hash(pair->local_address) ^ g_direct_hash(pair->remote_candidate); + return g_direct_hash(pair->local_intf) ^ g_direct_hash(pair->remote_candidate); } static int __pair_equal(const void *a, const void *b) { const struct ice_candidate_pair *A = a, *B = b; - return A->local_address == B->local_address + return A->local_intf == B->local_intf && A->remote_candidate == B->remote_candidate; } static unsigned int __cand_hash(const void *p) { const struct ice_candidate *cand = p; - return in6_addr_hash(&cand->endpoint.ip46) ^ cand->endpoint.port ^ cand->component_id; + return endpoint_hash(&cand->endpoint) ^ cand->component_id; } static int __cand_equal(const void *a, const void *b) { const struct ice_candidate *A = a, *B = b; - return A->endpoint.port == B->endpoint.port - && A->component_id == B->component_id - && in6_addr_eq(&A->endpoint.ip46, &B->endpoint.ip46); + return endpoint_eq(&A->endpoint, &B->endpoint) + && A->component_id == B->component_id; } static unsigned int __found_hash(const void *p) { const struct ice_candidate *cand = p; @@ -223,9 +211,9 @@ static int __pair_prio_cmp(const void *a, const void *b) { if (A->remote_candidate->component_id > B->remote_candidate->component_id) return 1; /* highest local preference first, which is lowest number first */ - if (A->local_address->preference < B->local_address->preference) + if (A->local_intf->preference < B->local_intf->preference) return -1; - if (A->local_address->preference > B->local_address->preference) + if (A->local_intf->preference > B->local_intf->preference) return 1; return 0; } @@ -240,7 +228,7 @@ static void __ice_agent_initialize(struct ice_agent *ag) { ag->foundation_hash = g_hash_table_new(__found_hash, __found_equal); ag->agent_flags = 0; bf_copy(&ag->agent_flags, ICE_AGENT_CONTROLLING, &media->media_flags, MEDIA_FLAG_ICE_CONTROLLING); - ag->local_interface = media->interface; + ag->logical_intf = media->logical_intf; ag->desired_family = media->desired_family; ag->nominated_pairs = g_tree_new(__pair_prio_cmp); ag->valid_pairs = g_tree_new(__pair_prio_cmp); @@ -336,7 +324,7 @@ void ice_update(struct ice_agent *ag, struct stream_params *sp) { __ice_restart(ag); else if (ag->pwd[0].s && sp->ice_pwd.s && str_cmp_str(&ag->pwd[0], &sp->ice_pwd)) __ice_restart(ag); - else if (ag->local_interface != media->interface) + else if (ag->logical_intf != media->logical_intf) __ice_restart(ag); /* update remote info */ @@ -424,7 +412,7 @@ void ice_update(struct ice_agent *ag, struct stream_params *sp) { pair: if (!ps) continue; - for (k = ag->local_interface->list.head; k; k = k->next) { + for (k = ag->logical_intf->list.head; k; k = k->next) { /* skip duplicates here also */ if (__pair_lookup(ag, dup, k->data)) continue; @@ -586,7 +574,6 @@ static void __fail_pair(struct ice_candidate_pair *pair) { /* agent must NOT be locked, but call must be locked in R */ static void __do_ice_check(struct ice_candidate_pair *pair) { - struct sockaddr_in6 dst; struct packet_stream *ps = pair->packet_stream; struct ice_agent *ag = pair->agent; u_int32_t prio, transact[3]; @@ -597,12 +584,7 @@ static void __do_ice_check(struct ice_candidate_pair *pair) { if (!ag->pwd[0].s) return; - ZERO(dst); - dst.sin6_port = htons(pair->remote_candidate->endpoint.port); - dst.sin6_addr = pair->remote_candidate->endpoint.ip46; - dst.sin6_family = AF_INET6; - - prio = ice_priority(ICT_PRFLX, pair->local_address->preference, + prio = ice_priority(ICT_PRFLX, pair->local_intf->preference, pair->remote_candidate->component_id); mutex_lock(&ag->lock); @@ -633,12 +615,12 @@ static void __do_ice_check(struct ice_candidate_pair *pair) { ilog(LOG_DEBUG, "Sending %sICE/STUN request for candidate pair "PAIR_FORMAT" from %s to %s", PAIR_ISSET(pair, TO_USE) ? "nominating " : "", - PAIR_FMT(pair), smart_ntop_buf(&pair->local_address->addr), - smart_ntop_ep_buf(&pair->remote_candidate->endpoint)); + PAIR_FMT(pair), sockaddr_print_buf(&pair->local_intf->spec->address.addr), + endpoint_print_buf(&pair->remote_candidate->endpoint)); - stun_binding_request(&dst, transact, &ag->pwd[0], ag->ufrag, + stun_binding_request(&pair->remote_candidate->endpoint, transact, &ag->pwd[0], ag->ufrag, AGENT_ISSET(ag, CONTROLLING), tie_breaker, - prio, &pair->local_address->addr, ps->sfd->fd.fd, + prio, &pair->local_intf->spec->address.addr, &ps->sfd->socket, PAIR_ISSET(pair, TO_USE)); } @@ -802,13 +784,12 @@ static void __agent_shutdown(struct ice_agent *ag) { } /* agent must be locked for these */ -static struct ice_candidate *__cand_lookup(struct ice_agent *ag, const struct sockaddr_in6 *sin, +static struct ice_candidate *__cand_lookup(struct ice_agent *ag, const endpoint_t *sin, unsigned int component) { struct ice_candidate d; - d.endpoint.port = ntohs(sin->sin6_port); - d.endpoint.ip46 = sin->sin6_addr; + d.endpoint = *sin; d.component_id = component; return g_hash_table_lookup(ag->candidate_hash, &d); } @@ -822,11 +803,11 @@ static struct ice_candidate *__foundation_lookup(struct ice_agent *ag, const str return g_hash_table_lookup(ag->foundation_hash, &d); } static struct ice_candidate_pair *__pair_lookup(struct ice_agent *ag, struct ice_candidate *cand, - struct interface_address *ifa) + const struct local_intf *ifa) { struct ice_candidate_pair p; - p.local_address = ifa; + p.local_intf = ifa; p.remote_candidate = cand; return g_hash_table_lookup(ag->pair_hash, &p); } @@ -835,18 +816,14 @@ static void __cand_ice_foundation(struct call *call, struct ice_candidate *cand) char buf[64]; int len; - len = sprintf(buf, "%lx%lx%lx%lx%x%x", - (long unsigned) cand->endpoint.ip46.s6_addr32[0], - (long unsigned) cand->endpoint.ip46.s6_addr32[1], - (long unsigned) cand->endpoint.ip46.s6_addr32[2], - (long unsigned) cand->endpoint.ip46.s6_addr32[3], - cand->type, cand->transport); + len = sprintf(buf, "%x%x%x", endpoint_hash(&cand->endpoint), + cand->type, g_direct_hash(cand->transport)); call_str_cpy_len(call, &cand->foundation, buf, len); } /* agent must be locked */ static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, struct packet_stream *ps, - struct sockaddr_in6 *src, struct interface_address *ifa, unsigned long priority) + const endpoint_t *src, const struct local_intf *ifa, unsigned long priority) { struct ice_candidate *cand, *old_cand; struct ice_candidate_pair *pair; @@ -854,10 +831,9 @@ static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, stru cand = g_slice_alloc0(sizeof(*cand)); cand->component_id = ps->component; - cand->transport = ITP_UDP; + cand->transport = ifa->spec->address.type; cand->priority = priority; - cand->endpoint.ip46 = src->sin6_addr; - cand->endpoint.port = ntohs(src->sin6_port); + cand->endpoint = *src; cand->type = ICT_PRFLX; __cand_ice_foundation(call, cand); @@ -972,7 +948,7 @@ static void __get_complete_components(GQueue *out, struct ice_agent *ag, GTree * cand = __foundation_lookup(ag, &pair1->remote_candidate->foundation, i); if (!cand) goto next_foundation; - pairX = __pair_lookup(ag, cand, pair1->local_address); + pairX = __pair_lookup(ag, cand, pair1->local_intf); if (!pairX) goto next_foundation; if (!bf_isset(&pairX->pair_flags, flag)) @@ -999,7 +975,7 @@ static int __check_valid(struct ice_agent *ag) { GList *l, *k; GQueue all_compos; struct ice_candidate_pair *pair; - struct interface_address *ifa; + const struct local_intf *ifa; __get_complete_valid_pairs(&all_compos, ag); @@ -1012,11 +988,12 @@ static int __check_valid(struct ice_agent *ag) { ilog(LOG_DEBUG, "ICE completed, using pair "PAIR_FORMAT, PAIR_FMT(pair)); AGENT_SET(ag, COMPLETED); - ifa = g_atomic_pointer_get(&media->local_address); - if (ifa != pair->local_address - && g_atomic_pointer_compare_and_exchange(&media->local_address, ifa, - pair->local_address)) - ilog(LOG_INFO, "ICE negotiated: local interface %s", smart_ntop_buf(&pair->local_address->addr)); + ifa = g_atomic_pointer_get(&media->local_intf); + if (ifa != pair->local_intf + && g_atomic_pointer_compare_and_exchange(&media->local_intf, ifa, + pair->local_intf)) + ilog(LOG_INFO, "ICE negotiated: local interface %s", + sockaddr_print_buf(&pair->local_intf->spec->address.addr)); for (l = media->streams.head, k = all_compos.head; l && k; l = l->next, k = k->next) { ps = l->data; @@ -1025,7 +1002,7 @@ static int __check_valid(struct ice_agent *ag) { mutex_lock(&ps->out_lock); if (memcmp(&ps->endpoint, &pair->remote_candidate->endpoint, sizeof(ps->endpoint))) { ilog(LOG_INFO, "ICE negotiated: peer for component %u is %s", ps->component, - smart_ntop_ep_buf(&pair->remote_candidate->endpoint)); + endpoint_print_buf(&pair->remote_candidate->endpoint)); ps->endpoint = pair->remote_candidate->endpoint; } mutex_unlock(&ps->out_lock); @@ -1045,18 +1022,18 @@ static int __check_valid(struct ice_agent *ag) { * -1 = generic error, process packet as normal * -2 = role conflict */ -int ice_request(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_addr *dst, +int ice_request(struct packet_stream *ps, const endpoint_t *src, const sockaddr_t *dst, struct stun_attrs *attrs) { struct call_media *media = ps->media; struct ice_agent *ag; - struct interface_address *ifa; + const struct local_intf *ifa; const char *err; struct ice_candidate *cand; struct ice_candidate_pair *pair; int ret; - __DBG("received ICE request from %s on %s", smart_ntop_port_buf(src), smart_ntop_buf(dst)); + __DBG("received ICE request from %s on %s", endpoint_print_buf(src), sockaddr_print_buf(dst)); ag = media->ice_agent; if (!ag) @@ -1064,7 +1041,7 @@ int ice_request(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_a atomic64_set(&ag->last_activity, poller_now); - ifa = get_interface_from_address(ag->local_interface, dst); + ifa = get_interface_from_address(ag->logical_intf, dst, NULL); /* XXX type */ err = "ICE/STUN binding request received on unknown local interface address"; if (!ifa) goto err; @@ -1130,7 +1107,7 @@ int ice_request(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_a err_unlock: mutex_unlock(&ag->lock); err: - ilog(LOG_NOTICE, "%s (from %s on interface %s)", err, smart_ntop_port_buf(src), smart_ntop_buf(dst)); + ilog(LOG_NOTICE, "%s (from %s on interface %s)", err, endpoint_print_buf(src), sockaddr_print_buf(dst)); return 0; } @@ -1154,7 +1131,7 @@ static int __check_succeeded_complete(struct ice_agent *ag) { } /* call is locked in R */ -int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_addr *dst, +int ice_response(struct packet_stream *ps, const endpoint_t *src, const sockaddr_t *dst, struct stun_attrs *attrs, u_int32_t transaction[3]) { struct ice_candidate_pair *pair, *opair; @@ -1163,10 +1140,10 @@ int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_ const char *err; unsigned int component; struct ice_candidate *cand; - struct interface_address *ifa; + const struct local_intf *ifa; int ret, was_ctl; - __DBG("received ICE response from %s on %s", smart_ntop_port_buf(src), smart_ntop_buf(dst)); + __DBG("received ICE response from %s on %s", endpoint_print_buf(src), sockaddr_print_buf(dst)); ag = media->ice_agent; if (!ag) @@ -1184,22 +1161,20 @@ int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_ mutex_unlock(&ag->lock); - ifa = pair->local_address; + ifa = pair->local_intf; ilog(LOG_DEBUG, "Received ICE/STUN response code %u for candidate pair "PAIR_FORMAT" from %s to %s", attrs->error_code, PAIR_FMT(pair), - smart_ntop_ep_buf(&pair->remote_candidate->endpoint), - smart_ntop_buf(&ifa->addr)); + endpoint_print_buf(&pair->remote_candidate->endpoint), + sockaddr_print_buf(&ifa->spec->address.addr)); /* verify endpoints */ err = "ICE/STUN response received, but source address didn't match remote candidate address"; - if (memcmp(&src->sin6_addr, &pair->remote_candidate->endpoint.ip46, sizeof(src->sin6_addr))) - goto err; - if (ntohs(src->sin6_port) != pair->remote_candidate->endpoint.port) + if (!endpoint_eq(src, &pair->remote_candidate->endpoint)) goto err; err = "ICE/STUN response received, but destination address didn't match local interface address"; - if (memcmp(dst, &ifa->addr, sizeof(*dst))) + if (!sockaddr_eq(dst, &ifa->spec->address.addr)) /* XXX lots of references to this struct member */ goto err; if (pair->packet_stream != ps) goto err; @@ -1283,7 +1258,7 @@ err_unlock: err: if (err) ilog(LOG_NOTICE, "%s (from %s on interface %s)", - err, smart_ntop_port_buf(src), smart_ntop_buf(dst)); + err, endpoint_print_buf(src), sockaddr_print_buf(dst)); if (pair && attrs->error_code) __fail_pair(pair); @@ -1364,9 +1339,9 @@ static void create_random_ice_string(struct call *call, str *s, int len) { call_str_cpy_len(call, s, buf, len); } -void ice_foundation(struct interface_address *ifa) { - random_ice_string(ifa->foundation_buf, sizeof(ifa->foundation_buf)); - str_init_len(&ifa->ice_foundation, ifa->foundation_buf, sizeof(ifa->foundation_buf)); +void ice_foundation(str *s) { + str_init_len(s, malloc(ICE_FOUNDATION_LENGTH), ICE_FOUNDATION_LENGTH); + random_ice_string(s->s, ICE_FOUNDATION_LENGTH); } void ice_remote_candidates(GQueue *out, struct ice_agent *ag) { diff --git a/daemon/ice.h b/daemon/ice.h index cd7922ee4..ae499fe0b 100644 --- a/daemon/ice.h +++ b/daemon/ice.h @@ -11,6 +11,8 @@ #include "obj.h" #include "aux.h" #include "call.h" +#include "media_socket.h" +#include "socket.h" @@ -20,6 +22,7 @@ #define STUN_RETRANSMIT_INTERVAL 100 /* ms, with exponential backoff */ #define STUN_MAX_RETRANSMITS 7 #define MAX_ICE_CANDIDATES 100 +#define ICE_FOUNDATION_LENGTH 16 @@ -52,8 +55,8 @@ -struct local_interface; -struct interface_address; +struct logical_intf; +struct local_intf; struct packet_stream; struct call_media; struct call; @@ -72,26 +75,19 @@ enum ice_candidate_type { __ICT_LAST, }; -enum ice_transport { - ITP_UNKNOWN = 0, - ITP_UDP, -// ITP_TCP, -}; - struct ice_candidate { str foundation; unsigned long component_id; - enum ice_transport transport; + socktype_t *transport; unsigned long priority; - struct endpoint endpoint; + endpoint_t endpoint; enum ice_candidate_type type; - struct in6_addr related_address; - unsigned int related_port; + endpoint_t related; }; struct ice_candidate_pair { struct ice_candidate *remote_candidate; - struct interface_address *local_address; + const struct local_intf *local_intf; struct packet_stream *packet_stream; volatile unsigned int pair_flags; u_int32_t stun_transaction[3]; /* belongs to transaction_hash, thus agent->lock */ @@ -109,8 +105,8 @@ struct ice_agent { struct obj obj; struct call *call; /* main reference */ struct call_media *media; - struct local_interface *local_interface; - int desired_family; + const struct logical_intf *logical_intf; + sockfamily_t *desired_family; atomic64 last_activity; mutex_t lock; /* for elements below. and call must be locked in R */ @@ -150,9 +146,8 @@ extern const char * const ice_type_strings[]; void ice_init(void); enum ice_candidate_type ice_candidate_type(const str *s); -enum ice_transport ice_transport(const str *s); int ice_has_related(enum ice_candidate_type); -void ice_foundation(struct interface_address *ifa); +void ice_foundation(str *); void ice_agent_init(struct ice_agent **agp, struct call_media *media); void ice_update(struct ice_agent *, struct stream_params *); @@ -164,8 +159,8 @@ void ice_remote_candidates(GQueue *, struct ice_agent *); void ice_thread_run(void *); -int ice_request(struct packet_stream *, struct sockaddr_in6 *, struct in6_addr *, struct stun_attrs *); -int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_addr *dst, +int ice_request(struct packet_stream *, const endpoint_t *, const sockaddr_t *, struct stun_attrs *); +int ice_response(struct packet_stream *ps, const endpoint_t *src, const sockaddr_t *dst, struct stun_attrs *attrs, u_int32_t transaction[3]); /* returns 0 if ICE still has work to do, 1 otherwise */ diff --git a/daemon/log.c b/daemon/log.c index 964f1ae00..3031a5e94 100644 --- a/daemon/log.c +++ b/daemon/log.c @@ -115,9 +115,9 @@ void __ilog(int prio, const char *fmt, ...) { break; case LOG_INFO_STREAM_FD: if (log_info.u.stream_fd->call) - snprintf(prefix, sizeof(prefix), "["STR_FORMAT" port %5hu] ", + snprintf(prefix, sizeof(prefix), "["STR_FORMAT" port %5u] ", STR_FMT(&log_info.u.stream_fd->call->callid), - log_info.u.stream_fd->fd.localport); + log_info.u.stream_fd->socket.local.port); break; case LOG_INFO_STR: snprintf(prefix, sizeof(prefix), "["STR_FORMAT"] ", diff --git a/daemon/main.c b/daemon/main.c index 93c3d5e75..e953af87e 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -28,6 +28,8 @@ #include "cli.h" #include "graphite.h" #include "ice.h" +#include "socket.h" +#include "media_socket.h" @@ -86,14 +88,12 @@ static mutex_t *openssl_locks; static char *pidfile; static gboolean foreground; static GQueue interfaces = G_QUEUE_INIT; -static u_int32_t listenp; -static u_int16_t listenport; -static struct in6_addr udp_listenp; -static u_int16_t udp_listenport; -static struct in6_addr ng_listenp; -static u_int16_t ng_listenport; -static u_int32_t cli_listenp; -static u_int16_t cli_listenport; +endpoint_t tcp_listen_ep; +endpoint_t udp_listen_ep; +endpoint_t ng_listen_ep; +endpoint_t cli_listen_ep; +endpoint_t graphite_ep; +endpoint_t redis_ep; static int tos; static int table = -1; static int no_fallback; @@ -101,15 +101,11 @@ static int timeout; static int silent_timeout; static int port_min = 30000; static int port_max = 40000; -static u_int32_t redis_ip; -static u_int16_t redis_port; static int redis_db = -1; static char *b2b_url; static enum xmlrpc_format xmlrpc_fmt = XF_SEMS; static int num_threads; static int delete_delay = 30; -static u_int32_t graphite_ip = 0; -static u_int16_t graphite_port; static int graphite_interval = 0; static void sighandler(gpointer x) { @@ -203,12 +199,11 @@ static void print_available_log_facilities () { } -static struct interface_address *if_addr_parse(char *s) { +static struct intf_config *if_addr_parse(char *s) { str name; char *c; - struct in6_addr addr, adv; - struct interface_address *ifa; - int family; + sockaddr_t addr, adv; + struct intf_config *ifa; /* name */ c = strchr(s, '/'); @@ -226,20 +221,21 @@ static struct interface_address *if_addr_parse(char *s) { *c++ = 0; /* address */ - if (pton_46(&addr, s, &family)) + if (sockaddr_parse_any(&addr, s)) return NULL; adv = addr; if (c) { - if (pton_46(&adv, c, NULL)) + if (sockaddr_parse_any(&adv, c)) return NULL; } ifa = g_slice_alloc0(sizeof(*ifa)); - ifa->interface_name = name; - ifa->addr = addr; - ifa->advertised = adv; - ifa->family = family; + ifa->name = name; + ifa->address.addr = addr; + ifa->address.advertised = adv; + ifa->port_min = port_min; + ifa->port_max = port_max; return ifa; } @@ -249,7 +245,7 @@ static struct interface_address *if_addr_parse(char *s) { static void options(int *argc, char ***argv) { char **if_a = NULL; char **iter; - struct interface_address *ifa; + struct intf_config *ifa; char *listenps = NULL; char *listenudps = NULL; char *listenngs = NULL; @@ -322,23 +318,23 @@ static void options(int *argc, char ***argv) { } if (listenps) { - if (parse_ip_port(&listenp, &listenport, listenps)) + if (endpoint_parse_any(&tcp_listen_ep, listenps)) die("Invalid IP or port (--listen-tcp)"); } if (listenudps) { - if (parse_ip6_port(&udp_listenp, &udp_listenport, listenudps)) + if (endpoint_parse_any(&udp_listen_ep, listenudps)) die("Invalid IP or port (--listen-udp)"); } if (listenngs) { - if (parse_ip6_port(&ng_listenp, &ng_listenport, listenngs)) + if (endpoint_parse_any(&ng_listen_ep, listenngs)) die("Invalid IP or port (--listen-ng)"); } - if (listencli) {if (parse_ip_port(&cli_listenp, &cli_listenport, listencli)) + if (listencli) {if (endpoint_parse_any(&cli_listen_ep, listencli)) die("Invalid IP or port (--listen-cli)"); } - if (graphitep) {if (parse_ip_port(&graphite_ip, &graphite_port, graphitep)) + if (graphitep) {if (endpoint_parse_any(&graphite_ep, graphitep)) die("Invalid IP or port (--graphite)"); } @@ -354,7 +350,7 @@ static void options(int *argc, char ***argv) { silent_timeout = 3600; if (redisps) { - if (parse_ip_port(&redis_ip, &redis_port, redisps) || !redis_ip) + if (endpoint_parse_any(&redis_ep, redisps)) die("Invalid IP or port (--redis)"); if (redis_db < 0) die("Must specify Redis DB number (--redis-db) when using Redis"); @@ -453,6 +449,7 @@ static void make_OpenSSL_thread_safe(void) { static void init_everything() { struct timespec ts; + socket_init(); log_init(); clock_gettime(CLOCK_REALTIME, &ts); srandom(ts.tv_sec ^ ts.tv_nsec); @@ -470,6 +467,7 @@ static void init_everything() { sdp_init(); dtls_init(); ice_init(); + interfaces_init(&interfaces); } void redis_mod_verify(void *dlh) { @@ -518,10 +516,11 @@ void redis_mod_verify(void *dlh) { check_struct_offset(call_monologue, active_dialogue); check_struct_offset(call_monologue, medias); - check_struct_offset(stream_fd, fd); - check_struct_offset(stream_fd, call); - check_struct_offset(stream_fd, stream); - check_struct_offset(stream_fd, dtls); + /* XXX adapt checks */ +// check_struct_offset(stream_fd, fd); +// check_struct_offset(stream_fd, call); +// check_struct_offset(stream_fd, stream); +// check_struct_offset(stream_fd, dtls); } void create_everything(struct main_context *ctx) { @@ -566,51 +565,47 @@ no_kernel: ZERO(mc); mc.kernelfd = kfd; mc.kernelid = table; - mc.interfaces = &interfaces; - mc.port_min = port_min; - mc.port_max = port_max; mc.timeout = timeout; mc.silent_timeout = silent_timeout; mc.delete_delay = delete_delay; mc.default_tos = tos; mc.b2b_url = b2b_url; mc.fmt = xmlrpc_fmt; - mc.graphite_port = graphite_port; - mc.graphite_ip = graphite_ip; + mc.graphite_ep = graphite_ep; mc.graphite_interval = graphite_interval; ct = NULL; - if (listenport) { - ct = control_tcp_new(ctx->p, listenp, listenport, ctx->m); + if (tcp_listen_ep.port) { + ct = control_tcp_new(ctx->p, &tcp_listen_ep, ctx->m); if (!ct) die("Failed to open TCP control connection port"); } cu = NULL; - if (udp_listenport) { - callmaster_exclude_port(ctx->m, udp_listenport); - cu = control_udp_new(ctx->p, udp_listenp, udp_listenport, ctx->m); + if (udp_listen_ep.port) { + // callmaster_exclude_port(ctx->m, udp_listenport); /* XXX fix */ + cu = control_udp_new(ctx->p, &udp_listen_ep, ctx->m); if (!cu) die("Failed to open UDP control connection port"); } cn = NULL; - if (ng_listenport) { - callmaster_exclude_port(ctx->m, ng_listenport); - cn = control_ng_new(ctx->p, ng_listenp, ng_listenport, ctx->m); + if (ng_listen_ep.port) { + // callmaster_exclude_port(ctx->m, ng_listenport); /* XXX fix */ + cn = control_ng_new(ctx->p, &ng_listen_ep, ctx->m); if (!cn) die("Failed to open UDP control connection port"); } cl = NULL; - if (cli_listenport) { - callmaster_exclude_port(ctx->m, cli_listenport); - cl = cli_new(ctx->p, cli_listenp, cli_listenport, ctx->m); + if (tcp_listen_ep.port) { + // callmaster_exclude_port(ctx->m, cli_listenport); /* XXX fix */ + cl = cli_new(ctx->p, &cli_listen_ep, ctx->m); if (!cl) die("Failed to open UDP CLI connection port"); } - if (redis_ip) { + if (!is_addr_unspecified(&redis_ep.address)) { dlh = dlopen(RE_PLUGIN_DIR "/rtpengine-redis.so", RTLD_NOW | RTLD_GLOBAL); if (!dlh && !g_file_test(RE_PLUGIN_DIR "/rtpengine-redis.so", G_FILE_TEST_IS_REGULAR) && g_file_test("../../rtpengine-redis/redis.so", G_FILE_TEST_IS_REGULAR)) @@ -621,13 +616,12 @@ no_kernel: if (!strp || !*strp || strcmp(*strp, REDIS_MODULE_VERSION)) die("Incorrect redis module version: %s", *strp); redis_mod_verify(dlh); - mc.redis = redis_new_mod(redis_ip, redis_port, redis_db); + mc.redis = redis_new_mod(&redis_ep, redis_db); if (!mc.redis) die("Cannot start up without Redis database"); } ctx->m->conf = mc; - callmaster_config_init(ctx->m); if (!foreground) daemonize(); @@ -650,7 +644,7 @@ int main(int argc, char **argv) { thread_create_detach(sighandler, NULL); thread_create_detach(poller_timer_loop, ctx.p); - if (graphite_ip) + if (!is_addr_unspecified(&graphite_ep.address)) thread_create_detach(graphite_loop, ctx.m); thread_create_detach(ice_thread_run, NULL); diff --git a/daemon/media_socket.c b/daemon/media_socket.c new file mode 100644 index 000000000..13e521a9c --- /dev/null +++ b/daemon/media_socket.c @@ -0,0 +1,209 @@ +#include "media_socket.h" +#include +#include +#include +#include "str.h" +#include "ice.h" +#include "socket.h" + + + +static GQueue *__interface_list_for_family(sockfamily_t *fam); + + +static GHashTable *__logical_intf_name_family_hash; +static GHashTable *__intf_spec_addr_type_hash; +static GQueue __preferred_lists_for_family[__SF_LAST]; + + + + + +struct logical_intf *get_logical_interface(const str *name, sockfamily_t *fam) { + struct logical_intf d, *lif; + + if (!name || !name->s) { + GQueue *q; + q = __interface_list_for_family(fam); + return q->head ? q->head->data : NULL; + } + + d.name = *name; + d.preferred_family = fam; + + lif = g_hash_table_lookup(__logical_intf_name_family_hash, &d); + return lif; +} + +static unsigned int __name_family_hash(const void *p) { + const struct logical_intf *lif = p; + return str_hash(&lif->name) ^ g_direct_hash(lif->preferred_family); +} +static int __name_family_eq(const void *a, const void *b) { + const struct logical_intf *A = a, *B = b; + return str_equal(&A->name, &B->name) && A->preferred_family == B->preferred_family; +} + +static unsigned int __addr_type_hash(const void *p) { + const struct intf_address *addr = p; + return sockaddr_hash(&addr->addr) ^ g_direct_hash(addr->type); +} +static int __addr_type_eq(const void *a, const void *b) { + const struct intf_address *A = a, *B = b; + return sockaddr_eq(&A->addr, &B->addr) && A->type == B->type; +} + +static GQueue *__interface_list_for_family(sockfamily_t *fam) { + return &__preferred_lists_for_family[fam->idx]; +} +static void __interface_append(struct intf_config *ifa, sockfamily_t *fam) { + struct logical_intf *lif; + GQueue *q; + struct local_intf *ifc; + struct intf_spec *spec; + + lif = get_logical_interface(&ifa->name, fam); + + if (!lif) { + lif = g_slice_alloc0(sizeof(*lif)); + lif->name = ifa->name; + lif->preferred_family = fam; + lif->addr_hash = g_hash_table_new(__addr_type_hash, __addr_type_eq); + g_hash_table_insert(__logical_intf_name_family_hash, lif, lif); + if (ifa->address.addr.family == fam) { + q = __interface_list_for_family(fam); + g_queue_push_tail(q, lif); + } + } + + spec = g_hash_table_lookup(__intf_spec_addr_type_hash, &ifa->address); + if (!spec) { + spec = g_slice_alloc0(sizeof(*spec)); + spec->address = ifa->address; + ice_foundation(&spec->ice_foundation); + spec->port_pool.min = ifa->port_min; + spec->port_pool.max = ifa->port_max; + g_hash_table_insert(__intf_spec_addr_type_hash, &spec->address, spec); + } + + ifc = g_slice_alloc(sizeof(*ifc)); + ifc->spec = spec; + ifc->preference = lif->list.length; + ifc->logical = lif; + + g_queue_push_tail(&lif->list, ifc); + g_hash_table_insert(lif->addr_hash, (void *) &ifc->spec->address, ifc); +} + +void interfaces_init(GQueue *interfaces) { + int i; + GList *l; + struct intf_config *ifa; + sockfamily_t *fam; + + /* init everything */ + __logical_intf_name_family_hash = g_hash_table_new(__name_family_hash, __name_family_eq); + __intf_spec_addr_type_hash = g_hash_table_new(__addr_type_hash, __addr_type_eq); + + for (i = 0; i < G_N_ELEMENTS(__preferred_lists_for_family); i++) + g_queue_init(&__preferred_lists_for_family[i]); + + /* build primary lists first */ + for (l = interfaces->head; l; l = l->next) { + ifa = l->data; + __interface_append(ifa, ifa->address.addr.family); + } + + /* then append to each other as lower-preference alternatives */ + for (i = 0; i < __SF_LAST; i++) { + fam = get_socket_family_enum(i); + for (l = interfaces->head; l; l = l->next) { + ifa = l->data; + if (ifa->address.addr.family == fam) + continue; + __interface_append(ifa, fam); + } + } +} + +struct local_intf *get_interface_address(const struct logical_intf *lif, sockfamily_t *fam) { + const GQueue *q; + + if (!fam) + return NULL; + q = &lif->list; + if (!q->head) + return NULL; + return q->head->data; +} + +/* safety fallback */ +struct local_intf *get_any_interface_address(const struct logical_intf *lif, sockfamily_t *fam) { + struct local_intf *ifa; + + ifa = get_interface_address(lif, fam); + if (ifa) + return ifa; + ifa = get_interface_address(lif, __get_socket_family_enum(SF_IP4)); + if (ifa) + return ifa; + return get_interface_address(lif, __get_socket_family_enum(SF_IP6)); +} + + + +/* XXX family specific */ +void set_tos(int fd, unsigned int tos) { + unsigned char ctos; + + ctos = tos; + + setsockopt(fd, IPPROTO_IP, IP_TOS, &ctos, sizeof(tos)); +#ifdef IPV6_TCLASS + setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); +#else +#warning "Will not set IPv6 traffic class" +#endif +} + + +/* XXX family specific? unify? */ +static int get_port6(socket_t *r, unsigned int port, const struct local_intf *lif, const struct call *c) { + if (open_socket(r, SOCK_DGRAM, port, &lif->spec->address.addr)) + return -1; + + set_tos(r->fd, c->tos); + + return 0; +} + +int get_port(socket_t *r, unsigned int port, const struct local_intf *lif, const struct call *c) { + int ret; + struct port_pool *pp; + + __C_DBG("attempting to open port %u", port); + + pp = &lif->spec->port_pool; + + if (bit_array_set(pp->ports_used, port)) { + __C_DBG("port in use"); + return -1; + } + __C_DBG("port locked"); + + ret = get_port6(r, port, lif, c); + + if (ret) { + __C_DBG("couldn't open port"); + bit_array_clear(pp->ports_used, port); + return ret; + } + + return 0; +} + +void release_port(socket_t *r, const struct local_intf *lif) { + __C_DBG("releasing port %u", r->local.port); + bit_array_clear(lif->spec->port_pool.ports_used, r->local.port); + close_socket(r); +} diff --git a/daemon/media_socket.h b/daemon/media_socket.h new file mode 100644 index 000000000..b781970d7 --- /dev/null +++ b/daemon/media_socket.h @@ -0,0 +1,89 @@ +#ifndef _MEDIA_SOCKET_H_ +#define _MEDIA_SOCKET_H_ + + +#include +#include +#include +#include "str.h" +#include "obj.h" +#include "aux.h" +#include "dtls.h" +#include "crypto.h" +#include "socket.h" + + + + + + +struct logical_intf { + str name; + sockfamily_t *preferred_family; + GQueue list; /* struct local_intf */ + GHashTable *addr_hash; +}; +struct port_pool { + BIT_ARRAY_DECLARE(ports_used, 0x10000); + volatile unsigned int last_used; + + unsigned int min, max; +}; +struct intf_address { + socktype_t *type; + sockaddr_t addr; + sockaddr_t advertised; +}; +struct intf_config { + str name; + struct intf_address address; + unsigned int port_min, port_max; +}; +struct intf_spec { + struct intf_address address; + str ice_foundation; + struct port_pool port_pool; +}; +struct local_intf { + struct intf_spec *spec; + unsigned int preference; /* starting with 0 */ + const struct logical_intf *logical; +}; +struct stream_fd { + struct obj obj; + socket_t socket; /* RO */ + const struct local_intf *local_intf; /* RO */ + struct call *call; /* RO */ + struct packet_stream *stream; /* LOCK: call->master_lock */ + struct crypto_context crypto; /* IN direction, LOCK: stream->in_lock */ + struct dtls_connection dtls; /* LOCK: stream->in_lock */ +}; + + + +void interfaces_init(GQueue *interfaces); + +struct logical_intf *get_logical_interface(const str *name, sockfamily_t *fam); +struct local_intf *get_interface_address(const struct logical_intf *lif, sockfamily_t *fam); +struct local_intf *get_any_interface_address(const struct logical_intf *lif, sockfamily_t *fam); + +int get_port(socket_t *r, unsigned int port, const struct local_intf *lif, const struct call *c); +void release_port(socket_t *r, const struct local_intf *); +void set_tos(int fd, unsigned int tos); + +INLINE int open_intf_socket(socket_t *r, unsigned int port, const struct local_intf *lif) { + return open_socket(r, SOCK_DGRAM, port, &lif->spec->address.addr); +} + +/* XXX shouldnt be necessary */ +INLINE struct local_intf *get_interface_from_address(const struct logical_intf *lif, + const sockaddr_t *addr, socktype_t *type) +{ + struct intf_address a; + a.type = type; + a.addr = *addr; + return g_hash_table_lookup(lif->addr_hash, &a); +} + + +#endif diff --git a/daemon/redis.c b/daemon/redis.c index 83349bfcb..8f76e2e57 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -1,6 +1,6 @@ #include "redis.h" -struct redis *(*redis_new_mod)(u_int32_t, u_int16_t, int); +struct redis *(*redis_new_mod)(const endpoint_t *, int); int (*redis_restore_mod)(struct callmaster *, struct redis *); void (*redis_update_mod)(struct call *, struct redis *); void (*redis_delete_mod)(struct call *, struct redis *); diff --git a/daemon/redis.h b/daemon/redis.h index 905d8662d..027fd9295 100644 --- a/daemon/redis.h +++ b/daemon/redis.h @@ -6,6 +6,7 @@ #include #include "compat.h" +#include "socket.h" @@ -16,7 +17,7 @@ struct redis; -extern struct redis *(*redis_new_mod)(u_int32_t, u_int16_t, int); +extern struct redis *(*redis_new_mod)(const endpoint_t *, int); extern int (*redis_restore_mod)(struct callmaster *, struct redis *); extern void (*redis_update_mod)(struct call *, struct redis *); extern void (*redis_delete_mod)(struct call *, struct redis *); diff --git a/daemon/sdp.c b/daemon/sdp.c index 46715e17a..0b3a22e9c 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -15,12 +15,13 @@ #include "dtls.h" #include "rtp.h" #include "ice.h" +#include "socket.h" struct network_address { str network_type; str address_type; str address; - struct in6_addr parsed; + sockaddr_t parsed; }; struct sdp_origin { @@ -223,36 +224,8 @@ static struct sdp_attribute *attr_get_by_id_m_s(struct sdp_media *m, int id) { } -/* hack hack */ -INLINE int inet_pton_str(int af, str *src, void *dst) { - char *s = src->s; - char p; - int ret; - p = s[src->len]; - s[src->len] = '\0'; - ret = smart_pton(af, src->s, dst); - s[src->len] = p; - return ret; -} - -int address_family(const str *s) { - if (s->len != 3) - return 0; - - if (!memcmp(s->s, "IP4", 3) - || !memcmp(s->s, "ip4", 3)) - return AF_INET; - - if (!memcmp(s->s, "IP6", 3) - || !memcmp(s->s, "ip6", 3)) - return AF_INET6; - - return 0; -} - -static int __parse_address(struct in6_addr *out, str *network_type, str *address_type, str *address) { - struct in_addr in4; - int af; +static int __parse_address(sockaddr_t *out, str *network_type, str *address_type, str *address) { + sockfamily_t *af; if (network_type) { if (network_type->len != 2) @@ -263,26 +236,13 @@ static int __parse_address(struct in6_addr *out, str *network_type, str *address } if (!address_type) { - if (inet_pton_str(AF_INET, address, &in4) == 1) - goto ip4; - if (inet_pton_str(AF_INET6, address, out) == 1) - return 0; - return -1; - } - - af = address_family(address_type); - - if (af == AF_INET) { - if (inet_pton_str(AF_INET, address, &in4) != 1) - return -1; -ip4: - in4_to_6(out, in4.s_addr); - } - else if (af == AF_INET6) { - if (inet_pton_str(AF_INET6, address, out) != 1) + if (sockaddr_parse_any_str(out, address)) return -1; + return 0; } - else + + af = get_socket_family_rfc(address_type); + if (sockaddr_parse_str(out, af, address)) return -1; return 0; @@ -322,7 +282,10 @@ INLINE int extract_token(char **sp, char *end, str *out) { if (parse_address(&output->field)) return -1 #define EXTRACT_NETWORK_ADDRESS_NF(field) \ EXTRACT_NETWORK_ADDRESS_NP(field); \ - if (parse_address(&output->field)) output->field.parsed.s6_addr32[0] = 0xfe + if (parse_address(&output->field)) do { \ + output->field.parsed.family = get_socket_family_enum(SF_IP4); \ + output->field.parsed.u.ipv4.s_addr = 1; \ + } while (0) #define PARSE_DECL char *end, *start #define PARSE_INIT start = output->value.s; end = start + output->value.len @@ -607,7 +570,7 @@ static int parse_attribute_candidate(struct sdp_attribute *output) { if (ep == c->component_str.s) return -1; - c->cand_parsed.transport = ice_transport(&c->transport_str); + c->cand_parsed.transport = get_socket_type(&c->transport_str); if (!c->cand_parsed.transport) return 0; @@ -615,7 +578,7 @@ static int parse_attribute_candidate(struct sdp_attribute *output) { if (ep == c->priority_str.s) return -1; - if (__parse_address(&c->cand_parsed.endpoint.ip46, NULL, NULL, &c->address_str)) + if (__parse_address(&c->cand_parsed.endpoint.address, NULL, NULL, &c->address_str)) return 0; c->cand_parsed.endpoint.port = strtoul(c->port_str.s, &ep, 10); @@ -642,10 +605,10 @@ static int parse_attribute_candidate(struct sdp_attribute *output) { if (str_cmp(&c->rport_str, "rport")) return -1; - if (__parse_address(&c->cand_parsed.related_address, NULL, NULL, &c->related_address_str)) + if (__parse_address(&c->cand_parsed.related.address, NULL, NULL, &c->related_address_str)) return 0; - c->cand_parsed.related_port = strtoul(c->related_port_str.s, &ep, 10); + c->cand_parsed.related.port = strtoul(c->related_port_str.s, &ep, 10); if (ep == c->related_port_str.s) return -1; @@ -1072,14 +1035,14 @@ static int fill_endpoint(struct endpoint *ep, const struct sdp_media *media, str &flags->received_from_address)) return -1; } - ep->ip46 = flags->parsed_received_from; + ep->address = flags->parsed_received_from; } else if (address && !is_addr_unspecified(&address->parsed)) - ep->ip46 = address->parsed; + ep->address = address->parsed; else if (media->connection.parsed) - ep->ip46 = media->connection.address.parsed; + ep->address = media->connection.address.parsed; else if (session->connection.parsed) - ep->ip46 = session->connection.address.parsed; + ep->address = session->connection.address.parsed; else return -1; @@ -1437,7 +1400,7 @@ static int replace_media_port(struct sdp_chopper *chop, struct sdp_media *media, if (copy_up_to(chop, port)) return -1; - p = ps->sfd ? ps->sfd->fd.localport : 0; + p = ps->sfd ? ps->sfd->socket.local.port : 0; chopper_append_printf(chop, "%u", p); if (skip_over(chop, port)) @@ -1460,7 +1423,7 @@ static int replace_consecutive_port_count(struct sdp_chopper *chop, struct sdp_m if (!j) goto warn; ps_n = j->data; - if (ps_n->sfd->fd.localport != ps->sfd->fd.localport + cons * 2) { + if (ps_n->sfd->socket.local.port != ps->sfd->socket.local.port + cons * 2) { warn: ilog(LOG_WARN, "Failed to handle consecutive ports"); break; @@ -1472,18 +1435,18 @@ warn: return 0; } -static int insert_ice_address(struct sdp_chopper *chop, struct packet_stream *ps, struct interface_address *ifa) { +static int insert_ice_address(struct sdp_chopper *chop, struct packet_stream *ps, struct local_intf *ifa) { char buf[64]; int len; call_stream_address46(buf, ps, SAF_ICE, &len, ifa); chopper_append_dup(chop, buf, len); - chopper_append_printf(chop, " %hu", ps->sfd->fd.localport); + chopper_append_printf(chop, " %u", ps->sfd->socket.local.port); return 0; } -static int insert_raddr_rport(struct sdp_chopper *chop, struct packet_stream *ps, struct interface_address *ifa) { +static int insert_raddr_rport(struct sdp_chopper *chop, struct packet_stream *ps, struct local_intf *ifa) { char buf[64]; int len; @@ -1491,7 +1454,7 @@ static int insert_raddr_rport(struct sdp_chopper *chop, struct packet_stream *ps call_stream_address46(buf, ps, SAF_ICE, &len, ifa); chopper_append_dup(chop, buf, len); chopper_append_c(chop, " rport "); - chopper_append_printf(chop, "%hu", ps->sfd->fd.localport); + chopper_append_printf(chop, "%u", ps->sfd->socket.local.port); return 0; } @@ -1514,15 +1477,8 @@ static int replace_network_address(struct sdp_chopper *chop, struct network_addr if (flags->media_address.s && is_addr_unspecified(&flags->parsed_media_address)) __parse_address(&flags->parsed_media_address, NULL, NULL, &flags->media_address); - if (!is_addr_unspecified(&flags->parsed_media_address)) { - if (IN6_IS_ADDR_V4MAPPED(&flags->parsed_media_address)) - len = sprintf(buf, "IP4 " IPF, IPP(flags->parsed_media_address.s6_addr32[3])); - else { - memcpy(buf, "IP6 ", 4); - inet_ntop(AF_INET6, &flags->parsed_media_address, buf + 4, sizeof(buf)-4); - len = strlen(buf); - } - } + if (!is_addr_unspecified(&flags->parsed_media_address)) + len = sprintf(buf, "%s", sockaddr_print_buf(&flags->parsed_media_address)); else call_stream_address(buf, ps, SAF_NG, &len); chopper_append_dup(chop, buf, len); @@ -1726,13 +1682,13 @@ out: static void insert_candidate(struct sdp_chopper *chop, struct packet_stream *ps, unsigned int component, unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type, - struct interface_address *ifa) + struct local_intf *ifa) { unsigned long priority; priority = ice_priority_pref(type_pref, local_pref, component); chopper_append_c(chop, "a=candidate:"); - chopper_append_str(chop, &ifa->ice_foundation); + chopper_append_str(chop, &ifa->spec->ice_foundation); chopper_append_printf(chop, " %u UDP %lu ", component, priority); insert_ice_address(chop, ps, ifa); chopper_append_c(chop, " typ "); @@ -1747,10 +1703,10 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt struct sdp_ng_flags *flags, struct sdp_media *sdp_media) { GList *l; - struct interface_address *ifa; + struct local_intf *ifa; unsigned int pref; struct call_media *media; - struct local_interface *lif; + const struct logical_intf *lif; struct ice_agent *ag; unsigned int type_pref, local_pref; enum ice_candidate_type cand_type; @@ -1769,10 +1725,10 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt } ag = media->ice_agent; - lif = ag ? ag->local_interface : media->interface; + lif = ag ? ag->logical_intf : media->logical_intf; if (ag && AGENT_ISSET(ag, COMPLETED)) { - ifa = g_atomic_pointer_get(&media->local_address); + ifa = g_atomic_pointer_get(&media->local_intf); insert_candidate(chop, rtp, 1, type_pref, ifa->preference, cand_type, ifa); if (rtcp) /* rtcp-mux only possible in answer */ insert_candidate(chop, rtcp, 2, type_pref, ifa->preference, cand_type, ifa); @@ -1787,7 +1743,7 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt chopper_append_c(chop, " "); cand = l->data; chopper_append_printf(chop, "%lu %s %u", cand->component_id, - smart_ntop_buf(&cand->endpoint.ip46), cand->endpoint.port); + sockaddr_print_buf(&cand->endpoint.address), cand->endpoint.port); } chopper_append_c(chop, "\r\n"); g_queue_clear(&rc); @@ -1998,13 +1954,13 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu if (MEDIA_ISSET(call_media, RTCP_MUX) && flags->opmode == OP_ANSWER) { chopper_append_c(chop, "a=rtcp:"); - chopper_append_printf(chop, "%hu", ps->sfd->fd.localport); + chopper_append_printf(chop, "%u", ps->sfd->socket.local.port); chopper_append_c(chop, "\r\na=rtcp-mux\r\n"); ps_rtcp = NULL; } else if (ps_rtcp && !flags->ice_force_relay) { chopper_append_c(chop, "a=rtcp:"); - chopper_append_printf(chop, "%hu", ps_rtcp->sfd->fd.localport); + chopper_append_printf(chop, "%u", ps_rtcp->sfd->socket.local.port); if (!MEDIA_ISSET(call_media, RTCP_MUX)) chopper_append_c(chop, "\r\n"); else diff --git a/daemon/sdp.h b/daemon/sdp.h index 4a9005a99..e7b8666fe 100644 --- a/daemon/sdp.h +++ b/daemon/sdp.h @@ -4,6 +4,7 @@ #include #include "str.h" #include "call.h" +#include "media_socket.h" struct sdp_ng_flags { @@ -14,10 +15,10 @@ struct sdp_ng_flags { str transport_protocol_str; str address_family_str; const struct transport_protocol *transport_protocol; - struct in6_addr parsed_received_from; - struct in6_addr parsed_media_address; + sockaddr_t parsed_received_from; + sockaddr_t parsed_media_address; str direction[2]; - int address_family; + sockfamily_t *address_family; int tos; int asymmetric:1, trust_address:1, @@ -62,10 +63,8 @@ int sdp_replace(struct sdp_chopper *, GQueue *, struct call_monologue *, struct struct sdp_chopper *sdp_chopper_new(str *input); void sdp_chopper_destroy(struct sdp_chopper *chop); -int address_family(const str *s); - INLINE int is_trickle_ice_address(const struct endpoint *ep) { - if (is_addr_unspecified(&ep->ip46) && ep->port == 9) + if (is_addr_unspecified(&ep->address) && ep->port == 9) return 1; return 0; } diff --git a/daemon/socket.c b/daemon/socket.c new file mode 100644 index 000000000..c3e000e02 --- /dev/null +++ b/daemon/socket.c @@ -0,0 +1,462 @@ +#include "socket.h" +#include +#include +#include +#include "str.h" +#include "media_socket.h" + +static int __ip4_addr_parse(sockaddr_t *dst, const char *src); +static int __ip6_addr_parse(sockaddr_t *dst, const char *src); +static int __ip4_addr_print(const sockaddr_t *a, char *buf, size_t len); +static int __ip6_addr_print(const sockaddr_t *a, char *buf, size_t len); +static int __ip6_addr_print_p(const sockaddr_t *a, char *buf, size_t len); +static unsigned int __ip4_hash(const sockaddr_t *a); +static unsigned int __ip6_hash(const sockaddr_t *a); +static int __ip4_eq(const sockaddr_t *a, const sockaddr_t *b); +static int __ip6_eq(const sockaddr_t *a, const sockaddr_t *b); +static int __ip4_is_specified(const sockaddr_t *a); +static int __ip6_is_specified(const sockaddr_t *a); +static int __ip_bind(socket_t *s, unsigned int, const sockaddr_t *); +static int __ip_connect(socket_t *s, const endpoint_t *); +static int __ip4_sockaddr2endpoint(endpoint_t *, const void *); +static int __ip6_sockaddr2endpoint(endpoint_t *, const void *); +static int __ip4_endpoint2sockaddr(void *, const endpoint_t *); +static int __ip6_endpoint2sockaddr(void *, const endpoint_t *); +static int __ip4_addrport2sockaddr(void *, const sockaddr_t *, unsigned int); +static int __ip6_addrport2sockaddr(void *, const sockaddr_t *, unsigned int); +static ssize_t __ip_recvfrom(socket_t *s, void *buf, size_t len, endpoint_t *ep); +static ssize_t __ip_sendmsg(socket_t *s, struct msghdr *mh, const endpoint_t *ep); +static ssize_t __ip_sendto(socket_t *s, const void *buf, size_t len, const endpoint_t *ep); + + + +static socktype_t __socket_types[] = { + { + .name = "udp", + .name_uc = "UDP", + }, +}; + +static struct socket_family __socket_families[__SF_LAST] = { + [SF_IP4] = { + .af = AF_INET, + .sockaddr_size = sizeof(struct sockaddr_in), + .name = "IPv4", + .rfc_name = "IP4", + .hash = __ip4_hash, + .eq = __ip4_eq, + .addr_parse = __ip4_addr_parse, + .addr_print = __ip4_addr_print, + .addr_print_p = __ip4_addr_print, + .is_specified = __ip4_is_specified, + .sockaddr2endpoint = __ip4_sockaddr2endpoint, + .endpoint2sockaddr = __ip4_endpoint2sockaddr, + .addrport2sockaddr = __ip4_addrport2sockaddr, + .bind = __ip_bind, + .connect = __ip_connect, + .recvfrom = __ip_recvfrom, + .sendmsg = __ip_sendmsg, + .sendto = __ip_sendto, + }, + [SF_IP6] = { + .af = AF_INET6, + .sockaddr_size = sizeof(struct sockaddr_in6), + .name = "IPv6", + .rfc_name = "IP6", + .hash = __ip6_hash, + .eq = __ip6_eq, + .addr_parse = __ip6_addr_parse, + .addr_print = __ip6_addr_print, + .addr_print_p = __ip6_addr_print_p, + .is_specified = __ip6_is_specified, + .sockaddr2endpoint = __ip6_sockaddr2endpoint, + .endpoint2sockaddr = __ip6_endpoint2sockaddr, + .addrport2sockaddr = __ip6_addrport2sockaddr, + .bind = __ip_bind, + .connect = __ip_connect, + .recvfrom = __ip_recvfrom, + .sendmsg = __ip_sendmsg, + .sendto = __ip_sendto, + }, +}; + + +static int __ip4_addr_parse(sockaddr_t *dst, const char *src) { + if (inet_pton(AF_INET, src, &dst->u.ipv4) == 1) + return 0; + return -1; +} +static int __ip6_addr_parse(sockaddr_t *dst, const char *src) { + if (src[0] != '[') { + if (inet_pton(AF_INET6, src, &dst->u.ipv6) == 1) + return 0; + return -1; + } + + const char *ep; + ep = strchr(src, ']'); + if (!ep) + return -1; + + unsigned int len = ep - src - 1; + char buf[64]; + memcpy(buf, src+1, len); + buf[len] = '\0'; + + if (inet_pton(AF_INET6, buf, &dst->u.ipv6) == 1) + return 0; + return -1; +} +static int __ip4_addr_print(const sockaddr_t *a, char *buf, size_t len) { + buf[0] = '\0'; + if (!inet_ntop(AF_INET, &a->u.ipv4, buf, len)) + return -1; + return 0; +} +static int __ip6_addr_print(const sockaddr_t *a, char *buf, size_t len) { + buf[0] = '\0'; + if (!inet_ntop(AF_INET6, &a->u.ipv6, buf, len)) + return -1; + return 0; +} +static int __ip6_addr_print_p(const sockaddr_t *a, char *buf, size_t len) { + buf[0] = '\0'; + if (!inet_ntop(AF_INET6, &a->u.ipv6, buf+1, len-2)) + return -1; + buf[0] = '['; + strcpy(buf + strlen(buf), "]"); + return 0; +} +static unsigned int __ip4_hash(const sockaddr_t *a) { + return a->u.ipv4.s_addr; +} +static unsigned int __ip6_hash(const sockaddr_t *a) { + return in6_addr_hash(&a->u.ipv6); +} +static int __ip4_eq(const sockaddr_t *a, const sockaddr_t *b) { + return !memcmp(&a->u.ipv4, &b->u.ipv4, sizeof(a->u.ipv4)); +} +static int __ip6_eq(const sockaddr_t *a, const sockaddr_t *b) { + return !memcmp(&a->u.ipv6, &b->u.ipv6, sizeof(a->u.ipv6)); +} +static int __ip4_is_specified(const sockaddr_t *a) { + return a->u.ipv4.s_addr != 0; +} +static int __ip6_is_specified(const sockaddr_t *a) { + return a->u.ipv6.s6_addr32[0] != 0 + && a->u.ipv6.s6_addr32[1] != 0 + && a->u.ipv6.s6_addr32[2] != 0 + && a->u.ipv6.s6_addr32[3] != 0; +} +static int __ip4_sockaddr2endpoint(endpoint_t *ep, const void *p) { + const struct sockaddr_in *sin = p; + if (sin->sin_family != AF_INET) + return -1; + ep->address.family = &__socket_families[SF_IP4]; + ep->address.u.ipv4 = sin->sin_addr; + ep->port = ntohs(sin->sin_port); + return 0; +} +static int __ip6_sockaddr2endpoint(endpoint_t *ep, const void *p) { + const struct sockaddr_in6 *sin = p; + if (sin->sin6_family != AF_INET6) + return -1; + ep->address.family = &__socket_families[SF_IP6]; + ep->address.u.ipv6 = sin->sin6_addr; + ep->port = ntohs(sin->sin6_port); + return 0; +} +static int __ip4_endpoint2sockaddr(void *p, const endpoint_t *ep) { + return __ip4_addrport2sockaddr(p, &ep->address, ep->port); +} +static int __ip6_endpoint2sockaddr(void *p, const endpoint_t *ep) { + return __ip6_addrport2sockaddr(p, &ep->address, ep->port); +} +static int __ip4_addrport2sockaddr(void *p, const sockaddr_t *sa, unsigned int port) { + struct sockaddr_in *sin = p; + ZERO(*sin); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + if (sa) + sin->sin_addr = sa->u.ipv4; + return 0; +} +static int __ip6_addrport2sockaddr(void *p, const sockaddr_t *sa, unsigned int port) { + struct sockaddr_in6 *sin = p; + ZERO(*sin); + sin->sin6_family = AF_INET6; + sin->sin6_port = htons(port); + if (sa) + sin->sin6_addr = sa->u.ipv6; + return 0; +} +static int __ip_bind(socket_t *s, unsigned int port, const sockaddr_t *a) { + struct sockaddr_storage sin; + + s->family->addrport2sockaddr(&sin, a, port); + if (bind(s->fd, (struct sockaddr *) &sin, s->family->sockaddr_size)) + return -1; + return 0; +} +static int __ip_connect(socket_t *s, const endpoint_t *ep) { + struct sockaddr_storage sin; + + s->family->endpoint2sockaddr(&sin, ep); + if (connect(s->fd, (struct sockaddr *) &sin, s->family->sockaddr_size)) + return -1; + return 0; +} +static ssize_t __ip_recvfrom(socket_t *s, void *buf, size_t len, endpoint_t *ep) { + ssize_t ret; + struct sockaddr_storage sin; + socklen_t sinlen; + + sinlen = s->family->sockaddr_size; + ret = recvfrom(s->fd, buf, len, 0, (void *) &sin, &sinlen); + if (ret < 0) + return ret; + s->family->sockaddr2endpoint(ep, &sin); + return ret; +} +static ssize_t __ip_sendmsg(socket_t *s, struct msghdr *mh, const endpoint_t *ep) { + struct sockaddr_storage sin; + + s->family->endpoint2sockaddr(&sin, ep); + mh->msg_name = &sin; + mh->msg_namelen = s->family->sockaddr_size; + + return sendmsg(s->fd, mh, 0); +} +static ssize_t __ip_sendto(socket_t *s, const void *buf, size_t len, const endpoint_t *ep) { + struct sockaddr_storage sin; + + s->family->endpoint2sockaddr(&sin, ep); + return sendto(s->fd, buf, len, 0, (void *) &sin, s->family->sockaddr_size); +} + + + + +unsigned int sockaddr_hash(const sockaddr_t *a) { + return a->family->hash(a) ^ g_direct_hash(a->family); +} +int sockaddr_eq(const sockaddr_t *a, const sockaddr_t *b) { + return a->family == b->family && a->family->eq(a, b); +} +unsigned int g_sockaddr_hash(const void *a) { + return sockaddr_hash(a); +} +int g_sockaddr_eq(const void *a, const void *b) { + return sockaddr_eq(a, b); +} + + +unsigned int endpoint_hash(const endpoint_t *a) { + return sockaddr_hash(&a->address) ^ a->port; +} +int endpoint_eq(const endpoint_t *a, const endpoint_t *b) { + return sockaddr_eq(&a->address, &b->address) && a->port == b->port; +} +unsigned int g_endpoint_hash(const void *a) { + return endpoint_hash(a); +} +int g_endpoint_eq(const void *a, const void *b) { + return endpoint_eq(a, b); +} + + + +int sockaddr_parse_any(sockaddr_t *dst, const char *src) { + int i; + sockfamily_t *fam; + + for (i = 0; i < __SF_LAST; i++) { + fam = &__socket_families[i]; + if (!fam->addr_parse(dst, src)) { + dst->family = fam; + return 0; + } + } + return -1; +} +int sockaddr_parse_any_str(sockaddr_t *dst, const str *src) { + char buf[64]; + if (src->len >= sizeof(buf)) + return -1; + sprintf(buf, STR_FORMAT, STR_FMT(src)); + return sockaddr_parse_any(dst, buf); +} +int sockaddr_parse_str(sockaddr_t *dst, sockfamily_t *fam, const str *src) { + char buf[64]; + if (src->len >= sizeof(buf)) + return -1; + if (!fam) + return -1; + sprintf(buf, STR_FORMAT, STR_FMT(src)); + dst->family = fam; + return fam->addr_parse(dst, buf); +} +sockfamily_t *get_socket_family_rfc(const str *s) { + int i; + sockfamily_t *fam; + + for (i = 0; i < __SF_LAST; i++) { + fam = &__socket_families[i]; + if (!str_cmp(s, fam->rfc_name)) + return fam; + } + return NULL; +} +sockfamily_t *__get_socket_family_enum(enum socket_families i) { + return &__socket_families[i]; +} +int endpoint_parse_any(endpoint_t *d, const char *s) { + int i; + sockfamily_t *fam; + unsigned int len; + const char *ep; + char buf[64]; + + ep = strrchr(s, ':'); + if (!ep) { + if (strchr(s, '.')) + return -1; + /* just a port number */ + d->port = atoi(s); + ZERO(d->address); + d->address.family = __get_socket_family_enum(SF_IP4); + return 0; + } + len = ep - s; + if (len >= sizeof(buf)) + return -1; + d->port = atoi(ep+1); + if (d->port > 0xffff) + return -1; + sprintf(buf, "%.*s", len-1, s); + + for (i = 0; i < __SF_LAST; i++) { + fam = &__socket_families[i]; + if (!fam->addr_parse(&d->address, buf)) { + d->address.family = fam; + return 0; + } + } + return -1; +} + +static int __socket(socket_t *r, int type, sockfamily_t *fam) { + ZERO(*r); + r->family = fam; + r->fd = socket(fam->af, type, 0); + if (r->fd == -1) + return -1; + + return 0; +} + +int open_socket(socket_t *r, int type, unsigned int port, const sockaddr_t *sa) { + sockfamily_t *fam; + + fam = sa->family; + + if (__socket(r, type, fam)) + return -1; + + nonblock(r->fd); + reuseaddr(r->fd); + + if (port > 0xffff) + goto fail; + + if (fam->bind(r, port, sa)) + goto fail; + + r->local.port = port; + r->local.address = *sa; + + return 0; + +fail: + close_socket(r); + return -1; +} + +int connect_socket(socket_t *r, int type, const endpoint_t *ep) { + sockfamily_t *fam; + + fam = ep->address.family; + + if (__socket(r, type, fam)) + return -1; + if (fam->connect(r, ep)) + goto fail; + + r->remote = *ep; + + return 0; + +fail: + close_socket(r); + return -1; +} + +int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep) { + sockfamily_t *fam; + int ret = 0; + + fam = ep->address.family; + + if (__socket(r, type, fam)) + return -1; + nonblock(r->fd); + if (fam->connect(r, ep)) { + if (errno != EINPROGRESS) + goto fail; + ret = 1; + } + + r->remote = *ep; + + return ret; + +fail: + close_socket(r); + return -1; +} + +void close_socket(socket_t *r) { + if (!r || r->fd == -1) + return; + close(r->fd); + r->fd = -1; + ZERO(r->local); + ZERO(r->remote); +} + + + + +socktype_t *get_socket_type(const str *s) { + int i; + socktype_t *tp; + + for (i = 0; i < G_N_ELEMENTS(__socket_types); i++) { + tp = &__socket_types[i]; + if (!str_cmp(s, tp->name)) + return tp; + if (!str_cmp(s, tp->name_uc)) + return tp; + } + return NULL; +} + + + + +void socket_init(void) { + int i; + + for (i = 0; i < __SF_LAST; i++) + __socket_families[i].idx = i; +} diff --git a/daemon/socket.h b/daemon/socket.h new file mode 100644 index 000000000..50dda3d00 --- /dev/null +++ b/daemon/socket.h @@ -0,0 +1,202 @@ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ + + +#include +#include + + + + +enum socket_families { + SF_IP4 = 0, + SF_IP6, + __SF_LAST +}; + + + +struct socket_address; +struct socket_type; +struct socket_family; +struct endpoint; +struct socket; + +typedef struct socket_address sockaddr_t; +typedef struct endpoint endpoint_t; +typedef struct socket socket_t; +typedef const struct socket_type socktype_t; +typedef const struct socket_family sockfamily_t; + + +#include "str.h" + + + +struct local_intf; + + +struct socket_type { + const char *name; /* lower case */ + const char *name_uc; /* upper case */ +}; +struct socket_family { + int idx; + int af; + size_t sockaddr_size; + const char *name; /* "IPv4" */ + const char *rfc_name; /* "IP4" */ + unsigned int (*hash)(const sockaddr_t *); + int (*eq)(const sockaddr_t *, const sockaddr_t *); + int (*addr_parse)(sockaddr_t *, const char *); + int (*addr_print)(const sockaddr_t *, char *, size_t); + int (*addr_print_p)(const sockaddr_t *, char *, size_t); + int (*is_specified)(const sockaddr_t *); + int (*sockaddr2endpoint)(endpoint_t *, const void *); + int (*endpoint2sockaddr)(void *, const endpoint_t *); + int (*addrport2sockaddr)(void *, const sockaddr_t *, unsigned int); + int (*bind)(socket_t *, unsigned int, const sockaddr_t *); + int (*connect)(socket_t *, const endpoint_t *); + ssize_t (*recvfrom)(socket_t *, void *, size_t, endpoint_t *); + ssize_t (*sendmsg)(socket_t *, struct msghdr *, const endpoint_t *); + ssize_t (*sendto)(socket_t *, const void *, size_t, const endpoint_t *); +}; +struct socket_address { + sockfamily_t *family; + union { + struct in_addr ipv4; + struct in6_addr ipv6; + } u; +}; +struct endpoint { + sockaddr_t address; + unsigned int port; +}; +struct socket { + int fd; + sockfamily_t *family; + endpoint_t local; + endpoint_t remote; +}; + + + +#include "aux.h" + + +INLINE int sockaddr_print(const sockaddr_t *a, char *buf, size_t len) { + if (!a->family) { + buf[0] = '\0'; + return 0; + } + return a->family->addr_print(a, buf, len); +} +INLINE char *sockaddr_print_buf(const sockaddr_t *a) { + char *buf = get_thread_buf(); + if (!a->family) { + buf[0] = '\0'; + return 0; + } + sockaddr_print(a, buf, THREAD_BUF_SIZE); + return buf; +} +INLINE int sockaddr_print_p(const sockaddr_t *a, char *buf, size_t len) { + if (!a->family) { + buf[0] = '\0'; + return 0; + } + return a->family->addr_print_p(a, buf, len); +} +INLINE char *sockaddr_print_p_buf(const sockaddr_t *a) { + char *buf = get_thread_buf(); + sockaddr_print_p(a, buf, THREAD_BUF_SIZE); + return buf; +} +INLINE int sockaddr_print_port(const sockaddr_t *a, unsigned int port, char *buf, size_t len) { + if (!a->family) { + buf[0] = '\0'; + return 0; + } + if (a->family->addr_print_p(a, buf, len-6)) + return -1; + sprintf(buf + strlen(buf), ":%u", port); + return 0; +} +INLINE char *sockaddr_print_port_buf(const sockaddr_t *a, unsigned int port) { + char *buf = get_thread_buf(); + sockaddr_print_port(a, port, buf, THREAD_BUF_SIZE); + return buf; +} +INLINE int endpoint_print(const endpoint_t *ep, char *buf, size_t len) { + return sockaddr_print_port(&ep->address, ep->port, buf, len); +} +INLINE char *endpoint_print_buf(const endpoint_t *ep) { + return sockaddr_print_port_buf(&ep->address, ep->port); +} +INLINE int is_addr_unspecified(const sockaddr_t *a) { + if (!a || !a->family) + return 1; + return !a->family->is_specified(a); +} +#define socket_recvfrom(s,a...) (s)->family->recvfrom((s), a) +#define socket_sendmsg(s,a...) (s)->family->sendmsg((s), a) +#define socket_sendto(s,a...) (s)->family->sendto((s), a) + + + +/* XXX obsolete these? */ +INLINE void nonblock(int fd) { + fcntl(fd, F_SETFL, O_NONBLOCK); +} +INLINE void reuseaddr(int fd) { + int one = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); +} +INLINE void ipv6only(int fd, int yn) { + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yn, sizeof(yn)); +} + + + +void socket_init(void); + +int open_socket(socket_t *r, int type, unsigned int port, const sockaddr_t *); +int connect_socket(socket_t *r, int type, const endpoint_t *ep); +int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep); +void close_socket(socket_t *r); + +sockfamily_t *get_socket_family_rfc(const str *s); +sockfamily_t *__get_socket_family_enum(enum socket_families); +int sockaddr_parse_any(sockaddr_t *dst, const char *src); +int sockaddr_parse_any_str(sockaddr_t *dst, const str *src); +int sockaddr_parse_str(sockaddr_t *dst, sockfamily_t *fam, const str *src); +int endpoint_parse_any(endpoint_t *, const char *); + +unsigned int sockaddr_hash(const sockaddr_t *); +int sockaddr_eq(const sockaddr_t *, const sockaddr_t *); /* true/false */ +unsigned int g_sockaddr_hash(const void *); +int g_sockaddr_eq(const void *, const void *); /* true/false */ + +unsigned int endpoint_hash(const endpoint_t *); +int endpoint_eq(const endpoint_t *, const endpoint_t *); /* true/false */ +unsigned int g_endpoint_hash(const void *); +int g_endpoint_eq(const void *, const void *); /* true/false */ + +INLINE sockfamily_t *get_socket_family_enum(enum socket_families i) { + if (i >= __SF_LAST) + return NULL; + return __get_socket_family_enum(i); +} +INLINE int endpoint_parse_port_any(endpoint_t *e, const char *p, unsigned int port) { + if (port > 0xffff) + return -1; + e->port = port; + return sockaddr_parse_any(&e->address, p); +} + + + +socktype_t *get_socket_type(const str *s); + + +#endif diff --git a/daemon/stun.c b/daemon/stun.c index 3a5de6273..ee441a6df 100644 --- a/daemon/stun.c +++ b/daemon/stun.c @@ -188,18 +188,21 @@ static int stun_attributes(struct stun_attrs *out, str *s, u_int16_t *unknowns, case STUN_XOR_MAPPED_ADDRESS: if (attr.len < 8) return -1; - out->mapped_port = ntohs(*((u_int16_t *) (&attr.s[2]))) ^ (STUN_COOKIE >> 16); - if (attr.len == 8 && ntohs(*((u_int16_t *) attr.s)) == 1) - in4_to_6(&out->mapped_address, - ntohl(*((u_int32_t *) (&attr.s[4]))) ^ STUN_COOKIE); + out->mapped.port = ntohs(*((u_int16_t *) (&attr.s[2]))) ^ (STUN_COOKIE >> 16); + if (attr.len == 8 && ntohs(*((u_int16_t *) attr.s)) == 1) { + out->mapped.address.family = get_socket_family_enum(SF_IP4); + out->mapped.address.u.ipv4.s_addr = + ntohl(*((u_int32_t *) (&attr.s[4]))) ^ STUN_COOKIE; + } else if (attr.len == 20 && ntohs(*((u_int16_t *) attr.s)) == 1) { - out->mapped_address.s6_addr32[0] + out->mapped.address.family = get_socket_family_enum(SF_IP6); + out->mapped.address.u.ipv6.s6_addr32[0] = *((u_int32_t *) (&attr.s[4])) ^ htonl(STUN_COOKIE); - out->mapped_address.s6_addr32[1] + out->mapped.address.u.ipv6.s6_addr32[1] = *((u_int32_t *) (&attr.s[8])) ^ req->transaction[0]; - out->mapped_address.s6_addr32[2] + out->mapped.address.u.ipv6.s6_addr32[2] = *((u_int32_t *) (&attr.s[12])) ^ req->transaction[1]; - out->mapped_address.s6_addr32[3] + out->mapped.address.u.ipv6.s6_addr32[3] = *((u_int32_t *) (&attr.s[16])) ^ req->transaction[2]; } break; @@ -228,7 +231,7 @@ out: return uc ? -1 : 0; } -static void output_init(struct msghdr *mh, struct iovec *iov, struct sockaddr_in6 *sin, +static void output_init(struct msghdr *mh, struct iovec *iov, struct header *hdr, unsigned short code, u_int32_t *transaction, unsigned char *buf, int buflen) { @@ -237,8 +240,6 @@ static void output_init(struct msghdr *mh, struct iovec *iov, struct sockaddr_in mh->msg_control = buf; mh->msg_controllen = buflen; - mh->msg_name = sin; - mh->msg_namelen = sizeof(*sin); mh->msg_iov = iov; mh->msg_iovlen = 1; @@ -297,7 +298,7 @@ static void __output_finish(struct msghdr *mh) { // __output_finish(mh); // stream_msg_mh_src(ps, mh); //} -static void output_finish_src(struct msghdr *mh, const struct in6_addr *src) { +static void output_finish_src(struct msghdr *mh, const sockaddr_t *src) { __output_finish(mh); msg_mh_src(src, mh); } @@ -352,7 +353,7 @@ static void integrity(struct msghdr *mh, struct msg_integrity *mi, str *pwd) { hdr->msg_len = ntohs(hdr->msg_len); } -static void stun_error_len(struct packet_stream *ps, struct sockaddr_in6 *sin, struct in6_addr *dst, +static void stun_error_len(struct packet_stream *ps, const endpoint_t *sin, const sockaddr_t *dst, struct header *req, int code, char *reason, int len, u_int16_t add_attr, void *attr_cont, int attr_len) @@ -366,7 +367,7 @@ static void stun_error_len(struct packet_stream *ps, struct sockaddr_in6 *sin, s struct iovec iov[7]; /* hdr, ec, reason, aa, attr_cont, mi, fp */ unsigned char buf[256]; - output_init(&mh, iov, sin, &hdr, STUN_BINDING_ERROR_RESPONSE, req->transaction, buf, sizeof(buf)); + output_init(&mh, iov, &hdr, STUN_BINDING_ERROR_RESPONSE, req->transaction, buf, sizeof(buf)); ec.codes = htonl(((code / 100) << 8) | (code % 100)); output_add_data(&mh, &ec, STUN_ERROR_CODE, reason, len); @@ -377,7 +378,7 @@ static void stun_error_len(struct packet_stream *ps, struct sockaddr_in6 *sin, s fingerprint(&mh, &fp); output_finish_src(&mh, dst); - sendmsg(ps->sfd->fd.fd, &mh, 0); + socket_sendmsg(&ps->sfd->socket, &mh, sin); } #define stun_error(ps, sin, dst, req, code, reason) \ @@ -447,7 +448,7 @@ static int check_auth(str *msg, struct stun_attrs *attrs, struct call_media *med /* XXX way too many parameters being passed around here, unify into a struct */ static int stun_binding_success(struct packet_stream *ps, struct header *req, struct stun_attrs *attrs, - struct sockaddr_in6 *sin, struct in6_addr *dst) + const endpoint_t *sin, const sockaddr_t *dst) { struct header hdr; struct xor_mapped_address xma; @@ -457,20 +458,20 @@ static int stun_binding_success(struct packet_stream *ps, struct header *req, st struct iovec iov[4]; /* hdr, xma, mi, fp */ unsigned char buf[256]; - output_init(&mh, iov, sin, &hdr, STUN_BINDING_SUCCESS_RESPONSE, req->transaction, buf, sizeof(buf)); + output_init(&mh, iov, &hdr, STUN_BINDING_SUCCESS_RESPONSE, req->transaction, buf, sizeof(buf)); - xma.port = sin->sin6_port ^ htons(STUN_COOKIE >> 16); - if (IN6_IS_ADDR_V4MAPPED(&sin->sin6_addr)) { + xma.port = htons(sin->port) ^ (STUN_COOKIE >> 16); + if (sin->address.family->af == AF_INET) { xma.family = htons(0x01); - xma.address[0] = sin->sin6_addr.s6_addr32[3] ^ htonl(STUN_COOKIE); + xma.address[0] = sin->address.u.ipv4.s_addr ^ htonl(STUN_COOKIE); output_add_len(&mh, &xma, STUN_XOR_MAPPED_ADDRESS, 8); } else { xma.family = htons(0x02); - xma.address[0] = sin->sin6_addr.s6_addr32[0] ^ htonl(STUN_COOKIE); - xma.address[1] = sin->sin6_addr.s6_addr32[1] ^ req->transaction[0]; - xma.address[2] = sin->sin6_addr.s6_addr32[2] ^ req->transaction[1]; - xma.address[3] = sin->sin6_addr.s6_addr32[3] ^ req->transaction[2]; + xma.address[0] = sin->address.u.ipv6.s6_addr32[0] ^ htonl(STUN_COOKIE); + xma.address[1] = sin->address.u.ipv6.s6_addr32[1] ^ req->transaction[0]; + xma.address[2] = sin->address.u.ipv6.s6_addr32[2] ^ req->transaction[1]; + xma.address[3] = sin->address.u.ipv6.s6_addr32[3] ^ req->transaction[2]; output_add(&mh, &xma, STUN_XOR_MAPPED_ADDRESS); } @@ -478,7 +479,7 @@ static int stun_binding_success(struct packet_stream *ps, struct header *req, st fingerprint(&mh, &fp); output_finish_src(&mh, dst); - sendmsg(ps->sfd->fd.fd, &mh, 0); + socket_sendmsg(&ps->sfd->socket, &mh, sin); return 0; } @@ -493,9 +494,9 @@ INLINE int u_int16_t_arr_len(u_int16_t *arr) { #define SLF " from %s" -#define SLP smart_ntop_port_buf(sin) -static int __stun_request(struct packet_stream *ps, struct sockaddr_in6 *sin, - struct in6_addr *dst, struct header *req, struct stun_attrs *attrs) +#define SLP endpoint_print_buf(sin) +static int __stun_request(struct packet_stream *ps, const endpoint_t *sin, + const sockaddr_t *dst, struct header *req, struct stun_attrs *attrs) { int ret; @@ -514,13 +515,13 @@ static int __stun_request(struct packet_stream *ps, struct sockaddr_in6 *sin, return ret; } -static int __stun_success(struct packet_stream *ps, struct sockaddr_in6 *sin, - struct in6_addr *dst, struct header *req, struct stun_attrs *attrs) +static int __stun_success(struct packet_stream *ps, const endpoint_t *sin, + const sockaddr_t *dst, struct header *req, struct stun_attrs *attrs) { return ice_response(ps, sin, dst, attrs, req->transaction); } -static int __stun_error(struct packet_stream *ps, struct sockaddr_in6 *sin, - struct in6_addr *dst, struct header *req, struct stun_attrs *attrs) +static int __stun_error(struct packet_stream *ps, const endpoint_t *sin, + const sockaddr_t *dst, struct header *req, struct stun_attrs *attrs) { return ice_response(ps, sin, dst, attrs, req->transaction); } @@ -533,7 +534,7 @@ static int __stun_error(struct packet_stream *ps, struct sockaddr_in6 *sin, * * call is locked in R */ -int stun(str *b, struct packet_stream *ps, struct sockaddr_in6 *sin, struct in6_addr *dst) { +int stun(str *b, struct packet_stream *ps, const endpoint_t *sin, const sockaddr_t *dst) { struct header *req = (void *) b->s; int msglen, method, class; str attr_str; @@ -620,9 +621,9 @@ ignore: return -1; } -int stun_binding_request(struct sockaddr_in6 *dst, u_int32_t transaction[3], str *pwd, +int stun_binding_request(const endpoint_t *dst, u_int32_t transaction[3], str *pwd, str ufrags[2], int controlling, u_int64_t tiebreaker, u_int32_t priority, - struct in6_addr *src, int fd, int to_use) + const sockaddr_t *src, socket_t *sock, int to_use) { struct header hdr; struct msghdr mh; @@ -637,7 +638,7 @@ int stun_binding_request(struct sockaddr_in6 *dst, u_int32_t transaction[3], str struct fingerprint fp; struct msg_integrity mi; - output_init(&mh, iov, dst, &hdr, STUN_BINDING_REQUEST, transaction, buf, sizeof(buf)); + output_init(&mh, iov, &hdr, STUN_BINDING_REQUEST, transaction, buf, sizeof(buf)); i = snprintf(username_buf, sizeof(username_buf), STR_FORMAT":"STR_FORMAT, STR_FMT(&ufrags[0]), STR_FMT(&ufrags[1])); @@ -658,7 +659,7 @@ int stun_binding_request(struct sockaddr_in6 *dst, u_int32_t transaction[3], str fingerprint(&mh, &fp); output_finish_src(&mh, src); - sendmsg(fd, &mh, 0); + socket_sendmsg(sock, &mh, dst); return 0; } diff --git a/daemon/stun.h b/daemon/stun.h index 9a52336fb..5f132b20d 100644 --- a/daemon/stun.h +++ b/daemon/stun.h @@ -8,6 +8,7 @@ #include "compat.h" #include "call.h" #include "str.h" +#include "socket.h" #define STUN_COOKIE 0x2112A442UL @@ -22,8 +23,7 @@ struct stun_attrs { char *fingerprint_attr; u_int32_t fingerprint; u_int64_t tiebreaker; - struct in6_addr mapped_address; - unsigned int mapped_port; /* XXX use struct endpoint */ + endpoint_t mapped; unsigned int error_code; int use:1, controlled:1, @@ -49,10 +49,10 @@ INLINE int is_stun(const str *s) { } -int stun(str *, struct packet_stream *, struct sockaddr_in6 *, struct in6_addr *); +int stun(str *, struct packet_stream *, const endpoint_t *, const sockaddr_t *); -int stun_binding_request(struct sockaddr_in6 *dst, u_int32_t transaction[3], str *pwd, +int stun_binding_request(const endpoint_t *dst, u_int32_t transaction[3], str *pwd, str ufrags[2], int controlling, u_int64_t tiebreaker, u_int32_t priority, - struct in6_addr *src, int fd, int); + const sockaddr_t *src, socket_t *, int); #endif diff --git a/daemon/udp_listener.c b/daemon/udp_listener.c index ec7a66d40..718decfdd 100644 --- a/daemon/udp_listener.c +++ b/daemon/udp_listener.c @@ -12,10 +12,12 @@ #include "str.h" #include "log.h" #include "obj.h" +#include "socket.h" struct udp_listener_callback { struct obj obj; udp_listener_callback_t func; + struct udp_listener *ul; struct obj *p; }; @@ -25,18 +27,20 @@ static void udp_listener_closed(int fd, void *p, uintptr_t x) { static void udp_listener_incoming(int fd, void *p, uintptr_t x) { struct udp_listener_callback *cb = p; - struct sockaddr_in6 sin; - socklen_t sin_len; int len; char buf[0x10000]; char addr[64]; str str; + struct udp_listener *ul; + socket_t *listener; + endpoint_t sin; str.s = buf; + ul = cb->ul; + listener = &ul->sock; for (;;) { - sin_len = sizeof(sin); - len = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &sin, &sin_len); + len = socket_recvfrom(listener, buf, sizeof(buf)-1, &sin); if (len < 0) { if (errno == EINTR) continue; @@ -46,39 +50,31 @@ static void udp_listener_incoming(int fd, void *p, uintptr_t x) { } buf[len] = '\0'; - smart_ntop_port(addr, &sin, sizeof(addr)); + endpoint_print(&sin, addr, sizeof(addr)); str.len = len; cb->func(cb->p, &str, &sin, addr); } } -int udp_listener_init(struct udp_listener *u, struct poller *p, struct in6_addr ip, u_int16_t port, udp_listener_callback_t func, struct obj *obj) { - struct sockaddr_in6 sin; +int udp_listener_init(struct udp_listener *u, struct poller *p, const endpoint_t *ep, + udp_listener_callback_t func, struct obj *obj) +{ struct poller_item i; struct udp_listener_callback *cb; cb = obj_alloc("udp_listener_callback", sizeof(*cb), NULL); cb->func = func; cb->p = obj_get_o(obj); + cb->ul = u; - u->fd = socket(AF_INET6, SOCK_DGRAM, 0); - if (u->fd == -1) + if (open_socket(&u->sock, SOCK_DGRAM, ep->port, &ep->address)) goto fail; - nonblock(u->fd); - reuseaddr(u->fd); - ipv6only(u->fd, 0); - - ZERO(sin); - sin.sin6_family = AF_INET6; - sin.sin6_addr = ip; - sin.sin6_port = htons(port); - if (bind(u->fd, (struct sockaddr *) &sin, sizeof(sin))) - goto fail; + ipv6only(u->sock.fd, 0); ZERO(i); - i.fd = u->fd; + i.fd = u->sock.fd; i.closed = udp_listener_closed; i.readable = udp_listener_incoming; i.obj = &cb->obj; @@ -88,8 +84,7 @@ int udp_listener_init(struct udp_listener *u, struct poller *p, struct in6_addr return 0; fail: - if (u->fd != -1) - close(u->fd); + close_socket(&u->sock); obj_put_o(obj); obj_put(cb); return -1; diff --git a/daemon/udp_listener.h b/daemon/udp_listener.h index f0b85b6a8..a865babc8 100644 --- a/daemon/udp_listener.h +++ b/daemon/udp_listener.h @@ -4,18 +4,19 @@ #include #include "poller.h" #include "str.h" +#include "socket.h" struct poller; struct obj; -typedef void (*udp_listener_callback_t)(struct obj *p, str *buf, struct sockaddr_in6 *sin, char *addr); +typedef void (*udp_listener_callback_t)(struct obj *p, str *buf, const endpoint_t *ep, char *addr); struct udp_listener { - int fd; + socket_t sock; struct poller *poller; }; -int udp_listener_init(struct udp_listener *, struct poller *p, struct in6_addr ip, u_int16_t port, udp_listener_callback_t, struct obj *); +int udp_listener_init(struct udp_listener *, struct poller *p, const endpoint_t *, udp_listener_callback_t, struct obj *); #endif