diff --git a/daemon/call.c b/daemon/call.c index 2495b4d..93925de 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1581,6 +1581,29 @@ int call_stream_address(char *o, struct peer *p, enum stream_address_format form return call_stream_address6(o, p, format, len); } +int call_stream_address_alt(char *o, struct peer *p, enum stream_address_format format, int *len) { + struct callmaster *m; + struct peer *other; + + m = p->up->call->callmaster; + other = &p->up->peers[p->idx ^ 1]; + + if (other->desired_family == AF_INET) + return call_stream_address6(o, p, format, len); + if (other->desired_family == 0 && IN6_IS_ADDR_V4MAPPED(&other->rtps[0].peer.ip46)) + return call_stream_address6(o, p, format, len); + if (other->desired_family == 0 && is_addr_unspecified(&other->rtps[0].peer_advertised.ip46)) + return call_stream_address6(o, p, format, len); + if (is_addr_unspecified(&m->conf.ipv6)) + return call_stream_address6(o, p, format, len); + + return call_stream_address4(o, p, format, len); +} + +int callmaster_has_ipv6(struct callmaster *m) { + return is_addr_unspecified(&m->conf.ipv6) ? 0 : 1; +} + static int call_stream_address_gstring(GString *o, struct peer *p, enum stream_address_format format) { int len, ret; char buf[64]; /* 64 bytes ought to be enough for anybody */ @@ -2220,6 +2243,7 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, GQueue *streams, ben } } + /* XXX convert to a "desired-family" kinda thing instead */ diridx = 0; if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) { for (it = list->child; it && diridx < 2; it = it->sibling) { diff --git a/daemon/call.h b/daemon/call.h index 662c897..1413d8c 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -148,6 +148,7 @@ struct callmaster; struct callmaster *callmaster_new(struct poller *); void callmaster_config(struct callmaster *m, struct callmaster_config *c); void callmaster_exclude_port(struct callmaster *m, u_int16_t p); +int callmaster_has_ipv6(struct callmaster *); str *call_request_tcp(char **, struct callmaster *); @@ -173,6 +174,7 @@ struct callstream *callstream_new(struct call *ca, int num); void callstream_init(struct callstream *s, struct relays_cache *); void kernelize(struct callstream *c); int call_stream_address(char *o, struct peer *p, enum stream_address_format format, int *len); +int call_stream_address_alt(char *o, struct peer *p, enum stream_address_format format, int *len); void relays_cache_init(struct relays_cache *c); int relays_cache_want_ports(struct relays_cache *c, int portA, int portB, struct call *call); diff --git a/daemon/sdp.c b/daemon/sdp.c index fb6df9d..3bdd1b8 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -104,6 +104,8 @@ struct sdp_attribute { static const char ice_chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char ice_foundation[17]; static str ice_foundation_str; +static char ice_foundation_alt[17]; +static str ice_foundation_str_alt; @@ -733,7 +735,7 @@ warn: return 0; } -static int insert_ice_address(struct sdp_chopper *chop, struct sdp_ng_flags *flags, struct streamrelay *sr) { +static int insert_ice_address(struct sdp_chopper *chop, struct streamrelay *sr) { char buf[64]; int len; @@ -744,8 +746,19 @@ static int insert_ice_address(struct sdp_chopper *chop, struct sdp_ng_flags *fla return 0; } +static int insert_ice_address_alt(struct sdp_chopper *chop, struct streamrelay *sr) { + char buf[64]; + int len; + + call_stream_address_alt(buf, sr->up, 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, - struct streamrelay *sr, struct sdp_ng_flags *flags) + struct streamrelay *sr) { char buf[64]; int len; @@ -897,6 +910,44 @@ out: return prio; } +static void insert_candidates(struct sdp_chopper *chop, struct streamrelay *rtp, struct streamrelay *rtcp, + unsigned long priority, struct sdp_session *session, struct sdp_media *media) +{ + chopper_append_c(chop, "a=candidate:"); + chopper_append_str(chop, &ice_foundation_str); + chopper_append_printf(chop, " 1 UDP %lu ", priority); + insert_ice_address(chop, rtp); + chopper_append_c(chop, " typ host\r\n"); + + if (has_rtcp(session, media)) { + chopper_append_c(chop, "a=candidate:"); + chopper_append_str(chop, &ice_foundation_str); + chopper_append_printf(chop, " 2 UDP %lu ", priority - 1); + insert_ice_address(chop, rtcp); + chopper_append_c(chop, " typ host\r\n"); + } + +} + +static void insert_candidates_alt(struct sdp_chopper *chop, struct streamrelay *rtp, struct streamrelay *rtcp, + unsigned long priority, struct sdp_session *session, struct sdp_media *media) +{ + chopper_append_c(chop, "a=candidate:"); + chopper_append_str(chop, &ice_foundation_str_alt); + chopper_append_printf(chop, " 1 UDP %lu ", priority); + insert_ice_address_alt(chop, rtp); + chopper_append_c(chop, " typ host\r\n"); + + if (has_rtcp(session, media)) { + chopper_append_c(chop, "a=candidate:"); + chopper_append_str(chop, &ice_foundation_str_alt); + chopper_append_printf(chop, " 2 UDP %lu ", priority - 1); + insert_ice_address_alt(chop, rtcp); + chopper_append_c(chop, " typ host\r\n"); + } + +} + int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, enum call_opmode opmode, struct sdp_ng_flags *flags, GHashTable *streamhash) { @@ -917,11 +968,11 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, fill_relays(&rtp, &rtcp, m, off, NULL); if (session->origin.parsed && flags->replace_origin) { - if (replace_network_address(chop, &session->origin.address, rtp, flags)) + if (replace_network_address(chop, &session->origin.address, rtp)) goto error; } if (session->connection.parsed) { - if (replace_network_address(chop, &session->connection.address, rtp, flags)) + if (replace_network_address(chop, &session->connection.address, rtp)) goto error; } @@ -961,7 +1012,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, goto error; if (media->connection.parsed && flags->replace_sess_conn) { - if (replace_network_address(chop, &media->connection.address, rtp, flags)) + if (replace_network_address(chop, &media->connection.address, rtp)) goto error; } @@ -985,18 +1036,11 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, else priority = new_priority(media); - chopper_append_c(chop, "a=candidate:"); - chopper_append_str(chop, &ice_foundation_str); - chopper_append_printf(chop, " 1 UDP %lu ", priority); - insert_ice_address(chop, flags, rtp); - chopper_append_c(chop, " typ host\r\n"); - - if (has_rtcp(session, media)) { - chopper_append_c(chop, "a=candidate:"); - chopper_append_str(chop, &ice_foundation_str); - chopper_append_printf(chop, " 2 UDP %lu ", priority - 1); - insert_ice_address(chop, flags, rtcp); - chopper_append_c(chop, " typ host\r\n"); + insert_candidates(chop, rtp, rtcp, priority, session, media); + + if (callmaster_has_ipv6(rtp->up->up->call->callmaster)) { + priority -= 256; + insert_candidates_alt(chop, rtp, rtcp, priority, session, media); } } } @@ -1014,4 +1058,8 @@ void sdp_init() { random_string(ice_foundation, sizeof(ice_foundation) - 1); ice_foundation_str.s = ice_foundation; ice_foundation_str.len = sizeof(ice_foundation) - 1; + + random_string(ice_foundation_alt, sizeof(ice_foundation_alt) - 1); + ice_foundation_str_alt.s = ice_foundation_alt; + ice_foundation_str_alt.len = sizeof(ice_foundation_alt) - 1; }