From e381e107ecc01e9193571e636af36b2cc5f17708 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 30 Jun 2014 10:23:38 -0400 Subject: [PATCH 1/2] configurable per-call TOS value --- daemon/call.c | 70 +++++++++++++++++++++++++++++++--------- daemon/call.h | 5 +-- daemon/call_interfaces.c | 1 + daemon/main.c | 4 +-- daemon/sdp.h | 1 + 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 765221f82..93e434895 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -351,7 +351,7 @@ void kernelize(struct packet_stream *stream) { mutex_lock(&sink->out_lock); mpt.target_port = stream->sfd->fd.localport; - mpt.tos = cm->conf.tos; + mpt.tos = call->tos; mpt.rtcp_mux = MEDIA_ISSET(stream->media, RTCP_MUX); mpt.dtls = MEDIA_ISSET(stream->media, DTLS); mpt.stun = PS_ISSET(stream, STUN); @@ -1184,10 +1184,21 @@ fail: -static int get_port6(struct udp_fd *r, u_int16_t p, struct callmaster *m) { +static void __set_tos(int fd, const struct call *c) { + int tos; + + setsockopt(fd, IPPROTO_IP, IP_TOS, &c->tos, sizeof(c->tos)); +#ifdef IPV6_TCLASS + tos = c->tos; + setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); +#else +#warning "Will not set IPv6 traffic class" +#endif +} + +static int get_port6(struct udp_fd *r, u_int16_t p, const struct call *c) { int fd; struct sockaddr_in6 sin; - int tos; fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd < 0) @@ -1196,15 +1207,7 @@ static int get_port6(struct udp_fd *r, u_int16_t p, struct callmaster *m) { nonblock(fd); reuseaddr(fd); ipv6only(fd, 0); - if (m->conf.tos) - setsockopt(fd, IPPROTO_IP, IP_TOS, &m->conf.tos, sizeof(m->conf.tos)); -#ifdef IPV6_TCLASS - tos = m->conf.tos; - if (tos) - setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); -#else -#warning "Will not set IPv6 traffic class" -#endif + __set_tos(fd, c); ZERO(sin); sin.sin6_family = AF_INET6; @@ -1221,8 +1224,9 @@ fail: return -1; } -static int get_port(struct udp_fd *r, u_int16_t p, struct callmaster *m) { +static int get_port(struct udp_fd *r, u_int16_t p, const struct call *c) { int ret; + struct callmaster *m = c->callmaster; assert(r->fd == -1); @@ -1234,7 +1238,7 @@ static int get_port(struct udp_fd *r, u_int16_t p, struct callmaster *m) { bit_array_set(m->ports_used, p); mutex_unlock(&m->portlock); - ret = get_port6(r, p, m); + ret = get_port6(r, p, c); if (ret) { mutex_lock(&m->portlock); @@ -1259,7 +1263,7 @@ static void release_port(struct udp_fd *r, struct callmaster *m) { r->localport = 0; } -int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_start_port, struct call *c) { +int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_start_port, const struct call *c) { int i, j, cycle = 0; struct udp_fd *it; u_int16_t port; @@ -1292,7 +1296,7 @@ int __get_consecutive_ports(struct udp_fd *array, int array_len, int wanted_star goto release_restart; } - if (get_port(it, port++, m)) + if (get_port(it, port++, c)) goto release_restart; } break; @@ -1805,6 +1809,37 @@ static void __unverify_fingerprint(struct call_media *m) { } } +static void __set_all_tos(struct call *c) { + GSList *l; + struct stream_fd *sfd; + + for (l = c->stream_fds; l; l = l->next) { + sfd = l->data; + __set_tos(sfd->fd.fd, c); + } +} + +static void __tos_change(struct call *call, const struct sdp_ng_flags *flags) { + unsigned char new_tos; + + /* Handle TOS= parameter. Negative value = no change, not present or too large = + * revert to default, otherwise set specified value. We only do it in an offer, but + * then for both directions. */ + if (flags->opmode != OP_OFFER || flags->tos < 0) + return; + + if (flags->tos > 255) + new_tos = call->callmaster->conf.default_tos; + else + new_tos = flags->tos; + + if (new_tos == call->tos) + return; + + call->tos = new_tos; + __set_all_tos(call); +} + /* called with call->master_lock held in W */ int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, const struct sdp_ng_flags *flags) @@ -1823,6 +1858,8 @@ int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, if (!other_ml) return -1; + __tos_change(monologue->call, flags); + ml_media = other_ml_media = NULL; for (media_iter = streams->head; media_iter; media_iter = media_iter->next) { @@ -2219,6 +2256,7 @@ static struct call *call_create(const str *callid, struct callmaster *m) { call_str_cpy(c, &c->callid, callid); c->created = poller_now; c->dtls_cert = dtls_cert(); + c->tos = m->conf.default_tos; return c; } diff --git a/daemon/call.h b/daemon/call.h index ffc18d8a5..99e8fb7fd 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -298,6 +298,7 @@ struct call { str callid; time_t created; time_t last_signal; + unsigned char tos; }; struct callmaster_config { @@ -313,7 +314,7 @@ struct callmaster_config { unsigned int silent_timeout; struct redis *redis; char *b2b_url; - unsigned char tos; + unsigned char default_tos; }; struct callmaster { @@ -373,7 +374,7 @@ void calls_dump_redis(struct callmaster *); struct call_monologue *__monologue_create(struct call *call); void __monologue_tag(struct call_monologue *ml, const str *tag); 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, struct call *c); +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); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index f7a44bb39..7cddb9333 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -541,6 +541,7 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu 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->tos = bencode_dictionary_get_integer(input, "TOS", 256); } static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m, diff --git a/daemon/main.c b/daemon/main.c index 15898ddd2..bcad4eaaa 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -251,7 +251,7 @@ static void options(int *argc, char ***argv) { { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46:]PORT" }, - { "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "TOS value to set on streams", "INT" }, + { "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "Default TOS value to set on streams", "INT" }, { "timeout", 'o', 0, G_OPTION_ARG_INT, &timeout, "RTP timeout", "SECS" }, { "silent-timeout",'s',0,G_OPTION_ARG_INT, &silent_timeout,"RTP timeout for muted", "SECS" }, { "pidfile", 'p', 0, G_OPTION_ARG_STRING, &pidfile, "Write PID to file", "FILE" }, @@ -476,7 +476,7 @@ no_kernel: mc.port_max = port_max; mc.timeout = timeout; mc.silent_timeout = silent_timeout; - mc.tos = tos; + mc.default_tos = tos; mc.b2b_url = b2b_url; ct = NULL; diff --git a/daemon/sdp.h b/daemon/sdp.h index 0098c741b..ccafaae39 100644 --- a/daemon/sdp.h +++ b/daemon/sdp.h @@ -18,6 +18,7 @@ struct sdp_ng_flags { struct in6_addr parsed_media_address; enum stream_direction directions[2]; int address_family; + int tos; int asymmetric:1, trust_address:1, replace_origin:1, From 68d94c699e42368e80aea454a7dcf7300d606556 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 1 Jul 2014 09:17:31 -0400 Subject: [PATCH 2/2] add --TOS to ng-client --- utils/ng-client | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/ng-client b/utils/ng-client index bac3c32d6..3dbaa5423 100755 --- a/utils/ng-client +++ b/utils/ng-client @@ -35,13 +35,14 @@ GetOptions( 'v|verbose' => \$options{'verbose'}, 'strict-source' => \$options{'strict source'}, 'media-handover' => \$options{'media handover'}, + 'TOS=i' => \$options{'TOS'}, ) or die; my $cmd = shift(@ARGV) or die; my %packet = (command => $cmd); -for my $x (split(',', 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family')) { +for my $x (split(',', 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,TOS')) { defined($options{$x}) and $packet{$x} = $options{$x}; } for my $x (split(',', 'trust address,symmetric,asymmetric,force,strict source,media handover')) {