|
|
|
|
@ -72,6 +72,7 @@ struct sdp_attribute {
|
|
|
|
|
enum {
|
|
|
|
|
ATTR_OTHER = 0,
|
|
|
|
|
ATTR_RTCP,
|
|
|
|
|
ATTR_ICE,
|
|
|
|
|
} attr;
|
|
|
|
|
|
|
|
|
|
union {
|
|
|
|
|
@ -261,6 +262,32 @@ static void parse_attribute(struct sdp_attribute *a) {
|
|
|
|
|
if (!str_cmp(&a->name, "rtcp"))
|
|
|
|
|
parse_attribute_rtcp(a);
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
if (!str_cmp(&a->name, "ice-pwd"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
if (!str_cmp(&a->name, "ice-lite"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
if (!str_cmp(&a->name, "candidate"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
else if (!str_cmp(&a->name, "ice-ufrag"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
if (!str_cmp(&a->name, "ice-options"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
break;
|
|
|
|
|
case 12:
|
|
|
|
|
if (!str_cmp(&a->name, "ice-mismatch"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
break;
|
|
|
|
|
case 17:
|
|
|
|
|
if (!str_cmp(&a->name, "remote-candidates"))
|
|
|
|
|
a->attr = ATTR_ICE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -413,13 +440,19 @@ void sdp_free(GQueue *sessions) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int fill_stream(struct stream_input *si, struct sdp_media *media, struct sdp_session *session, int offset) {
|
|
|
|
|
static int fill_stream_address(struct stream_input *si, struct sdp_media *media, struct sdp_session *session) {
|
|
|
|
|
if (media->connection.parsed)
|
|
|
|
|
si->stream.ip46 = media->connection.address.parsed;
|
|
|
|
|
else if (session->connection.parsed)
|
|
|
|
|
si->stream.ip46 = session->connection.address.parsed;
|
|
|
|
|
else
|
|
|
|
|
return -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int fill_stream(struct stream_input *si, struct sdp_media *media, struct sdp_session *session, int offset) {
|
|
|
|
|
if (fill_stream_address(si, media, session))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* we ignore the media type */
|
|
|
|
|
si->stream.port = (media->port_num + (offset * 2)) & 0xffff;
|
|
|
|
|
@ -427,6 +460,13 @@ static int fill_stream(struct stream_input *si, struct sdp_media *media, struct
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int fill_stream_rtcp(struct stream_input *si, struct sdp_media *media, struct sdp_session *session, int port) {
|
|
|
|
|
if (fill_stream_address(si, media, session))
|
|
|
|
|
return -1;
|
|
|
|
|
si->stream.port = port;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash) {
|
|
|
|
|
struct sdp_session *session;
|
|
|
|
|
struct sdp_media *media;
|
|
|
|
|
@ -466,10 +506,23 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash)
|
|
|
|
|
|
|
|
|
|
if (!si || media->port_count != 1)
|
|
|
|
|
continue;
|
|
|
|
|
str_init(&s, "rtcp");
|
|
|
|
|
str_init(&s, "rtcp"); /* XXX use the enum for hash instead? */
|
|
|
|
|
attr = g_hash_table_lookup(media->attributes.hash, &s);
|
|
|
|
|
if (!attr)
|
|
|
|
|
if (!attr || !attr->u.rtcp.port_num)
|
|
|
|
|
continue;
|
|
|
|
|
if (attr->u.rtcp.port_num == si->stream.port + 1)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
si->has_rtcp = 1;
|
|
|
|
|
|
|
|
|
|
si = g_slice_alloc0(sizeof(*si));
|
|
|
|
|
if (fill_stream_rtcp(si, media, session, attr->u.rtcp.port_num))
|
|
|
|
|
goto error;
|
|
|
|
|
si->stream.num = ++num;
|
|
|
|
|
si->consecutive_num = 1;
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert(streamhash, si, si);
|
|
|
|
|
g_queue_push_tail(streams, si);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -477,6 +530,8 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash)
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
mylog(LOG_WARNING, "Failed to extract streams from SDP: %s", errstr);
|
|
|
|
|
if (si)
|
|
|
|
|
g_slice_free1(sizeof(*si), si);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -608,21 +663,14 @@ warn:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int insert_ice_address(struct sdp_chopper *chop, GList *m, int off, struct sdp_ng_flags *flags, int streamoff) {
|
|
|
|
|
struct callstream *cs;
|
|
|
|
|
struct peer *peer;
|
|
|
|
|
struct streamrelay *sr;
|
|
|
|
|
static int insert_ice_address(struct sdp_chopper *chop, struct sdp_ng_flags *flags, struct streamrelay *sr) {
|
|
|
|
|
char buf[64];
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
cs = m->data;
|
|
|
|
|
peer = &cs->peers[off];
|
|
|
|
|
sr = &peer->rtps[streamoff];
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
call_stream_address(buf, sr->up, SAF_ICE, &len);
|
|
|
|
|
chopper_append_dup(chop, buf, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -631,7 +679,9 @@ static int insert_ice_address(struct sdp_chopper *chop, GList *m, int off, struc
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int replace_network_address(struct sdp_chopper *chop, struct network_address *address, GList *m, int off, struct sdp_ng_flags *flags) {
|
|
|
|
|
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;
|
|
|
|
|
char buf[64];
|
|
|
|
|
@ -670,39 +720,36 @@ void sdp_chopper_destroy(struct sdp_chopper *chop) {
|
|
|
|
|
g_slice_free1(sizeof(*chop), chop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int remove_ice(struct sdp_chopper *chop, struct sdp_attributes *attrs) {
|
|
|
|
|
struct sdp_attribute *attr;
|
|
|
|
|
static void random_string(char *buf, int len) {
|
|
|
|
|
while (len--)
|
|
|
|
|
*buf++ = ice_chars[random() % strlen(ice_chars)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void create_random_string(struct call *call, str *s, int len) {
|
|
|
|
|
char buf[30];
|
|
|
|
|
|
|
|
|
|
assert(len < sizeof(buf));
|
|
|
|
|
if (s->s)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
random_string(buf, len);
|
|
|
|
|
call_str_cpy_len(call, s, buf, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int process_session_attributes(struct sdp_chopper *chop, struct sdp_attributes *attrs, struct sdp_ng_flags *flags) {
|
|
|
|
|
GList *l;
|
|
|
|
|
struct sdp_attribute *attr;
|
|
|
|
|
|
|
|
|
|
for (l = attrs->list.head; l; l = l->next) {
|
|
|
|
|
attr = l->data;
|
|
|
|
|
|
|
|
|
|
switch (attr->name.len) {
|
|
|
|
|
case 7:
|
|
|
|
|
if (!str_cmp(&attr->name, "ice-pwd"))
|
|
|
|
|
goto strip;
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
if (!str_cmp(&attr->name, "ice-lite"))
|
|
|
|
|
goto strip;
|
|
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
if (!str_cmp(&attr->name, "candidate"))
|
|
|
|
|
goto strip;
|
|
|
|
|
if (!str_cmp(&attr->name, "ice-ufrag"))
|
|
|
|
|
goto strip;
|
|
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
if (!str_cmp(&attr->name, "ice-options"))
|
|
|
|
|
goto strip;
|
|
|
|
|
break;
|
|
|
|
|
case 12:
|
|
|
|
|
if (!str_cmp(&attr->name, "ice-mismatch"))
|
|
|
|
|
goto strip;
|
|
|
|
|
break;
|
|
|
|
|
case 17:
|
|
|
|
|
if (!str_cmp(&attr->name, "remote-candidates"))
|
|
|
|
|
goto strip;
|
|
|
|
|
switch (attr->attr) {
|
|
|
|
|
case ATTR_ICE:
|
|
|
|
|
if (!flags->ice_remove && !flags->ice_force)
|
|
|
|
|
break;
|
|
|
|
|
goto strip;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -718,20 +765,37 @@ strip:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void random_string(char *buf, int len) {
|
|
|
|
|
while (len--)
|
|
|
|
|
*buf++ = ice_chars[random() % strlen(ice_chars)];
|
|
|
|
|
}
|
|
|
|
|
static int process_media_attributes(struct sdp_chopper *chop, struct sdp_attributes *attrs, struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
GList *l;
|
|
|
|
|
struct sdp_attribute *attr;
|
|
|
|
|
|
|
|
|
|
static void create_random_string(struct call *call, str *s, int len) {
|
|
|
|
|
char buf[30];
|
|
|
|
|
for (l = attrs->list.head; l; l = l->next) {
|
|
|
|
|
attr = l->data;
|
|
|
|
|
|
|
|
|
|
assert(len < sizeof(buf));
|
|
|
|
|
if (s->s)
|
|
|
|
|
return;
|
|
|
|
|
switch (attr->attr) {
|
|
|
|
|
case ATTR_ICE:
|
|
|
|
|
if (!flags->ice_remove && !flags->ice_force)
|
|
|
|
|
break;
|
|
|
|
|
goto strip;
|
|
|
|
|
|
|
|
|
|
random_string(buf, len);
|
|
|
|
|
call_str_cpy_len(call, s, buf, len);
|
|
|
|
|
case ATTR_RTCP:
|
|
|
|
|
goto strip;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
strip:
|
|
|
|
|
if (copy_up_to(chop, &attr->full_line))
|
|
|
|
|
return -1;
|
|
|
|
|
if (skip_over(chop, &attr->full_line))
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
@ -742,6 +806,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
GList *l, *k, *m;
|
|
|
|
|
int off;
|
|
|
|
|
struct stream_input si, *sip;
|
|
|
|
|
struct streamrelay *rtp, *rtcp;
|
|
|
|
|
|
|
|
|
|
off = opmode;
|
|
|
|
|
m = call->callstreams->head;
|
|
|
|
|
@ -758,11 +823,8 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX convert to a "process attributes" kinda function */
|
|
|
|
|
if (flags->ice_remove || flags->ice_force) {
|
|
|
|
|
if (remove_ice(chop, &session->attributes))
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (process_session_attributes(chop, &session->attributes, flags))
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
if (flags->ice_force) {
|
|
|
|
|
create_random_string(call, &call->ice_ufrag[0], 4);
|
|
|
|
|
@ -775,7 +837,6 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
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) {
|
|
|
|
|
@ -787,6 +848,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
sip = g_hash_table_lookup(streamhash, &si);
|
|
|
|
|
if (!sip)
|
|
|
|
|
goto error;
|
|
|
|
|
/* XXX use a hash instead? must link input streams to output streams */
|
|
|
|
|
if (!m)
|
|
|
|
|
m = call->callstreams->head;
|
|
|
|
|
while (m && ((struct callstream *) m->data)->num < sip->stream.num)
|
|
|
|
|
@ -794,6 +856,12 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
while (m && ((struct callstream *) m->data)->num > sip->stream.num)
|
|
|
|
|
m = m->prev;
|
|
|
|
|
|
|
|
|
|
/* XXX use those in function calls exclusively */
|
|
|
|
|
rtp = &((struct callstream *) m->data)->peers[off].rtps[0];
|
|
|
|
|
rtcp = &((struct callstream *) m->data)->peers[off].rtps[1];
|
|
|
|
|
if (sip->has_rtcp && m->next)
|
|
|
|
|
rtcp = &((struct callstream *) m->next->data)->peers[off].rtps[0];
|
|
|
|
|
|
|
|
|
|
if (replace_media_port(chop, media, m, off))
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
@ -802,26 +870,28 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX convert to a "process attributes" kinda function */
|
|
|
|
|
if (flags->ice_remove || flags->ice_force) {
|
|
|
|
|
if (remove_ice(chop, &media->attributes))
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (process_media_attributes(chop, &media->attributes, flags))
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
copy_up_to_end_of(chop, &media->s);
|
|
|
|
|
|
|
|
|
|
/* XXX create exception for b=..:0 cases */
|
|
|
|
|
chopper_append_c(chop, "a=rtcp:");
|
|
|
|
|
chopper_append_printf(chop, "%hu", rtcp->fd.localport);
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
|
|
|
|
|
if (flags->ice_force) {
|
|
|
|
|
copy_up_to_end_of(chop, &media->s);
|
|
|
|
|
/* prio = (2^24) * 126 + (2^8) * 65535 + (256 - componentID) */
|
|
|
|
|
chopper_append_c(chop, "a=candidate:");
|
|
|
|
|
chopper_append_str(chop, &ice_foundation_str);
|
|
|
|
|
chopper_append_c(chop, " 1 UDP 2130706431 ");
|
|
|
|
|
insert_ice_address(chop, m, off, flags, 0);
|
|
|
|
|
insert_ice_address(chop, flags, rtp);
|
|
|
|
|
chopper_append_c(chop, " typ host\r\n");
|
|
|
|
|
chopper_append_c(chop, "a=candidate:");
|
|
|
|
|
chopper_append_str(chop, &ice_foundation_str);
|
|
|
|
|
chopper_append_c(chop, " 2 UDP 2130706430 ");
|
|
|
|
|
insert_ice_address(chop, m, off, flags, 1);
|
|
|
|
|
insert_ice_address(chop, flags, rtcp);
|
|
|
|
|
chopper_append_c(chop, " typ host\r\n");
|
|
|
|
|
/* XXX handle rtcp here too */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|