Browse Source

Mass update - manual merge of rfuchs/socket-rework branch

This brings master up to date with branch `rfuchs/socket-rework` at
commit `b1bcc096b7`. The branches have diverged too much for a proper
merge, so this is a manual (squashed) merge.

The old master before this merge can be found in branch
`old-master-before-socket-rework` (commit `82199216b2`).

This is a complete rewrite of all socket handling routines. The most
important functional change is that sockets aren't indiscriminately
bound to INADDR_ANY (or rather in6addr_any), but instead are always
bound to their respective local interface address and with the correct
address family.

Side effects of this are that in multi-homed environments, multiple
sockets must be opened (one per interface address and family) which must
be taken into account when considering RLIMIT_NOFILE values. As a
benefit, this change allows rtpengine to utilize the full UDP port space
per interface address, instead of just one port space per machine.

The socket abstraction also makes it possible to support RTP over TCP in
the future.

Change-Id: If6cf4f42136229490186d2d2482fb4fc140c2b53
pull/197/head
Richard Fuchs 10 years ago
parent
commit
6d3865b971
38 changed files with 3861 additions and 3108 deletions
  1. +1
    -0
      daemon/.ycm_extra_conf.py
  2. +2
    -2
      daemon/Makefile
  3. +39
    -268
      daemon/aux.h
  4. +281
    -1517
      daemon/call.c
  5. +34
    -96
      daemon/call.h
  6. +27
    -35
      daemon/call_interfaces.c
  7. +3
    -2
      daemon/call_interfaces.h
  8. +20
    -32
      daemon/cli.c
  9. +4
    -3
      daemon/cli.h
  10. +14
    -13
      daemon/control_ng.c
  11. +4
    -3
      daemon/control_ng.h
  12. +8
    -19
      daemon/control_tcp.c
  13. +2
    -1
      daemon/control_tcp.h
  14. +17
    -22
      daemon/control_udp.c
  15. +3
    -2
      daemon/control_udp.h
  16. +18
    -46
      daemon/dtls.c
  17. +2
    -1
      daemon/dtls.h
  18. +33
    -72
      daemon/graphite.c
  19. +1
    -1
      daemon/graphite.h
  20. +87
    -108
      daemon/ice.c
  21. +15
    -20
      daemon/ice.h
  22. +2
    -2
      daemon/kernel.c
  23. +2
    -1
      daemon/kernel.h
  24. +2
    -2
      daemon/log.c
  25. +58
    -75
      daemon/main.c
  26. +1443
    -0
      daemon/media_socket.c
  27. +112
    -0
      daemon/media_socket.h
  28. +663
    -536
      daemon/redis.c
  29. +10
    -12
      daemon/redis.h
  30. +69
    -106
      daemon/sdp.c
  31. +5
    -6
      daemon/sdp.h
  32. +550
    -0
      daemon/socket.c
  33. +224
    -0
      daemon/socket.h
  34. +13
    -0
      daemon/str.h
  35. +64
    -74
      daemon/stun.c
  36. +5
    -5
      daemon/stun.h
  37. +18
    -23
      daemon/udp_listener.c
  38. +6
    -3
      daemon/udp_listener.h

+ 1
- 0
daemon/.ycm_extra_conf.py View File

@ -22,6 +22,7 @@ flags = [
'-I../kernel-module/',
'-D_GNU_SOURCE',
'-D__DEBUG=1',
'-D__YCM=1',
'-DRTPENGINE_VERSION="dummy"',
'-DRE_PLUGIN_DIR="/usr/lib/rtpengine"',
'-O2',


+ 2
- 2
daemon/Makefile View File

@ -64,8 +64,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)


+ 39
- 268
daemon/aux.h View File

@ -51,7 +51,6 @@ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
/*** HELPER MACROS ***/
#define OFFSET_OF(t,e) ((unsigned int) (unsigned long) &(((t *) 0)->e))
#define ZERO(x) memset(&(x), 0, sizeof(x))
#define UINT64F "%" G_GUINT64_FORMAT
@ -60,16 +59,8 @@ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
#define NUM_THREAD_BUFS 8
/*** TYPES ***/
struct endpoint {
struct in6_addr ip46;
u_int16_t port;
};
#define ALGORITHM_DEFAULT ""
#define ALGORITHM_ROUND_ROBIN_CALLS "round-robin-calls"
/*** GLOBALS ***/
@ -213,22 +204,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) {
@ -272,239 +247,6 @@ 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;
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;
}
INLINE void msg_mh_src(const struct in6_addr *src, struct msghdr *mh) {
struct cmsghdr *ch;
struct in_pktinfo *pi;
struct in6_pktinfo *pi6;
struct sockaddr_in6 *sin6;
sin6 = mh->msg_name;
ch = CMSG_FIRSTHDR(mh);
ZERO(*ch);
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
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);
mh->msg_controllen = CMSG_SPACE(sizeof(*pi));
}
else {
ch->cmsg_len = CMSG_LEN(sizeof(*pi6));
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = IPV6_PKTINFO;
pi6 = (void *) CMSG_DATA(ch);
ZERO(*pi6);
pi6->ipi6_addr = *src;
mh->msg_controllen = CMSG_SPACE(sizeof(*pi6));
}
}
/*** MUTEX ABSTRACTION ***/
@ -808,30 +550,30 @@ INLINE void atomic64_local_copy_zero(atomic64 *dst, atomic64 *src) {
/*** TIMEVAL FUNCTIONS ***/
INLINE long long timeval_ms(const struct timeval *t) {
INLINE long long timeval_us(const struct timeval *t) {
return (long long) ((long long) t->tv_sec * 1000000LL) + t->tv_usec;
}
INLINE void timeval_from_ms(struct timeval *t, long long ms) {
INLINE void timeval_from_us(struct timeval *t, long long ms) {
t->tv_sec = ms/1000000LL;
t->tv_usec = ms%1000000LL;
}
INLINE long long timeval_diff(const struct timeval *a, const struct timeval *b) {
return timeval_ms(a) - timeval_ms(b);
return timeval_us(a) - timeval_us(b);
}
INLINE void timeval_subtract(struct timeval *result, const struct timeval *a, const struct timeval *b) {
timeval_from_ms(result, timeval_diff(a, b));
timeval_from_us(result, timeval_diff(a, b));
}
INLINE void timeval_multiply(struct timeval *result, const struct timeval *a, const long multiplier) {
timeval_from_ms(result, timeval_ms(a) * multiplier);
timeval_from_us(result, timeval_us(a) * multiplier);
}
INLINE void timeval_divide(struct timeval *result, const struct timeval *a, const long divisor) {
timeval_from_ms(result, timeval_ms(a) / divisor);
timeval_from_us(result, timeval_us(a) / divisor);
}
INLINE void timeval_add(struct timeval *result, const struct timeval *a, const struct timeval *b) {
timeval_from_ms(result, timeval_ms(a) + timeval_ms(b));
timeval_from_us(result, timeval_us(a) + timeval_us(b));
}
INLINE void timeval_add_usec(struct timeval *tv, long usec) {
timeval_from_ms(tv, timeval_ms(tv) + usec);
timeval_from_us(tv, timeval_us(tv) + usec);
}
INLINE int timeval_cmp(const struct timeval *a, const struct timeval *b) {
long long diff;
@ -849,4 +591,33 @@ INLINE void timeval_lowest(struct timeval *l, const struct timeval *n) {
*l = *n;
}
/*** ALLOC WITH UNIQUE ID HELPERS ***/
#define uid_slice_alloc(ptr, q) __uid_slice_alloc(sizeof(*(ptr)), q, \
G_STRUCT_OFFSET(__typeof__(*(ptr)), unique_id))
#define uid_slice_alloc0(ptr, q) __uid_slice_alloc0(sizeof(*(ptr)), q, \
G_STRUCT_OFFSET(__typeof__(*(ptr)), unique_id))
INLINE void __uid_slice_alloc_fill(void *ptr, GQueue *q, unsigned int offset) {
unsigned int *id;
id = G_STRUCT_MEMBER_P(ptr, offset);
*id = g_queue_get_length(q);
g_queue_push_tail(q, ptr);
}
INLINE void *__uid_slice_alloc(unsigned int size, GQueue *q, unsigned int offset) {
void *ret;
ret = g_slice_alloc(size);
__uid_slice_alloc_fill(ret, q, offset);
return ret;
}
INLINE void *__uid_slice_alloc0(unsigned int size, GQueue *q, unsigned int offset) {
void *ret;
ret = g_slice_alloc0(size);
__uid_slice_alloc_fill(ret, q, offset);
return ret;
}
#endif

+ 281
- 1517
daemon/call.c
File diff suppressed because it is too large
View File


+ 34
- 96
daemon/call.h View File

@ -17,6 +17,8 @@
#include "compat.h"
#include "control_ng.h"
#include "aux.h"
#include "socket.h"
#include "media_socket.h"
#define TRUNCATED " ... Output truncated. Increase Output Buffer ... \n"
@ -86,14 +88,14 @@ enum call_stream_state {
#include "rtp.h"
#define ERROR_NO_FREE_PORTS -100
#define ERROR_NO_FREE_LOGS -101
#define MAX_RTP_PACKET_SIZE 8192
#define RTP_BUFFER_HEAD_ROOM 128
#define RTP_BUFFER_TAIL_ROOM 512
#define RTP_BUFFER_SIZE (MAX_RTP_PACKET_SIZE + RTP_BUFFER_HEAD_ROOM + RTP_BUFFER_TAIL_ROOM)
#define MAX_REDIS_HKEY_SIZE 150
#ifndef RTP_LOOP_PROTECT
#define RTP_LOOP_PROTECT 28 /* number of bytes */
#define RTP_LOOP_PACKETS 2 /* number of packets */
@ -186,8 +188,8 @@ enum call_stream_state {
#define MEDIA_SET(p, f) bf_set(&(p)->media_flags, MEDIA_FLAG_ ## f)
#define MEDIA_CLEAR(p, f) bf_clear(&(p)->media_flags, MEDIA_FLAG_ ## f)
typedef enum { RC_SFD, RC_EM, RC_PS, RC_MEDIA, RC_MONO, RC_LIMIT} rc_type;
typedef struct redis_hkey_counters { unsigned char val[RC_LIMIT]; } redis_hkey_counters;
struct poller;
struct control_stream;
@ -243,7 +245,7 @@ struct totalstats {
mutex_t total_average_lock; /* for these two below */
u_int64_t total_managed_sess;
struct timeval total_average_call_dur;
struct timeval total_average_call_dur;
mutex_t managed_sess_lock; /* for these below */
u_int64_t managed_sess_crt;
@ -254,10 +256,6 @@ struct totalstats {
struct timeval total_calls_duration_interval;
};
struct udp_fd {
int fd;
u_int16_t localport;
};
struct stream_params {
unsigned int index; /* starting with 1 */
str type;
@ -268,7 +266,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 */
@ -277,21 +275,13 @@ 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 */
char redis_hkey[MAX_REDIS_HKEY_SIZE];
};
struct endpoint_map {
unsigned int unique_id;
struct endpoint endpoint;
GQueue sfds;
unsigned int num_ports;
const struct logical_intf *logical_intf;
GQueue intf_sfds; /* list of struct intf_list - contains stream_fd list */
int wildcard:1;
char redis_hkey[MAX_REDIS_HKEY_SIZE];
};
struct loop_protector {
@ -300,7 +290,7 @@ struct loop_protector {
};
struct rtp_stats {
unsigned int payload_type;
unsigned int payload_type;
atomic64 packets;
atomic64 bytes;
atomic64 kernel_packets;
@ -318,8 +308,10 @@ struct packet_stream {
struct call_media *media; /* RO */
struct call *call; /* RO */
unsigned int component; /* RO, starts with 1 */
unsigned int unique_id; /* RO */
struct stream_fd *sfd; /* LOCK: call->master_lock */
GQueue sfds; /* LOCK: call->master_lock */
struct stream_fd * volatile selected_sfd;
struct packet_stream *rtp_sink; /* LOCK: call->master_lock */
struct packet_stream *rtcp_sink; /* LOCK: call->master_lock */
struct packet_stream *rtcp_sibling; /* LOCK: call->master_lock */
@ -344,7 +336,6 @@ struct packet_stream {
/* in_lock must be held for SETTING these: */
volatile unsigned int ps_flags;
char redis_hkey[MAX_REDIS_HKEY_SIZE];
};
/* protected by call->master_lock, except the RO elements */
@ -353,15 +344,11 @@ struct call_media {
struct call *call; /* RO */
unsigned int index; /* RO */
unsigned int unique_id; /* RO */
str type; /* RO */
const struct transport_protocol *protocol;
int desired_family;
struct local_interface *interface;
/* 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;
sockfamily_t *desired_family;
const struct logical_intf *logical_intf;
struct ice_agent *ice_agent;
@ -374,17 +361,17 @@ struct call_media {
struct dtls_fingerprint fingerprint; /* as received */
GQueue streams; /* normally RTP + RTCP */
GSList *endpoint_maps;
GQueue endpoint_maps;
GHashTable *rtp_payload_types;
volatile unsigned int media_flags;
char redis_hkey[MAX_REDIS_HKEY_SIZE];
};
/* half a dialogue */
/* protected by call->master_lock, except the RO elements */
struct call_monologue {
struct call *call; /* RO */
unsigned int unique_id; /* RO */
str tag;
str viabranch;
@ -398,7 +385,6 @@ struct call_monologue {
struct call_monologue *active_dialogue;
GQueue medias;
char redis_hkey[MAX_REDIS_HKEY_SIZE];
};
struct call {
@ -407,52 +393,32 @@ struct call {
struct callmaster *callmaster; /* RO */
mutex_t buffer_lock;
call_buffer_t buffer;
GQueue rtp_bridge_ports;
call_buffer_t buffer;
/* everything below protected by master_lock */
rwlock_t master_lock;
GSList *monologues;
GHashTable *tags;
GQueue monologues;
GQueue medias;
GHashTable *tags;
GHashTable *viabranches;
GSList *streams;
GSList *stream_fds;
GQueue streams;
GQueue stream_fds;
GQueue endpoint_maps;
struct dtls_cert *dtls_cert; /* for outgoing */
str callid;
str callid;
time_t created;
time_t last_signal;
time_t deleted;
time_t ml_deleted;
unsigned char tos;
unsigned char tos;
char *created_from;
struct sockaddr_in6 created_from_addr;
struct redis_hkey_counters rc;
};
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;
int max_sessions;
unsigned int timeout;
unsigned int silent_timeout;
@ -463,8 +429,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;
};
@ -474,13 +439,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 */
@ -511,8 +469,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);
struct timeval add_ongoing_calls_dur_in_interval(struct callmaster *m,
struct timeval *iv_start, struct timeval *iv_duration);
@ -523,8 +479,6 @@ void calls_dump_redis_write(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 packet_stream *__packet_stream_new(struct call *call);
@ -538,19 +492,11 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc
const str *fromtag, const str *totag, bencode_item_t *output, int delete_delay);
void call_destroy(struct call *);
enum call_stream_state call_stream_state_machine(struct packet_stream *);
void call_media_state_machine(struct call_media *m);
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, const struct local_intf *ifa);
const struct transport_protocol *transport_protocol(const str *s);
void add_total_calls_duration_in_interval(struct callmaster *cm, struct timeval *interval_tv);
@ -608,9 +554,6 @@ INLINE str *call_str_init_dup(struct call *c, char *s) {
str_init(&t, 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);
}
INLINE struct packet_stream *packet_stream_sink(struct packet_stream *ps) {
struct packet_stream *ret;
ret = ps->rtp_sink;
@ -619,11 +562,6 @@ INLINE struct packet_stream *packet_stream_sink(struct packet_stream *ps) {
return ret;
}
INLINE void redis_hkey_cpy(char *dst, char *src) {
strncpy(dst, src, MAX_REDIS_HKEY_SIZE);
dst[MAX_REDIS_HKEY_SIZE-1] = '\0';
}
const char * get_tag_type_text(enum tag_type t);
#endif

+ 27
- 35
daemon/call_interfaces.c View File

@ -31,7 +31,7 @@ static int call_stream_address_gstring(GString *o, struct packet_stream *ps, enu
int len, ret;
char buf[64]; /* 64 bytes ought to be enough for anybody */
ret = call_stream_address(buf, ps, format, &len);
ret = call_stream_address46(buf, ps, format, &len, NULL);
g_string_append_len(o, buf, len);
return ret;
}
@ -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->selected_sfd ? ps->selected_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);
@ -217,7 +214,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) {
@ -240,7 +237,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;
@ -250,12 +246,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;
@ -648,13 +641,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;
@ -697,7 +690,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 */
@ -734,6 +727,12 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster
gettimeofday(&(monologue->started), NULL);
errstr = "Error rewriting SDP";
if (ret == ERROR_NO_FREE_PORTS || ret == ERROR_NO_FREE_LOGS) {
ilog(LOG_ERR, "Destroying call");
call_destroy(call);
}
if (ret)
goto out;
@ -750,7 +749,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)
{
if (m->conf.max_sessions>=0) {
rwlock_lock_r(&m->hashlock);
@ -822,18 +821,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);
}
@ -850,8 +842,8 @@ 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);
if (ps->selected_sfd)
bencode_dictionary_add_integer(dict, "local port", ps->selected_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);
@ -963,7 +955,7 @@ void ng_call_stats(struct call *call, const str *fromtag, const str *totag, benc
{
bencode_item_t *tags = NULL, *dict;
const str *match_tag;
GSList *l;
GList *l;
struct call_monologue *ml;
struct call_stats t_b;
@ -985,7 +977,7 @@ stats:
match_tag = (totag && totag->s && totag->len) ? totag : fromtag;
if (!match_tag || !match_tag->len) {
for (l = call->monologues; l; l = l->next) {
for (l = call->monologues.head; l; l = l->next) {
ml = l->data;
ng_stats_monologue(tags, ml, totals);
}


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


+ 20
- 32
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"
@ -86,9 +87,8 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m
}
for (GList *l = list; l; l = l->next) {
struct control_ng_stats* cur = l->data;
printlen = snprintf(replybuffer,(outbufend-replybuffer), " %20s | %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,
@ -142,7 +142,7 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m
struct call_monologue *ml;
struct call_media *md;
struct packet_stream *ps;
GSList *l;
GList *l;
GList *k, *o;
int printlen=0;
struct timeval tim_result_duration;
@ -168,7 +168,7 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m
c->callid.s , c->ml_deleted?"yes":"no", (int)c->created, c->created_from, (unsigned int)c->tos, (unsigned long long)c->last_signal);
ADJUSTLEN(printlen,outbufend,replybuffer);
for (l = c->monologues; l; l = l->next) {
for (l = c->monologues.head; l; l = l->next) {
ml = l->data;
if (!ml->terminated.tv_sec) {
gettimeofday(&now, NULL);
@ -200,7 +200,7 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m
""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,
sockaddr_print_buf(&ps->endpoint.ip46), ps->endpoint.port,
(!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "",
atomic64_get(&ps->stats.packets),
atomic64_get(&ps->stats.bytes),
@ -211,7 +211,7 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m
""UINT64F" p, "UINT64F" b, "UINT64F" e, "UINT64F" last_packet, %.9f delay_min, %.9f delay_avg, %.9f delay_max\n",
md->index,
(unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0),
smart_ntop_p_buf(&ps->endpoint.ip46), ps->endpoint.port,
sockaddr_print_buf(&ps->endpoint.ip46), ps->endpoint.port,
(!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "",
atomic64_get(&ps->stats.packets),
atomic64_get(&ps->stats.bytes),
@ -222,11 +222,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->selected_sfd ? ps->selected_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),
@ -408,7 +408,7 @@ static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m,
GHashTableIter iter;
gpointer key, value;
struct call_monologue *ml;
GSList *i;
GList *i;
if (len<=1) {
printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required.");
@ -426,7 +426,7 @@ static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m,
c = (struct call*)value;
if (!c) continue;
if (!c->ml_deleted) {
for (i = c->monologues; i; i = i->next) {
for (i = c->monologues.head; i; i = i->next) {
ml = i->data;
gettimeofday(&(ml->terminated), NULL);
ml->term_reason = FORCED;
@ -450,7 +450,7 @@ static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m,
}
if (!c->ml_deleted) {
for (i = c->monologues; i; i = i->next) {
for (i = c->monologues.head; i; i = i->next) {
ml = i->data;
gettimeofday(&(ml->terminated), NULL);
ml->term_reason = FORCED;
@ -538,40 +538,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;
@ -584,6 +572,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_ */

+ 14
- 13
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,24 +68,26 @@ 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 udp_listener *ul)
{
struct control_ng *c = (void *) obj;
bencode_buffer_t bencbuf;
bencode_item_t *dict, *resp;
str cmd, cookie, data, reply, *to_send, callid;
const char *errstr;
struct msghdr mh;
struct iovec iov[3];
unsigned int iovlen;
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) {
@ -195,11 +198,7 @@ send_resp:
}
send_only:
ZERO(mh);
mh.msg_name = sin;
mh.msg_namelen = sizeof(*sin);
mh.msg_iov = iov;
mh.msg_iovlen = 3;
iovlen = 3;
iov[0].iov_base = cookie.s;
iov[0].iov_len = cookie.len;
@ -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_sendiov(&ul->sock, iov, iovlen, 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, endpoint_t *ep, struct callmaster *m) {
struct control_ng *c;
if (!p || !m)
@ -235,7 +234,9 @@ 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_listeners[0], p, ep, control_ng_incoming, &c->obj))
goto fail2;
if (ipv46_any_convert(ep) && udp_listener_init(&c->udp_listeners[1], p, ep, control_ng_incoming, &c->obj))
goto fail2;
return c;


+ 4
- 3
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;
@ -24,9 +25,9 @@ struct control_ng {
struct obj obj;
struct callmaster *callmaster;
struct cookie_cache cookie_cache;
struct udp_listener udp_listener;
struct udp_listener udp_listeners[2];
};
struct control_ng *control_ng_new(struct poller *, struct in6_addr, u_int16_t, struct callmaster *);
struct control_ng *control_ng_new(struct poller *, 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)));


+ 17
- 22
daemon/control_udp.c View File

@ -17,15 +17,17 @@
#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 udp_listener *ul) {
struct control_udp *u = (void *) obj;
int ret;
int ovec[100];
char **out;
struct msghdr mh;
struct iovec iov[10];
unsigned int iovlen;
str cookie, *reply;
ret = pcre_exec(u->parse_re, u->parse_ree, buf->s, buf->len, 0, 0, ovec, G_N_ELEMENTS(ovec));
@ -40,11 +42,6 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6
pcre_get_substring_list(buf->s, ovec, ret, (const char ***) &out);
ZERO(mh);
mh.msg_name = sin;
mh.msg_namelen = sizeof(*sin);
mh.msg_iov = iov;
iov[0].iov_base = (void *) out[RE_UDP_COOKIE];
iov[0].iov_len = strlen(out[RE_UDP_COOKIE]);
if (out[RE_UDP_UL_CMD] && (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U' || chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L')) {
@ -54,15 +51,15 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6
iov[2].iov_len = strlen(out[3]);
iov[3].iov_base = "\n";
iov[3].iov_len = 1;
mh.msg_iovlen = 4;
iovlen = 4;
}
else {
iov[1].iov_base = " E8\n";
iov[1].iov_len = 4;
mh.msg_iovlen = 2;
iovlen = 2;
}
sendmsg(u->udp_listener.fd, &mh, 0);
socket_sendiov(&ul->sock, iov, iovlen, sin);
pcre_free(out);
@ -77,7 +74,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(&ul->sock, reply->s, reply->len, sin);
free(reply);
goto out;
}
@ -96,11 +93,7 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6
else if (chrtoupper(out[RE_UDP_DQ_CMD][0]) == 'Q')
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;
iovlen = 2;
iov[0].iov_base = (void *) out[RE_UDP_COOKIE];
iov[0].iov_len = strlen(out[RE_UDP_COOKIE]);
@ -117,18 +110,18 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6
ret = 1;
iov[2].iov_base = ret ? "1\n" : "0\n";
iov[2].iov_len = 2;
mh.msg_iovlen++;
iovlen++;
}
else {
iov[2].iov_base = "20040107\n";
iov[2].iov_len = 9;
mh.msg_iovlen++;
iovlen++;
}
sendmsg(u->udp_listener.fd, &mh, 0);
socket_sendiov(&ul->sock, iov, iovlen, sin);
}
if (reply) {
sendto(u->udp_listener.fd, reply->s, reply->len, 0, (struct sockaddr *) sin, sizeof(*sin));
socket_sendto(&ul->sock, reply->s, reply->len, sin);
cookie_cache_insert(&u->cookie_cache, &cookie, reply);
free(reply);
}
@ -140,7 +133,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, endpoint_t *ep, struct callmaster *m) {
struct control_udp *c;
const char *errptr;
int erroff;
@ -172,7 +165,9 @@ 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_listeners[0], p, ep, control_udp_incoming, &c->obj))
goto fail2;
if (ipv46_any_convert(ep) && udp_listener_init(&c->udp_listeners[1], p, ep, control_udp_incoming, &c->obj))
goto fail2;
return c;


+ 3
- 2
daemon/control_udp.h View File

@ -13,6 +13,7 @@
#include "aux.h"
#include "cookie_cache.h"
#include "udp_listener.h"
#include "socket.h"
@ -49,7 +50,7 @@ struct control_udp {
struct callmaster *callmaster;
struct cookie_cache cookie_cache;
struct udp_listener udp_listener;
struct udp_listener udp_listeners[2];
pcre *parse_re;
pcre_extra *parse_ree;
@ -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 *, endpoint_t *, struct callmaster *);


+ 18
- 46
daemon/dtls.c View File

@ -475,12 +475,12 @@ int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert
struct dtls_connection *d;
unsigned long err;
if (!ps || !ps->sfd)
if (!ps || !ps->selected_sfd)
return 0;
__DBG("dtls_connection_init(%i)", active);
d = &ps->sfd->dtls;
d = &ps->selected_sfd->dtls;
if (d->init) {
if ((d->active && active) || (!d->active && !active))
@ -516,7 +516,7 @@ int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert
if (!d->r_bio || !d->w_bio)
goto error;
SSL_set_app_data(d->ssl, ps->sfd); /* XXX obj reference here? */
SSL_set_app_data(d->ssl, ps->selected_sfd); /* XXX obj reference here? */
SSL_set_bio(d->ssl, d->r_bio, d->w_bio);
SSL_set_mode(d->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
@ -613,15 +613,15 @@ found:
if (d->active) {
/* we're the client */
crypto_init(&ps->crypto, &client);
crypto_init(&ps->sfd->crypto, &server);
crypto_init(&ps->selected_sfd->crypto, &server);
}
else {
/* we're the server */
crypto_init(&ps->crypto, &server);
crypto_init(&ps->sfd->crypto, &client);
crypto_init(&ps->selected_sfd->crypto, &client);
}
crypto_dump_keys(&ps->crypto, &ps->sfd->crypto);
crypto_dump_keys(&ps->crypto, &ps->selected_sfd->crypto);
return 0;
@ -635,20 +635,17 @@ 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;
unsigned char buf[0x10000];
if (!ps || !ps->sfd)
if (!ps || !ps->selected_sfd)
return 0;
if (!MEDIA_ISSET(ps->media, DTLS))
return 0;
d = &ps->sfd->dtls;
d = &ps->selected_sfd->dtls;
if (s)
__DBG("dtls packet input: len %u %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
@ -670,7 +667,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->selected_sfd->socket.local.port);
/* fatal error */
dtls_connection_cleanup(d);
return 0;
@ -709,30 +706,11 @@ 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;
}
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;
ZERO(iov);
iov.iov_base = buf;
iov.iov_len = ret;
stream_msg_mh_src(ps, &mh);
if (!fsin)
fsin = &ps->endpoint;
ilog(LOG_DEBUG, "Sending DTLS packet");
sendmsg(ps->sfd->fd.fd, &mh, 0);
socket_sendto(&ps->selected_sfd->socket, buf, ret, fsin);
}
return 0;
@ -741,25 +719,19 @@ 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)
if (!ps || !ps->selected_sfd)
return;
__DBG("dtls_shutdown");
d = &ps->sfd->dtls;
d = &ps->selected_sfd->dtls;
if (!d->init)
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);
@ -770,7 +742,7 @@ void dtls_shutdown(struct packet_stream *ps) {
}
crypto_reset(&ps->crypto);
crypto_reset(&ps->sfd->crypto);
crypto_reset(&ps->selected_sfd->crypto);
}
void dtls_connection_cleanup(struct dtls_connection *c) {


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


+ 33
- 72
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;
@ -39,65 +39,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(struct totalstats *sent_data) {
int rc=0;
if (graphite_sock < 0) {
if (graphite_sock.fd < 0) {
ilog(LOG_ERROR,"Graphite socket is not connected.");
return -1;
}
@ -186,7 +154,7 @@ int send_graphite_data(struct totalstats *sent_data) {
(unsigned long long ) ts->total_calls_duration_interval.tv_usec,
(unsigned long long ) g_now.tv_sec);
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;
@ -194,7 +162,7 @@ int send_graphite_data(struct totalstats *sent_data) {
return 0;
error:
close(graphite_sock); graphite_sock=-1;
close_socket(&graphite_sock);
return -1;
}
@ -213,33 +181,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.");
@ -259,15 +224,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) {
add_total_calls_duration_in_interval(cm, &graphite_interval_tv);
rc = send_graphite_data(&graphite_stats);
@ -276,7 +237,7 @@ void graphite_loop_run(struct callmaster* callmaster, int seconds) {
ilog(LOG_ERROR,"Sending graphite data failed.");
}
copy_with_lock(&cm->totalstats_lastinterval, &graphite_stats, &cm->totalstats_lastinterval_lock);
copy_with_lock(&cm->totalstats_lastinterval, &graphite_stats, &cm->totalstats_lastinterval.total_average_lock);
}
}
@ -289,7 +250,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);


+ 87
- 108
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,12 +97,12 @@ 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;
g = ice_priority(ICT_HOST, ifa->preference, cand->component_id);
g = ice_priority(ICT_HOST, ifa->unique_id, cand->component_id);
d = cand->priority;
if (!controlling) {
@ -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,20 +132,20 @@ 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,
struct ice_candidate *cand, struct packet_stream *ps)
static struct ice_candidate_pair *__pair_candidate(struct stream_fd *sfd, struct ice_agent *ag,
struct ice_candidate *cand)
{
struct ice_candidate_pair *pair;
if (addr->family != family_from_address(&cand->endpoint.ip46))
if (sfd->socket.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->packet_stream = ps;
pair->local_intf = sfd->local_intf;
pair->sfd = sfd;
if (cand->component_id != 1)
PAIR_SET(pair, FROZEN);
__do_ice_pair_priority(pair);
@ -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(&sfd->socket.local.address),
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;
@ -222,10 +210,10 @@ static int __pair_prio_cmp(const void *a, const void *b) {
return -1;
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)
/* highest local preference first, which is lowest unique_id first */
if (A->local_intf->unique_id < B->local_intf->unique_id)
return -1;
if (A->local_address->preference > B->local_address->preference)
if (A->local_intf->unique_id > B->local_intf->unique_id)
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);
@ -320,6 +308,7 @@ void ice_update(struct ice_agent *ag, struct stream_params *sp) {
unsigned int comps;
struct packet_stream *components[MAX_COMPONENTS], *ps;
GQueue *candidates;
struct stream_fd *sfd;
if (!ag)
return;
@ -336,7 +325,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,11 +413,13 @@ 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 = ps->sfds.head; k; k = k->next) {
sfd = k->data;
/* skip duplicates here also */
if (__pair_lookup(ag, dup, k->data))
if (__pair_lookup(ag, dup, sfd->local_intf))
continue;
__pair_candidate(k->data, ag, dup, ps);
__pair_candidate(sfd, ag, dup);
}
}
@ -614,8 +605,7 @@ 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 stream_fd *sfd = pair->sfd;
struct ice_agent *ag = pair->agent;
u_int32_t prio, transact[3];
@ -625,12 +615,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->unique_id,
pair->remote_candidate->component_id);
mutex_lock(&ag->lock);
@ -661,12 +646,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, &sfd->socket,
PAIR_ISSET(pair, TO_USE));
}
@ -721,7 +706,7 @@ static void __nominate_pairs(struct ice_agent *ag) {
static void __do_ice_checks(struct ice_agent *ag) {
GList *l;
struct ice_candidate_pair *pair, *highest = NULL, *frozen = NULL, *valid;
struct packet_stream *ps;
struct stream_fd *sfd;
GQueue retransmits = G_QUEUE_INIT;
struct timeval next_run = {0,0};
int have_more = 0;
@ -761,8 +746,8 @@ static void __do_ice_checks(struct ice_agent *ag) {
pair = l->data;
/* skip dead streams */
ps = pair->packet_stream;
if (!ps || !ps->sfd)
sfd = pair->sfd;
if (!sfd || !sfd->stream || !sfd->stream->selected_sfd)
continue;
if (PAIR_ISSET(pair, FAILED))
continue;
@ -835,13 +820,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);
}
@ -855,11 +839,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);
}
@ -868,29 +852,25 @@ 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)
static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, struct stream_fd *sfd,
const endpoint_t *src, unsigned long priority)
{
struct ice_candidate *cand, *old_cand;
struct ice_candidate_pair *pair;
struct call *call = ag->call;
struct packet_stream *ps = sfd->stream;
cand = g_slice_alloc0(sizeof(*cand));
cand->component_id = ps->component;
cand->transport = ITP_UDP;
cand->transport = sfd->local_intf->spec->address.type; // XXX add socket type into socket_t?
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);
@ -900,7 +880,7 @@ static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, stru
* address, but from different ports. we cannot distinguish such candidates and
* will drop the one with the lower priority */
g_slice_free1(sizeof(*cand), cand);
pair = __pair_lookup(ag, old_cand, ifa);
pair = __pair_lookup(ag, old_cand, sfd->local_intf);
if (pair)
goto out; /* nothing to do */
cand = old_cand;
@ -912,7 +892,7 @@ static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, stru
g_hash_table_insert(ag->foundation_hash, cand, cand);
pair:
pair = __pair_candidate(ifa, ag, cand, ps);
pair = __pair_candidate(sfd, ag, cand);
PAIR_SET(pair, LEARNED);
__all_pairs_list(ag);
@ -1005,7 +985,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))
@ -1029,10 +1009,11 @@ found:
static int __check_valid(struct ice_agent *ag) {
struct call_media *media = ag->media;
struct packet_stream *ps;
GList *l, *k;
GList *l, *k, *m;
GQueue all_compos;
struct ice_candidate_pair *pair;
struct interface_address *ifa;
// const struct local_intf *ifa;
struct stream_fd *sfd;
if (!ag) {
ilog(LOG_ERR, "ice ag is NULL");
@ -1050,12 +1031,6 @@ 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));
for (l = media->streams.head, k = all_compos.head; l && k; l = l->next, k = k->next) {
ps = l->data;
pair = k->data;
@ -1063,10 +1038,20 @@ 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);
for (m = ps->sfds.head; m; m = m->next) {
sfd = m->data;
if (sfd->local_intf != pair->local_intf)
continue;
ps->selected_sfd = sfd;
if (ps->component == 1)
ilog(LOG_INFO, "ICE negotiated: local interface %s",
sockaddr_print_buf(&pair->local_intf->spec->address.addr));
}
}
call_media_unkernelize(media);
@ -1083,18 +1068,19 @@ 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 stream_fd *sfd, const endpoint_t *src,
struct stun_attrs *attrs)
{
struct packet_stream *ps = sfd->stream;
struct call_media *media = ps->media;
struct ice_agent *ag;
struct interface_address *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),
endpoint_print_buf(&sfd->socket.local));
ag = media->ice_agent;
if (!ag)
@ -1102,20 +1088,15 @@ 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);
err = "ICE/STUN binding request received on unknown local interface address";
if (!ifa)
goto err;
/* determine candidate pair */
mutex_lock(&ag->lock);
cand = __cand_lookup(ag, src, ps->component);
if (!cand)
pair = __learned_candidate(ag, ps, src, ifa, attrs->priority);
pair = __learned_candidate(ag, sfd, src, attrs->priority);
else
pair = __pair_lookup(ag, cand, ifa);
pair = __pair_lookup(ag, cand, sfd->local_intf);
err = "Failed to determine ICE candidate from STUN request";
if (!pair)
@ -1167,8 +1148,8 @@ 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),
endpoint_print_buf(&sfd->socket.local));
return 0;
}
@ -1192,19 +1173,21 @@ 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 stream_fd *sfd, const endpoint_t *src,
struct stun_attrs *attrs, u_int32_t transaction[3])
{
struct ice_candidate_pair *pair, *opair;
struct ice_agent *ag;
struct packet_stream *ps = sfd->stream;
struct call_media *media = ps->media;
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),
endpoint_print_buf(&sfd->socket.local));
ag = media->ice_agent;
if (!ag)
@ -1222,24 +1205,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)))
goto err;
if (pair->packet_stream != ps)
if (pair->sfd != sfd)
goto err;
PAIR_CLEAR(pair, IN_PROGRESS);
@ -1321,7 +1300,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), endpoint_print_buf(&sfd->socket.local));
if (pair && attrs->error_code)
__fail_pair(pair);
@ -1402,9 +1381,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) {


+ 15
- 20
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,27 +75,20 @@ 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;
struct packet_stream *packet_stream;
const struct local_intf *local_intf;
struct stream_fd *sfd;
volatile unsigned int pair_flags;
u_int32_t stun_transaction[3]; /* belongs to transaction_hash, thus agent->lock */
unsigned int retransmit_ms;
@ -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 stream_fd *, const endpoint_t *, struct stun_attrs *);
int ice_response(struct stream_fd *, const endpoint_t *src,
struct stun_attrs *attrs, u_int32_t transaction[3]);
/* returns 0 if ICE still has work to do, 1 otherwise */


+ 2
- 2
daemon/kernel.c View File

@ -86,13 +86,13 @@ int kernel_add_stream(int fd, struct rtpengine_target_info *mti, int update) {
}
int kernel_del_stream(int fd, u_int16_t p) {
int kernel_del_stream(int fd, const struct re_address *a) {
struct rtpengine_message msg;
int ret;
ZERO(msg);
msg.cmd = MMG_DEL;
msg.target.target_port = p;
msg.target.local = *a;
ret = write(fd, &msg, sizeof(msg));
if (ret > 0)


+ 2
- 1
daemon/kernel.h View File

@ -11,6 +11,7 @@
struct rtpengine_target_info;
struct re_address;
@ -18,7 +19,7 @@ int kernel_create_table(unsigned int);
int kernel_open_table(unsigned int);
int kernel_add_stream(int, struct rtpengine_target_info *, int);
int kernel_del_stream(int, u_int16_t);
int kernel_del_stream(int, const struct re_address *);
GList *kernel_list(unsigned int);


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


+ 58
- 75
daemon/main.c View File

@ -27,6 +27,8 @@
#include "cli.h"
#include "graphite.h"
#include "ice.h"
#include "socket.h"
#include "media_socket.h"
@ -57,14 +59,14 @@ 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;
endpoint_t redis_read_ep;
endpoint_t redis_write_ep;
static int tos;
static int table = -1;
static int no_fallback;
@ -73,21 +75,13 @@ static int silent_timeout;
static int port_min = 30000;
static int port_max = 40000;
static int max_sessions = -1;
static u_int32_t redis_ip;
static u_int16_t redis_port;
static int redis_db = -1;
static u_int32_t redis_read_ip;
static u_int32_t redis_write_ip;
static u_int16_t redis_read_port;
static u_int16_t redis_write_port;
static int redis_read_db = -1;
static int redis_write_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) {
@ -146,10 +140,14 @@ static void signals(void) {
}
static void resources(void) {
struct rlimit rl;
int tryv;
rlim(RLIMIT_CORE, RLIM_INFINITY);
for (tryv = ((1<<20) - 1); tryv && rlim(RLIMIT_NOFILE, tryv) == -1; tryv >>= 1)
if (getrlimit(RLIMIT_NOFILE, &rl))
rl.rlim_cur = 0;
for (tryv = ((1<<20) - 1); tryv && tryv > rl.rlim_cur && rlim(RLIMIT_NOFILE, tryv) == -1; tryv >>= 1)
;
rlim(RLIMIT_DATA, RLIM_INFINITY);
@ -181,12 +179,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, '/');
@ -204,20 +201,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;
}
@ -227,7 +225,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;
@ -306,23 +304,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)");
}
@ -338,21 +336,21 @@ 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");
}
if (redisps_read) {
if (parse_ip_port(&redis_read_ip, &redis_read_port, redisps_read) || !redis_read_ip)
if (endpoint_parse_any(&redis_read_ep, redisps_read))
die("Invalid Redis read IP or port (--redis-read)");
if (redis_read_db < 0)
die("Must specify Redis read DB number (--redis-read-db) when using Redis");
}
if (redisps_write) {
if (parse_ip_port(&redis_write_ip, &redis_write_port, redisps_write) || !redis_write_ip)
if (endpoint_parse_any(&redis_write_ep, redisps_write))
die("Invalid Redis write IP or port (--redis-write)");
if (redis_write_db < 0)
die("Must specify Redis write DB number (--redis-write-db) when using Redis");
@ -451,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);
@ -468,19 +467,7 @@ static void init_everything() {
sdp_init();
dtls_init();
ice_init();
}
static double time_diff_ms(struct timeval x , struct timeval y)
{
double x_ms , y_ms , diff;
x_ms = (double)x.tv_sec * 1000 + (double)x.tv_usec / 1000;
y_ms = (double)y.tv_sec * 1000 + (double)y.tv_usec / 1000;
diff = (double)y_ms - (double)x_ms;
return diff;
interfaces_init(&interfaces);
}
@ -527,9 +514,6 @@ no_kernel:
ZERO(mc);
mc.kernelfd = kfd;
mc.kernelid = table;
mc.interfaces = &interfaces;
mc.port_min = port_min;
mc.port_max = port_max;
if (max_sessions < -1) {
max_sessions = -1;
}
@ -540,61 +524,59 @@ no_kernel:
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) {
interfaces_exclude_port(udp_listen_ep.port);
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) {
interfaces_exclude_port(ng_listen_ep.port);
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 (cli_listen_ep.port) {
interfaces_exclude_port(cli_listen_ep.port);
cl = cli_new(ctx->p, &cli_listen_ep, ctx->m);
if (!cl)
die("Failed to open UDP CLI connection port");
}
if (redis_ip) {
mc.redis = redis_new(redis_ip, redis_port, redis_db, MASTER_REDIS_ROLE);
if (!is_addr_unspecified(&redis_ep.address)) {
mc.redis = redis_new(&redis_ep, redis_db, MASTER_REDIS_ROLE);
if (!mc.redis)
die("Cannot start up without Redis database");
}
if (redis_read_ip) {
mc.redis_read = redis_new(redis_read_ip, redis_read_port, redis_read_db, ANY_REDIS_ROLE);
if (!is_addr_unspecified(&redis_read_ep.address)) {
mc.redis_read = redis_new(&redis_read_ep, redis_read_db, ANY_REDIS_ROLE);
if (!mc.redis_read)
die("Cannot start up without Redis read database");
}
if (redis_write_ip) {
mc.redis_write = redis_new(redis_write_ip, redis_write_port, redis_write_db, ANY_REDIS_ROLE);
if (!is_addr_unspecified(&redis_write_ep.address)) {
mc.redis_write = redis_new(&redis_write_ep, redis_write_db, ANY_REDIS_ROLE);
if (!mc.redis_write)
die("Cannot start up without Redis write database");
}
ctx->m->conf = mc;
callmaster_config_init(ctx->m);
if (!foreground)
daemonize();
@ -603,6 +585,7 @@ no_kernel:
// start redis restore timer
gettimeofday(&redis_start, NULL);
// restore
if (mc.redis_read) {
if (redis_restore(ctx->m, mc.redis_read, ANY_REDIS_ROLE))
die("Refusing to continue without working Redis read database");
@ -615,12 +598,12 @@ no_kernel:
gettimeofday(&redis_stop, NULL);
// print redis restore duration
redis_diff += time_diff_ms(redis_start, redis_stop);
redis_diff += timeval_diff(&redis_start, &redis_stop) / 1000.0;
ilog(LOG_INFO, "Redis restore time = %.0lf ms", redis_diff);
gettimeofday(&ctx->m->latest_graphite_interval_start, NULL);
timeval_from_ms(&tmp_tv, graphite_interval*1000000);
timeval_from_us(&tmp_tv, graphite_interval*1000000);
set_graphite_interval_tv(&tmp_tv);
}
@ -637,7 +620,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);


+ 1443
- 0
daemon/media_socket.c
File diff suppressed because it is too large
View File


+ 112
- 0
daemon/media_socket.h View File

@ -0,0 +1,112 @@
#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;
volatile unsigned int free_ports;
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 unique_id; /* starting with 0 - serves as preference */
const struct logical_intf *logical;
};
struct intf_list {
const struct local_intf *local_intf;
GQueue list;
};
struct stream_fd {
struct obj obj;
unsigned int unique_id; /* RO */
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, int num_ports);
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);
void interfaces_exclude_port(unsigned int port);
//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 *);
INLINE void set_tos(socket_t *s, unsigned int tos) {
s->family->tos(s, tos);
}
int __get_consecutive_ports(GQueue *out, unsigned int num_ports, unsigned int wanted_start_port,
struct intf_spec *spec);
int get_consecutive_ports(GQueue *out, unsigned int num_ports, const struct logical_intf *log);
struct stream_fd *stream_fd_new(socket_t *fd, struct call *call, const struct local_intf *lif);
void free_intf_list(struct intf_list *il);
void free_socket_intf_list(struct intf_list *il);
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);
}
void kernelize(struct packet_stream *);
void __unkernelize(struct packet_stream *);
void unkernelize(struct packet_stream *);
void __stream_unconfirm(struct packet_stream *);
/* 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

+ 663
- 536
daemon/redis.c
File diff suppressed because it is too large
View File


+ 10
- 12
daemon/redis.h View File

@ -4,6 +4,9 @@
#include <sys/types.h>
#include "compat.h"
#include "socket.h"
#include "aux.h"
#include <glib.h>
@ -21,9 +24,8 @@ struct call;
struct redis {
u_int32_t ip;
char host[32];
int port;
endpoint_t endpoint;
char host[64];
redisContext *ctx;
int db;
@ -35,17 +37,13 @@ struct redis_hash {
GHashTable *ht;
};
struct redis_list {
GQueue q;
struct redis_hash rh;
};
struct list_item {
redisReply *id;
struct redis_hash rh;
void *ptr;
unsigned int len;
struct redis_hash *rh;
void **ptrs;
};
#define HKEY(ptr) ptr ? ptr->redis_hkey : "0"
@ -77,7 +75,7 @@ INLINE gboolean g_hash_table_insert_check(GHashTable *h, gpointer k, gpointer v)
struct redis *redis_new(u_int32_t, u_int16_t, int, int);
struct redis *redis_new(const endpoint_t *, int, int);
int redis_restore(struct callmaster *, struct redis *, int);
void redis_update(struct call *, struct redis *, int);
void redis_delete(struct call *, struct redis *, int);


+ 69
- 106
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->selected_sfd ? ps->selected_sfd->socket.local.port : 0;
chopper_append_printf(chop, "%u", p);
if (skip_over(chop, port))
@ -1452,7 +1415,7 @@ static int replace_consecutive_port_count(struct sdp_chopper *chop, struct sdp_m
int cons;
struct packet_stream *ps_n;
if (media->port_count == 1 || !ps->sfd)
if (media->port_count == 1 || !ps->selected_sfd)
return 0;
for (cons = 1; cons < media->port_count; cons++) {
@ -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->selected_sfd->socket.local.port != ps->selected_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 stream_fd *sfd) {
char buf[64];
int len;
call_stream_address46(buf, ps, SAF_ICE, &len, ifa);
call_stream_address46(buf, sfd->stream, SAF_ICE, &len, sfd->local_intf);
chopper_append_dup(chop, buf, len);
chopper_append_printf(chop, " %hu", ps->sfd->fd.localport);
chopper_append_printf(chop, " %u", 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, const 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->selected_sfd->socket.local.port);
return 0;
}
@ -1514,17 +1477,10 @@ 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);
call_stream_address46(buf, ps, SAF_NG, &len, NULL);
chopper_append_dup(chop, buf, len);
if (skip_over(chop, &address->address))
@ -1725,17 +1681,21 @@ out:
*lprefp = lpref;
}
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)
static void insert_candidate(struct sdp_chopper *chop, struct stream_fd *sfd,
unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type)
{
unsigned long priority;
struct packet_stream *ps = sfd->stream;
const struct local_intf *ifa = sfd->local_intf;
priority = ice_priority_pref(type_pref, local_pref, component);
if (local_pref == -1)
local_pref = ifa->unique_id;
priority = ice_priority_pref(type_pref, local_pref, ps->component);
chopper_append_c(chop, "a=candidate:");
chopper_append_str(chop, &ifa->ice_foundation);
chopper_append_printf(chop, " %u UDP %lu ", component, priority);
insert_ice_address(chop, ps, ifa);
chopper_append_str(chop, &ifa->spec->ice_foundation);
chopper_append_printf(chop, " %u UDP %lu ", ps->component, priority);
insert_ice_address(chop, sfd);
chopper_append_c(chop, " typ ");
chopper_append_c(chop, ice_candidate_type_str(type));
/* raddr and rport are required for non-host candidates: rfc5245 section-15.1 */
@ -1744,14 +1704,26 @@ static void insert_candidate(struct sdp_chopper *chop, struct packet_stream *ps,
chopper_append_c(chop, "\r\n");
}
static void insert_sfd_candidates(struct sdp_chopper *chop, struct packet_stream *ps,
unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type)
{
GList *l;
struct stream_fd *sfd;
for (l = ps->sfds.head; l; l = l->next) {
sfd = l->data;
insert_candidate(chop, sfd, type_pref, local_pref, type);
if (local_pref != -1)
local_pref++;
}
}
static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp,
struct sdp_ng_flags *flags, struct sdp_media *sdp_media)
{
GList *l;
struct interface_address *ifa;
unsigned int pref;
const struct local_intf *ifa;
struct call_media *media;
struct local_interface *lif;
struct ice_agent *ag;
unsigned int type_pref, local_pref;
enum ice_candidate_type cand_type;
@ -1770,13 +1742,12 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt
}
ag = media->ice_agent;
lif = ag ? ag->local_interface : media->interface;
if (ag && AGENT_ISSET(ag, COMPLETED)) {
ifa = g_atomic_pointer_get(&media->local_address);
insert_candidate(chop, rtp, 1, type_pref, ifa->preference, cand_type, ifa);
ifa = rtp->selected_sfd->local_intf;
insert_candidate(chop, rtp->selected_sfd, type_pref, ifa->unique_id, cand_type);
if (rtcp) /* rtcp-mux only possible in answer */
insert_candidate(chop, rtcp, 2, type_pref, ifa->preference, cand_type, ifa);
insert_candidate(chop, rtcp->selected_sfd, type_pref, ifa->unique_id, cand_type);
if (flags->opmode == OP_OFFER && AGENT_ISSET(ag, CONTROLLING)) {
GQueue rc;
@ -1788,7 +1759,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);
@ -1796,18 +1767,10 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt
return;
}
for (l = lif->list.head; l; l = l->next) {
ifa = l->data;
pref = (local_pref == -1) ? ifa->preference : local_pref;
insert_candidate(chop, rtp, 1, type_pref, pref, cand_type, ifa);
insert_sfd_candidates(chop, rtp, type_pref, local_pref, cand_type);
if (rtcp) /* rtcp-mux only possible in answer */
insert_candidate(chop, rtcp, 2, type_pref, pref, cand_type, ifa);
if (local_pref != -1)
local_pref++;
}
if (rtcp) /* rtcp-mux only possible in answer */
insert_sfd_candidates(chop, rtcp, type_pref, local_pref, cand_type);
}
static void insert_dtls(struct call_media *media, struct sdp_chopper *chop) {
@ -1985,7 +1948,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
assert(j->data == ps_rtcp);
}
if (!sdp_media->port_num || !ps->sfd)
if (!sdp_media->port_num || !ps->selected_sfd)
goto next;
if (MEDIA_ARESET2(call_media, SEND, RECV))
@ -2000,13 +1963,13 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
if (call_media->protocol && call_media->protocol->rtp) {
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->selected_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->selected_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,
@ -63,10 +64,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;
}


+ 550
- 0
daemon/socket.c View File

@ -0,0 +1,550 @@
#include "socket.h"
#include <glib.h>
#include <unistd.h>
#include <errno.h>
#include "str.h"
#include "media_socket.h"
#include "xt_RTPENGINE.h"
#include "call.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 int __ip4_tos(socket_t *, unsigned int);
static int __ip6_tos(socket_t *, unsigned int);
static void __ip4_endpoint2kernel(struct re_address *, const endpoint_t *);
static void __ip6_endpoint2kernel(struct re_address *, const endpoint_t *);
static void __ip4_kernel2endpoint(endpoint_t *ep, const struct re_address *ra);
static void __ip6_kernel2endpoint(endpoint_t *ep, const struct re_address *ra);
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",
.unspec_string = "0.0.0.0",
.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,
.tos = __ip4_tos,
.endpoint2kernel = __ip4_endpoint2kernel,
.kernel2endpoint = __ip4_kernel2endpoint,
},
[SF_IP6] = {
.af = AF_INET6,
.sockaddr_size = sizeof(struct sockaddr_in6),
.name = "IPv6",
.rfc_name = "IP6",
.unspec_string = "::",
.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,
.tos = __ip6_tos,
.endpoint2kernel = __ip6_endpoint2kernel,
.kernel2endpoint = __ip6_kernel2endpoint,
},
};
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;
ZERO(*ep);
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;
ZERO(*ep);
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)) {
__C_DBG("bind fail, fd=%d, port=%d", s->fd, s->local.port);
return -1;
} else {
__C_DBG("bind success, fd=%d, port=%d", s->fd, s->local.port);
}
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)) {
__C_DBG("connect fail, fd=%d, port=%d", s->fd, s->local.port);
return -1;
} else {
__C_DBG("connect succes, fd=%d, port=%d", s->fd, s->local.port);
}
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);
}
static int __ip4_tos(socket_t *s, unsigned int tos) {
unsigned char ctos;
ctos = tos;
setsockopt(s->fd, IPPROTO_IP, IP_TOS, &ctos, sizeof(ctos));
return 0;
}
static int __ip6_tos(socket_t *s, unsigned int tos) {
setsockopt(s->fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos));
return 0;
}
static void __ip4_endpoint2kernel(struct re_address *ra, const endpoint_t *ep) {
ZERO(*ra);
ra->family = AF_INET;
ra->u.ipv4 = ep->address.u.ipv4.s_addr;
ra->port = ep->port;
}
static void __ip6_endpoint2kernel(struct re_address *ra, const endpoint_t *ep) {
ZERO(*ra);
ra->family = AF_INET6;
memcpy(ra->u.ipv6, &ep->address.u.ipv6, sizeof(ra->u.ipv6));
ra->port = ep->port;
}
void kernel2endpoint(endpoint_t *ep, const struct re_address *ra) {
ZERO(*ep);
if (ra->family == AF_INET)
ep->address.family = __get_socket_family_enum(SF_IP4);
else if (ra->family == AF_INET6)
ep->address.family = __get_socket_family_enum(SF_IP6);
else
abort();
ep->port = ra->port;
ep->address.family->kernel2endpoint(ep, ra);
}
static void __ip4_kernel2endpoint(endpoint_t *ep, const struct re_address *ra) {
ep->address.u.ipv4.s_addr = ra->u.ipv4;
}
static void __ip6_kernel2endpoint(endpoint_t *ep, const struct re_address *ra) {
memcpy(&ep->address.u.ipv6, ra->u.ipv6, sizeof(ep->address.u.ipv6));
}
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, 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) {
__C_DBG("socket() syscall fail, fd=%d", r->fd);
return -1;
} else {
__C_DBG("socket() syscall success, fd=%d", r->fd);
}
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)) {
__C_DBG("open socket fail, fd=%d", r->fd);
return -1;
}
nonblock(r->fd);
reuseaddr(r->fd);
if (port > 0xffff) {
__C_DBG("open socket fail, port=%d > 0xfffffd", port);
goto fail;
}
if (fam->bind(r, port, sa)) {
__C_DBG("open socket fail, fd=%d, port=%d", r->fd, port);
goto fail;
}
r->local.port = port;
r->local.address = *sa;
__C_DBG("open socket success, fd=%d, port=%d", r->fd, port);
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;
}
int close_socket(socket_t *r) {
if (!r || r->fd == -1) {
__C_DBG("close() syscall not called, fd=%d", r->fd);
return -1;
}
if (close(r->fd) != 0) {
__C_DBG("close() syscall fail, fd=%d", r->fd);
return -1;
}
__C_DBG("close() syscall success, fd=%d", r->fd);
r->fd = -1;
ZERO(r->local);
ZERO(r->remote);
return 0;
}
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;
}

+ 224
- 0
daemon/socket.h View File

@ -0,0 +1,224 @@
#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;
struct re_address;
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" */
const char *unspec_string; /* 0.0.0.0 or :: */
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 *);
int (*tos)(socket_t *, unsigned int);
void (*endpoint2kernel)(struct re_address *, const endpoint_t *);
void (*kernel2endpoint)(endpoint_t *, const struct re_address *);
};
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)
INLINE ssize_t socket_sendiov(socket_t *s, const struct iovec *v, unsigned int len, const endpoint_t *dst) {
struct msghdr mh;
ZERO(mh);
mh.msg_iov = (void *) v;
mh.msg_iovlen = len;
return socket_sendmsg(s, &mh, dst);
}
/* 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);
int 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 *);
void kernel2endpoint(endpoint_t *ep, const struct re_address *ra);
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);
}
INLINE int ipv46_any_convert(endpoint_t *ep) {
if (ep->address.family->af != AF_INET)
return 0;
if (!is_addr_unspecified(&ep->address))
return 0;
ep->address.family = __get_socket_family_enum(SF_IP6);
ZERO(ep->address.u.ipv6);
return 1;
}
socktype_t *get_socket_type(const str *s);
#endif

+ 13
- 0
daemon/str.h View File

@ -65,6 +65,8 @@ INLINE void str_swap(str *a, str *b);
INLINE int str_to_i(str *s, int def);
/* parses a string uinto an int, returns default if conversion fails */
INLINE uint str_to_ui(str *s, int def);
/* extracts the first/next token into "new_token" and modifies "ori_and_remainer" in place */
INLINE int str_token(str *new_token, str *ori_and_remainder, int sep);
/* asprintf() analogs */
#define str_sprintf(fmt, a...) __str_sprintf(STR_MALLOC_PADDING fmt, a)
@ -278,4 +280,15 @@ INLINE unsigned int str_to_ui(str *s, int def) {
return ret;
}
// XXX use this for sdp.c token extraction
INLINE int str_token(str *new_token, str *ori_and_remainder, int sep) {
*new_token = *ori_and_remainder;
if (!str_chr_str(ori_and_remainder, ori_and_remainder, sep))
return -1;
new_token->len = ori_and_remainder->s - new_token->s;
if (str_shift(ori_and_remainder, 1))
return -1;
return 0;
}
#endif

+ 64
- 74
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,17 +231,11 @@ out:
return uc ? -1 : 0;
}
static void output_init(struct msghdr *mh, struct iovec *iov, struct sockaddr_in6 *sin,
struct header *hdr, unsigned short code, u_int32_t *transaction,
unsigned char *buf, int buflen)
static void output_init(struct msghdr *mh, struct iovec *iov,
struct header *hdr, unsigned short code, u_int32_t *transaction)
{
ZERO(*mh);
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;
@ -293,13 +290,8 @@ static void __output_finish(struct msghdr *mh) {
hdr = mh->msg_iov->iov_base;
hdr->msg_len = htons(hdr->msg_len);
}
//static void output_finish_ps(struct msghdr *mh, struct packet_stream *ps) {
// __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) {
__output_finish(mh);
msg_mh_src(src, mh);
}
static void fingerprint(struct msghdr *mh, struct fingerprint *fp) {
@ -352,7 +344,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 stream_fd *sfd, const endpoint_t *sin,
struct header *req,
int code, char *reason, int len, u_int16_t add_attr, void *attr_cont,
int attr_len)
@ -364,27 +356,26 @@ static void stun_error_len(struct packet_stream *ps, struct sockaddr_in6 *sin, s
struct generic aa;
struct msghdr mh;
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);
ec.codes = htonl(((code / 100) << 8) | (code % 100));
output_add_data(&mh, &ec, STUN_ERROR_CODE, reason, len);
if (attr_cont)
output_add_data(&mh, &aa, add_attr, attr_cont, attr_len);
integrity(&mh, &mi, &ps->media->ice_agent->pwd[0]);
integrity(&mh, &mi, &sfd->stream->media->ice_agent->pwd[0]);
fingerprint(&mh, &fp);
output_finish_src(&mh, dst);
sendmsg(ps->sfd->fd.fd, &mh, 0);
output_finish_src(&mh);
socket_sendmsg(&sfd->socket, &mh, sin);
}
#define stun_error(ps, sin, dst, req, code, reason) \
stun_error_len(ps, sin, dst, req, code, reason "\0\0\0", strlen(reason), \
#define stun_error(sfd, sin, req, code, reason) \
stun_error_len(sfd, sin, req, code, reason "\0\0\0", strlen(reason), \
0, NULL, 0)
#define stun_error_attrs(ps, sin, dst, req, code, reason, type, content, len) \
stun_error_len(ps, sin, dst, req, code, reason "\0\0\0", strlen(reason), \
#define stun_error_attrs(sfd, sin, req, code, reason, type, content, len) \
stun_error_len(sfd, sin, req, code, reason "\0\0\0", strlen(reason), \
type, content, len)
@ -434,11 +425,11 @@ static int check_auth(str *msg, struct stun_attrs *attrs, struct call_media *med
lenX = htons((attrs->msg_integrity_attr - msg->s) - 20 + 24);
iov[0].iov_base = msg->s;
iov[0].iov_len = OFFSET_OF(struct header, msg_len);
iov[0].iov_len = G_STRUCT_OFFSET(struct header, msg_len);
iov[1].iov_base = &lenX;
iov[1].iov_len = sizeof(lenX);
iov[2].iov_base = msg->s + OFFSET_OF(struct header, cookie);
iov[2].iov_len = ntohs(lenX) + - 24 + 20 - OFFSET_OF(struct header, cookie);
iov[2].iov_base = msg->s + G_STRUCT_OFFSET(struct header, cookie);
iov[2].iov_len = ntohs(lenX) + - 24 + 20 - G_STRUCT_OFFSET(struct header, cookie);
__integrity(iov, G_N_ELEMENTS(iov), &ag->pwd[dst], digest);
@ -446,8 +437,8 @@ 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)
static int stun_binding_success(struct stream_fd *sfd, struct header *req, struct stun_attrs *attrs,
const endpoint_t *sin)
{
struct header hdr;
struct xor_mapped_address xma;
@ -455,30 +446,29 @@ static int stun_binding_success(struct packet_stream *ps, struct header *req, st
struct fingerprint fp;
struct msghdr mh;
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);
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);
}
integrity(&mh, &mi, &ps->media->ice_agent->pwd[1]);
integrity(&mh, &mi, &sfd->stream->media->ice_agent->pwd[1]);
fingerprint(&mh, &fp);
output_finish_src(&mh, dst);
sendmsg(ps->sfd->fd.fd, &mh, 0);
output_finish_src(&mh);
socket_sendmsg(&sfd->socket, &mh, sin);
return 0;
}
@ -493,36 +483,36 @@ 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 stream_fd *sfd, const endpoint_t *sin,
struct header *req, struct stun_attrs *attrs)
{
int ret;
ret = ice_request(ps, sin, dst, attrs);
ret = ice_request(sfd, sin, attrs);
if (ret == -2) {
ilog(LOG_DEBUG, "ICE role conflict detected");
stun_error(ps, sin, dst, req, 487, "Role conflict");
stun_error(sfd, sin, req, 487, "Role conflict");
return 0;
}
if (ret < 0)
return -1;
ilog(LOG_DEBUG, "Successful STUN binding request" SLF, SLP);
stun_binding_success(ps, req, attrs, sin, dst);
stun_binding_success(sfd, req, attrs, 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 stream_fd *sfd, const endpoint_t *sin,
struct header *req, struct stun_attrs *attrs)
{
return ice_response(ps, sin, dst, attrs, req->transaction);
return ice_response(sfd, sin, 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 stream_fd *sfd, const endpoint_t *sin,
struct header *req, struct stun_attrs *attrs)
{
return ice_response(ps, sin, dst, attrs, req->transaction);
return ice_response(sfd, sin, attrs, req->transaction);
}
@ -533,7 +523,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 stream_fd *sfd, const endpoint_t *sin) {
struct header *req = (void *) b->s;
int msglen, method, class;
str attr_str;
@ -541,6 +531,7 @@ int stun(str *b, struct packet_stream *ps, struct sockaddr_in6 *sin, struct in6_
u_int16_t unknowns[UNKNOWNS_COUNT];
const char *err;
int dst_idx, src_idx;
struct packet_stream *ps = sfd->stream;
msglen = ntohs(req->msg_len);
err = "message-length mismatch";
@ -564,7 +555,7 @@ int stun(str *b, struct packet_stream *ps, struct sockaddr_in6 *sin, struct in6_
goto ignore;
ilog(LOG_WARNING, "STUN packet contained unknown "
"\"comprehension required\" attribute(s)" SLF, SLP);
stun_error_attrs(ps, sin, dst, req, 420, "Unknown attribute",
stun_error_attrs(sfd, sin, req, 420, "Unknown attribute",
STUN_UNKNOWN_ATTRIBUTES, unknowns,
u_int16_t_arr_len(unknowns) * 2);
return 0;
@ -597,11 +588,11 @@ int stun(str *b, struct packet_stream *ps, struct sockaddr_in6 *sin, struct in6_
switch (class) {
case STUN_CLASS_REQUEST:
return __stun_request(ps, sin, dst, req, &attrs);
return __stun_request(sfd, sin, req, &attrs);
case STUN_CLASS_SUCCESS:
return __stun_success(ps, sin, dst, req, &attrs);
return __stun_success(sfd, sin, req, &attrs);
case STUN_CLASS_ERROR:
return __stun_error(ps, sin, dst, req, &attrs);
return __stun_error(sfd, sin, req, &attrs);
default:
return -1;
}
@ -609,25 +600,24 @@ int stun(str *b, struct packet_stream *ps, struct sockaddr_in6 *sin, struct in6_
bad_req:
ilog(LOG_NOTICE, "Received invalid STUN packet" SLF ": %s", SLP, err);
stun_error(ps, sin, dst, req, 400, "Bad request");
stun_error(sfd, sin, req, 400, "Bad request");
return 0;
unauth:
ilog(LOG_NOTICE, "STUN authentication mismatch" SLF, SLP);
stun_error(ps, sin, dst, req, 401, "Unauthorized");
stun_error(sfd, sin, req, 401, "Unauthorized");
return 0;
ignore:
ilog(LOG_NOTICE, "Not handling potential STUN packet" SLF ": %s", SLP, err);
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)
socket_t *sock, int to_use)
{
struct header hdr;
struct msghdr mh;
struct iovec iov[8]; /* hdr, username x2, ice_controlled/ing, priority, uc, fp, mi */
unsigned char buf[256];
char username_buf[256];
int i;
struct generic un_attr;
@ -637,7 +627,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);
i = snprintf(username_buf, sizeof(username_buf), STR_FORMAT":"STR_FORMAT,
STR_FMT(&ufrags[0]), STR_FMT(&ufrags[1]));
@ -657,8 +647,8 @@ int stun_binding_request(struct sockaddr_in6 *dst, u_int32_t transaction[3], str
integrity(&mh, &mi, pwd);
fingerprint(&mh, &fp);
output_finish_src(&mh, src);
sendmsg(fd, &mh, 0);
output_finish_src(&mh);
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 stream_fd *, const endpoint_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);
socket_t *, int);
#endif

+ 18
- 23
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);
cb->func(cb->p, &str, &sin, addr, ul);
}
}
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, 1);
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;


+ 6
- 3
daemon/udp_listener.h View File

@ -4,18 +4,21 @@
#include <netinet/in.h>
#include "poller.h"
#include "str.h"
#include "socket.h"
struct poller;
struct obj;
struct udp_listener;
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 *);
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