static int streams_parse_func(char **a, void **ret, void *p) { struct stream_params *sp; u_int32_t ip; int *i; i = p; sp = g_slice_alloc0(sizeof(*sp)); SP_SET(sp, SEND); SP_SET(sp, RECV); sp->protocol = &transport_protocols[PROTO_RTP_AVP]; ip = inet_addr(a[0]); if (ip == -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; sp->rtcp_endpoint = sp->rtp_endpoint; sp->rtcp_endpoint.port++; if (!sp->rtp_endpoint.port && strcmp(a[1], "0")) goto fail; *ret = sp; return 0; fail: ilog(LOG_WARNING, "Failed to parse a media stream: %s:%s", a[0], a[1]); g_slice_free1(sizeof(*sp), sp); return -1; }
static int addr_parse_udp(struct stream_params *sp, char **out) { u_int32_t ip4; const char *cp; char c; int i; ZERO(*sp); SP_SET(sp, SEND); SP_SET(sp, RECV); 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) 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) goto fail; } else goto fail; sp->rtp_endpoint.port = atoi(out[RE_UDP_UL_PORT]); if (!sp->rtp_endpoint.port && strcmp(out[RE_UDP_UL_PORT], "0")) goto fail; if (out[RE_UDP_UL_FLAGS] && *out[RE_UDP_UL_FLAGS]) { i = 0; for (cp =out[RE_UDP_UL_FLAGS]; *cp && i < 2; cp++) { c = chrtoupper(*cp); if (c == 'E') str_init(&sp->direction[i++], "external"); else if (c == 'I') str_init(&sp->direction[i++], "internal"); } } if (out[RE_UDP_UL_NUM] && *out[RE_UDP_UL_NUM]) sp->index = atoi(out[RE_UDP_UL_NUM]); if (!sp->index) sp->index = 1; sp->consecutive_ports = 1; sp->rtcp_endpoint = sp->rtp_endpoint; sp->rtcp_endpoint.port++; return 0; fail: return -1; }
static void __sdp_ice(struct stream_params *sp, struct sdp_media *media) { struct sdp_attribute *attr; struct attribute_candidate *ac; struct ice_candidate *cand; GQueue *q; GList *ql; attr = attr_get_by_id_m_s(media, ATTR_ICE_UFRAG); if (!attr) return; sp->ice_ufrag = attr->value; SP_SET(sp, ICE); q = attr_list_get_by_id(&media->attributes, ATTR_CANDIDATE); if (!q) goto no_cand; for (ql = q->head; ql; ql = ql->next) { attr = ql->data; ac = &attr->u.candidate; if (!ac->parsed) continue; cand = g_slice_alloc(sizeof(*cand)); *cand = ac->cand_parsed; g_queue_push_tail(&sp->ice_candidates, cand); } no_cand: if ((attr = attr_get_by_id(&media->attributes, ATTR_ICE_OPTIONS))) { if (str_str(&attr->value, "trickle") >= 0) SP_SET(sp, TRICKLE_ICE); } else if (is_trickle_ice_address(&sp->rtp_endpoint)) SP_SET(sp, TRICKLE_ICE); if (attr_get_by_id(&media->attributes, ATTR_ICE_LITE)) SP_SET(sp, ICE_LITE); attr = attr_get_by_id_m_s(media, ATTR_ICE_PWD); if (attr) sp->ice_pwd = attr->value; }
/* XXX split this function up */ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *flags) { struct sdp_session *session; struct sdp_media *media; struct stream_params *sp; GList *l, *k; const char *errstr; int num; struct sdp_attribute *attr; num = 0; for (l = sessions->head; l; l = l->next) { session = l->data; for (k = session->media_streams.head; k; k = k->next) { media = k->data; sp = g_slice_alloc0(sizeof(*sp)); sp->index = ++num; errstr = "No address info found for stream"; if (fill_endpoint(&sp->rtp_endpoint, media, flags, NULL, media->port_num)) goto error; sp->consecutive_ports = media->port_count; sp->protocol = transport_protocol(&media->transport); sp->type = media->media_type; memcpy(sp->direction, flags->direction, sizeof(sp->direction)); sp->desired_family = flags->address_family; bf_set_clear(&sp->sp_flags, SP_FLAG_ASYMMETRIC, flags->asymmetric); bf_set_clear(&sp->sp_flags, SP_FLAG_STRICT_SOURCE, flags->strict_source); bf_set_clear(&sp->sp_flags, SP_FLAG_MEDIA_HANDOVER, flags->media_handover); errstr = "Invalid RTP payload types"; if (__rtp_payload_types(sp, media)) goto error; /* a=crypto */ attr = attr_get_by_id(&media->attributes, ATTR_CRYPTO); if (attr) { sp->crypto.crypto_suite = attr->u.crypto.crypto_suite; sp->crypto.mki_len = attr->u.crypto.mki_len; if (sp->crypto.mki_len) { sp->crypto.mki = malloc(sp->crypto.mki_len); memcpy(sp->crypto.mki, attr->u.crypto.mki, sp->crypto.mki_len); } sp->sdes_tag = attr->u.crypto.tag; assert(sizeof(sp->crypto.master_key) >= attr->u.crypto.master_key.len); assert(sizeof(sp->crypto.master_salt) >= attr->u.crypto.salt.len); memcpy(sp->crypto.master_key, attr->u.crypto.master_key.s, attr->u.crypto.master_key.len); memcpy(sp->crypto.master_salt, attr->u.crypto.salt.s, attr->u.crypto.salt.len); sp->crypto.session_params.unencrypted_srtp = attr->u.crypto.unencrypted_srtp; sp->crypto.session_params.unencrypted_srtcp = attr->u.crypto.unencrypted_srtcp; sp->crypto.session_params.unauthenticated_srtp = attr->u.crypto.unauthenticated_srtp; } /* a=sendrecv/sendonly/recvonly/inactive */ SP_SET(sp, SEND); SP_SET(sp, RECV); if (attr_get_by_id_m_s(media, ATTR_RECVONLY)) SP_CLEAR(sp, SEND); else if (attr_get_by_id_m_s(media, ATTR_SENDONLY)) SP_CLEAR(sp, RECV); else if (attr_get_by_id_m_s(media, ATTR_INACTIVE)) { SP_CLEAR(sp, RECV); SP_CLEAR(sp, SEND); } /* a=setup */ attr = attr_get_by_id_m_s(media, ATTR_SETUP); if (attr) { if (attr->u.setup.value == SETUP_ACTPASS || attr->u.setup.value == SETUP_ACTIVE) SP_SET(sp, SETUP_ACTIVE); if (attr->u.setup.value == SETUP_ACTPASS || attr->u.setup.value == SETUP_PASSIVE) SP_SET(sp, SETUP_PASSIVE); } /* a=fingerprint */ attr = attr_get_by_id_m_s(media, ATTR_FINGERPRINT); if (attr && attr->u.fingerprint.hash_func) { sp->fingerprint.hash_func = attr->u.fingerprint.hash_func; memcpy(sp->fingerprint.digest, attr->u.fingerprint.fingerprint, sp->fingerprint.hash_func->num_bytes); } __sdp_ice(sp, media); /* determine RTCP endpoint */ if (attr_get_by_id(&media->attributes, ATTR_RTCP_MUX)) { SP_SET(sp, RTCP_MUX); goto next; } if (media->port_count != 1) goto next; attr = attr_get_by_id(&media->attributes, ATTR_RTCP); if (!attr) { SP_SET(sp, IMPLICIT_RTCP); goto next; } if (attr->u.rtcp.port_num == sp->rtp_endpoint.port && !is_trickle_ice_address(&sp->rtp_endpoint)) { SP_SET(sp, RTCP_MUX); goto next; } errstr = "Invalid RTCP attribute"; if (fill_endpoint(&sp->rtcp_endpoint, media, flags, &attr->u.rtcp.address, attr->u.rtcp.port_num)) goto error; next: g_queue_push_tail(streams, sp); } } return 0; error: ilog(LOG_WARNING, "Failed to extract streams from SDP: %s", errstr); if (sp) g_slice_free1(sizeof(*sp), sp); return -1; }