Browse Source

complete rework and abstraction of socket handling - WIP

pull/163/head
Richard Fuchs 11 years ago
parent
commit
e520b4fe07
34 changed files with 1453 additions and 1121 deletions
  1. +2
    -2
      daemon/Makefile
  2. +8
    -228
      daemon/aux.h
  3. +127
    -322
      daemon/call.c
  4. +12
    -58
      daemon/call.h
  5. +17
    -31
      daemon/call_interfaces.c
  6. +3
    -2
      daemon/call_interfaces.h
  7. +13
    -24
      daemon/cli.c
  8. +4
    -3
      daemon/cli.h
  9. +8
    -9
      daemon/control_ng.c
  10. +3
    -2
      daemon/control_ng.h
  11. +8
    -19
      daemon/control_tcp.c
  12. +2
    -1
      daemon/control_tcp.h
  13. +9
    -11
      daemon/control_udp.c
  14. +2
    -1
      daemon/control_udp.h
  15. +6
    -20
      daemon/dtls.c
  16. +2
    -1
      daemon/dtls.h
  17. +32
    -71
      daemon/graphite.c
  18. +1
    -1
      daemon/graphite.h
  19. +59
    -84
      daemon/ice.c
  20. +14
    -19
      daemon/ice.h
  21. +2
    -2
      daemon/log.c
  22. +47
    -53
      daemon/main.c
  23. +209
    -0
      daemon/media_socket.c
  24. +89
    -0
      daemon/media_socket.h
  25. +1
    -1
      daemon/redis.c
  26. +2
    -1
      daemon/redis.h
  27. +38
    -82
      daemon/sdp.c
  28. +5
    -6
      daemon/sdp.h
  29. +462
    -0
      daemon/socket.c
  30. +202
    -0
      daemon/socket.h
  31. +38
    -37
      daemon/stun.c
  32. +5
    -5
      daemon/stun.h
  33. +17
    -22
      daemon/udp_listener.c
  34. +4
    -3
      daemon/udp_listener.h

+ 2
- 2
daemon/Makefile View File

@ -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)


+ 8
- 228
daemon/aux.h View File

@ -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));
}


+ 127
- 322
daemon/call.c View File

@ -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);
}

+ 12
- 58
daemon/call.h View File

@ -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;


+ 17
- 31
daemon/call_interfaces.c View File

@ -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);


+ 3
- 2
daemon/call_interfaces.h View File

@ -6,6 +6,7 @@
#include <glib.h>
#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 *);


+ 13
- 24
daemon/cli.c View File

@ -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;
}

+ 4
- 3
daemon/cli.h View File

@ -1,18 +1,19 @@
#ifndef CLI_UDP_H_
#define CLI_UDP_H_
#include <netinet/in.h>
#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_ */

+ 8
- 9
daemon/control_ng.c View File

@ -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;


+ 3
- 2
daemon/control_ng.h View File

@ -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

+ 8
- 19
daemon/control_tcp.c View File

@ -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;
}


+ 2
- 1
daemon/control_tcp.h View File

@ -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)));


+ 9
- 11
daemon/control_udp.c View File

@ -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;


+ 2
- 1
daemon/control_udp.h View File

@ -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 *);


+ 6
- 20
daemon/dtls.c View File

@ -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);


+ 2
- 1
daemon/dtls.h View File

@ -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);


+ 32
- 71
daemon/graphite.c View File

@ -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


+ 1
- 1
daemon/graphite.h View File

@ -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);


+ 59
- 84
daemon/ice.c View File

@ -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) {


+ 14
- 19
daemon/ice.h View File

@ -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 */


+ 2
- 2
daemon/log.c View File

@ -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"] ",


+ 47
- 53
daemon/main.c View File

@ -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);


+ 209
- 0
daemon/media_socket.c View File

@ -0,0 +1,209 @@
#include "media_socket.h"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#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);
}

+ 89
- 0
daemon/media_socket.h View File

@ -0,0 +1,89 @@
#ifndef _MEDIA_SOCKET_H_
#define _MEDIA_SOCKET_H_
#include <glib.h>
#include <string.h>
#include <stdio.h>
#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

+ 1
- 1
daemon/redis.c View File

@ -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 *);


+ 2
- 1
daemon/redis.h View File

@ -6,6 +6,7 @@
#include <sys/types.h>
#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 *);


+ 38
- 82
daemon/sdp.c View File

@ -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


+ 5
- 6
daemon/sdp.h View File

@ -4,6 +4,7 @@
#include <glib.h>
#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;
}


+ 462
- 0
daemon/socket.c View File

@ -0,0 +1,462 @@
#include "socket.h"
#include <glib.h>
#include <unistd.h>
#include <errno.h>
#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;
}

+ 202
- 0
daemon/socket.h View File

@ -0,0 +1,202 @@
#ifndef _SOCKET_H_
#define _SOCKET_H_
#include <arpa/inet.h>
#include <sys/types.h>
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

+ 38
- 37
daemon/stun.c View File

@ -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;
}

+ 5
- 5
daemon/stun.h View File

@ -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

+ 17
- 22
daemon/udp_listener.c View File

@ -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;


+ 4
- 3
daemon/udp_listener.h View File

@ -4,18 +4,19 @@
#include <netinet/in.h>
#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

Loading…
Cancel
Save