diff --git a/daemon/call.c b/daemon/call.c index 38ae7a0fd..a248f3a3c 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2233,6 +2233,8 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, GQueue *streams, ben if (bencode_dictionary_get_str(input, "ICE", &s)) { if (!str_cmp(&s, "remove")) out->ice_remove = 1; + else if (!str_cmp(&s, "force")) + out->ice_force = 1; } } diff --git a/daemon/call.h b/daemon/call.h index f59c2e1bc..0a1980a5e 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -34,6 +34,7 @@ enum stream_address_format { SAF_TCP, SAF_UDP, SAF_NG, + SAF_ICE, }; enum stream_direction { DIR_UNKNOWN = 0, @@ -118,6 +119,9 @@ struct call { char redis_uuid[37]; time_t created; time_t lookup_done; + + str ice_ufrag[2]; + str ice_pwd; }; struct callmaster_config { diff --git a/daemon/sdp.c b/daemon/sdp.c index 64c3d123b..232cfa673 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -30,6 +30,7 @@ struct sdp_connection { }; struct sdp_session { + str s; struct sdp_origin origin; struct sdp_connection connection; GQueue attributes; @@ -37,6 +38,7 @@ struct sdp_session { }; struct sdp_media { + str s; str media_type; str port; str transport; @@ -59,6 +61,10 @@ struct sdp_attribute { +static const char ufrag_pwd_chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + + /* hack hack */ static inline int inet_pton_str(int af, str *src, void *dst) { char *s = src->s; @@ -179,6 +185,7 @@ int sdp_parse(str *body, GQueue *sessions) { struct sdp_media *media = NULL; const char *errstr; struct sdp_attribute *attribute; + str *adj_s; b = body->s; end = str_end(body); @@ -214,6 +221,7 @@ int sdp_parse(str *body, GQueue *sessions) { g_queue_init(&session->attributes); g_queue_push_tail(sessions, session); media = NULL; + session->s.s = b; break; @@ -234,6 +242,8 @@ int sdp_parse(str *body, GQueue *sessions) { if (parse_media(value, line_end, media)) goto error; g_queue_push_tail(&session->media_streams, media); + media->s.s = b; + break; case 'c': @@ -283,6 +293,9 @@ int sdp_parse(str *body, GQueue *sessions) { goto error; } + adj_s = media ? &media->s : &session->s; + adj_s->len = (next_line ? : end) - adj_s->s; + b = next_line; } @@ -389,6 +402,12 @@ static void chopper_append(struct sdp_chopper *c, const char *s, int len) { iov->iov_len = len; c->str_len += len; } +static inline void chopper_append_c(struct sdp_chopper *c, const char *s) { + chopper_append(c, s, strlen(s)); +} +static inline void chopper_append_str(struct sdp_chopper *c, const str *s) { + chopper_append(c, s->s, s->len); +} static void chopper_append_dup(struct sdp_chopper *c, const char *s, int len) { return chopper_append(c, g_string_chunk_insert_len(c->chunk, s, len), len); @@ -494,6 +513,29 @@ warn: return 0; } +static int insert_ice_address(struct sdp_chopper *chop, GList *m, int off, struct sdp_ng_flags *flags) { + struct callstream *cs; + struct peer *peer; + struct streamrelay *sr; + char buf[64]; + int len; + + cs = m->data; + peer = &cs->peers[off]; + sr = &peer->rtps[0]; + + if (!flags->trust_address && flags->received_from_family.len == 3 && flags->received_from_address.len) + chopper_append_str(chop, &flags->received_from_address); + else { + call_stream_address(buf, peer, SAF_ICE, &len); + chopper_append_dup(chop, buf, len); + } + + chopper_append_printf(chop, " %hu", sr->fd.localport); + + return 0; +} + static int replace_network_address(struct sdp_chopper *chop, struct network_address *address, GList *m, int off, struct sdp_ng_flags *flags) { struct callstream *cs; struct peer *peer; @@ -512,9 +554,9 @@ static int replace_network_address(struct sdp_chopper *chop, struct network_addr return -1; if (!flags->trust_address && flags->received_from_family.len == 3 && flags->received_from_address.len) { - chopper_append(chop, flags->received_from_family.s, flags->received_from_family.len); - chopper_append(chop, " ", 1); - chopper_append(chop, flags->received_from_address.s, flags->received_from_address.len); + chopper_append_str(chop, &flags->received_from_family); + chopper_append_c(chop, " "); + chopper_append_str(chop, &flags->received_from_address); } else { call_stream_address(buf, peer, SAF_NG, &len); @@ -581,6 +623,21 @@ strip: return 0; } +static void create_random_string(struct call *call, str *s, int len) { + char buf[30]; + char *p; + + assert(len < sizeof(buf)); + if (s->s) + return; + + p = buf; + while (len--) + *p++ = ufrag_pwd_chars[random() % strlen(ufrag_pwd_chars)]; + + call_str_cpy_len(call, s, buf, p - buf); +} + int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, enum call_opmode opmode, struct sdp_ng_flags *flags, GHashTable *streamhash) { @@ -605,11 +662,26 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, goto error; } - if (flags->ice_remove) { + /* XXX convert to a "process attributes" kinda function */ + if (flags->ice_remove || flags->ice_force) { if (remove_ice(chop, &session->attributes)) goto error; } + if (flags->ice_force) { + create_random_string(call, &call->ice_ufrag[0], 4); + create_random_string(call, &call->ice_ufrag[1], 4); + create_random_string(call, &call->ice_pwd, 20); + + copy_up_to_end_of(chop, &session->s); + chopper_append_c(chop, "a=ice-lite\r\na=ice-ufrag:"); + chopper_append_str(chop, &call->ice_ufrag[off]); + chopper_append_c(chop, "\r\na=ice-pwd:"); + chopper_append_str(chop, &call->ice_pwd); + chopper_append_c(chop, "\r\n"); + /* XXX handle RTCP attributes */ + } + for (k = session->media_streams.head; k; k = k->next) { media = k->data; @@ -634,11 +706,19 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, goto error; } - if (flags->ice_remove) { + /* XXX convert to a "process attributes" kinda function */ + if (flags->ice_remove || flags->ice_force) { if (remove_ice(chop, &media->attributes)) goto error; } + if (flags->ice_force) { + copy_up_to_end_of(chop, &media->s); + /* XXX insert proper priority */ + chopper_append_c(chop, "a=candidate:1 1 UDP 1 "); + insert_ice_address(chop, m, off, flags); + chopper_append_c(chop, " typ host\r\n"); + } } } diff --git a/daemon/sdp.h b/daemon/sdp.h index 7e05cc95b..eb5dedcbf 100644 --- a/daemon/sdp.h +++ b/daemon/sdp.h @@ -15,7 +15,8 @@ struct sdp_ng_flags { trust_address:1, replace_origin:1, replace_sess_conn:1, - ice_remove:1; + ice_remove:1, + ice_force:1; }; struct sdp_chopper {