static int replace_consecutive_port_count(struct sdp_chopper *chop, struct sdp_media *media, struct packet_stream *ps, GList *j) { int cons; struct packet_stream *ps_n; if (media->port_count == 1 || !ps->sfd) return 0; for (cons = 1; cons < media->port_count; cons++) { j = j->next; if (!j) goto warn; ps_n = j->data; if (ps_n->sfd->fd.localport != ps->sfd->fd.localport + cons * 2) { warn: ilog(LOG_WARN, "Failed to handle consecutive ports"); break; } } chopper_append_printf(chop, "/%i", cons); return 0; }
static int insert_ice_address(struct sdp_chopper *chop, struct packet_stream *ps, struct interface_address *ifa) { char buf[64]; int len; call_stream_address46(buf, ps, SAF_ICE, &len, ifa); chopper_append_dup(chop, buf, len); chopper_append_printf(chop, " %hu", ps->sfd->fd.localport); return 0; }
static int insert_ice_address(struct sdp_chopper *chop, struct stream_fd *sfd) { char buf[64]; int len; call_stream_address46(buf, sfd->stream, SAF_ICE, &len, sfd->local_intf); chopper_append_dup(chop, buf, len); chopper_append_printf(chop, " %u", sfd->socket.local.port); return 0; }
static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp, struct sdp_ng_flags *flags, struct sdp_media *sdp_media) { const struct local_intf *ifa; struct call_media *media; struct ice_agent *ag; unsigned int type_pref, local_pref; enum ice_candidate_type cand_type; struct ice_candidate *cand; media = rtp->media; cand_type = ICT_HOST; if (flags->ice_force_relay) cand_type = ICT_RELAY; if (MEDIA_ISSET(media, PASSTHRU)) new_priority(sdp_media, cand_type, &type_pref, &local_pref); else { type_pref = ice_type_preference(cand_type); local_pref = -1; } ag = media->ice_agent; if (ag && AGENT_ISSET(ag, COMPLETED)) { ifa = rtp->selected_sfd->local_intf; insert_candidate(chop, rtp->selected_sfd, type_pref, ifa->unique_id, cand_type); if (rtcp) /* rtcp-mux only possible in answer */ insert_candidate(chop, rtcp->selected_sfd, type_pref, ifa->unique_id, cand_type); if (flags->opmode == OP_OFFER && AGENT_ISSET(ag, CONTROLLING)) { GQueue rc; GList *l; chopper_append_c(chop, "a=remote-candidates:"); ice_remote_candidates(&rc, ag); for (l = rc.head; l; l = l->next) { if (l != rc.head) chopper_append_c(chop, " "); cand = l->data; chopper_append_printf(chop, "%lu %s %u", cand->component_id, sockaddr_print_buf(&cand->endpoint.address), cand->endpoint.port); } chopper_append_c(chop, "\r\n"); g_queue_clear(&rc); } return; } insert_sfd_candidates(chop, rtp, type_pref, local_pref, cand_type); if (rtcp) /* rtcp-mux only possible in answer */ insert_sfd_candidates(chop, rtcp, type_pref, local_pref, cand_type); }
static int insert_raddr_rport(struct sdp_chopper *chop, struct packet_stream *ps, const struct local_intf *ifa) { char buf[64]; int len; chopper_append_c(chop, " raddr "); call_stream_address46(buf, ps, SAF_ICE, &len, ifa); chopper_append_dup(chop, buf, len); chopper_append_c(chop, " rport "); chopper_append_printf(chop, "%u", ps->selected_sfd->socket.local.port); return 0; }
static void insert_crypto(struct call_media *media, struct sdp_chopper *chop) { char b64_buf[((SRTP_MAX_MASTER_KEY_LEN + SRTP_MAX_MASTER_SALT_LEN) / 3 + 1) * 4 + 4]; char *p; int state = 0, save = 0, i; struct crypto_params *cp = &media->sdes_out.params; unsigned long long ull; if (!cp->crypto_suite || !MEDIA_ISSET(media, SDES) || MEDIA_ISSET(media, PASSTHRU)) return; p = b64_buf; p += g_base64_encode_step((unsigned char *) cp->master_key, cp->crypto_suite->master_key_len, 0, p, &state, &save); p += g_base64_encode_step((unsigned char *) cp->master_salt, cp->crypto_suite->master_salt_len, 0, p, &state, &save); p += g_base64_encode_close(0, p, &state, &save); chopper_append_c(chop, "a=crypto:"); chopper_append_printf(chop, "%u ", media->sdes_out.tag); chopper_append_c(chop, cp->crypto_suite->name); chopper_append_c(chop, " inline:"); chopper_append_dup(chop, b64_buf, p - b64_buf); if (cp->mki_len) { ull = 0; for (i = 0; i < cp->mki_len && i < sizeof(ull); i++) ull |= cp->mki[cp->mki_len - i - 1] << (i * 8); chopper_append_printf(chop, "|%llu:%u", ull, cp->mki_len); } if (cp->session_params.unencrypted_srtp) chopper_append_c(chop, " UNENCRYPTED_SRTP"); if (cp->session_params.unencrypted_srtcp) chopper_append_c(chop, " UNENCRYPTED_SRTCP"); if (cp->session_params.unauthenticated_srtp) chopper_append_c(chop, " UNAUTHENTICATED_SRTP"); chopper_append_c(chop, "\r\n"); }
static void insert_candidate(struct sdp_chopper *chop, struct packet_stream *ps, unsigned int component, unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type, struct interface_address *ifa) { unsigned long priority; priority = ice_priority_pref(type_pref, local_pref, component); chopper_append_c(chop, "a=candidate:"); chopper_append_str(chop, &ifa->ice_foundation); chopper_append_printf(chop, " %u UDP %lu ", component, priority); insert_ice_address(chop, ps, ifa); chopper_append_c(chop, " typ "); chopper_append_c(chop, ice_candidate_type_str(type)); /* raddr and rport are required for non-host candidates: rfc5245 section-15.1 */ if(type != ICT_HOST) insert_raddr_rport(chop, ps, ifa); chopper_append_c(chop, "\r\n"); }
static int replace_media_port(struct sdp_chopper *chop, struct sdp_media *media, struct packet_stream *ps) { str *port = &media->port; unsigned int p; if (!media->port_num) return 0; if (copy_up_to(chop, port)) return -1; p = ps->sfd ? ps->sfd->fd.localport : 0; chopper_append_printf(chop, "%u", p); if (skip_over(chop, port)) return -1; return 0; }
static void insert_candidate(struct sdp_chopper *chop, struct stream_fd *sfd, unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type) { unsigned long priority; struct packet_stream *ps = sfd->stream; const struct local_intf *ifa = sfd->local_intf; if (local_pref == -1) local_pref = ifa->unique_id; priority = ice_priority_pref(type_pref, local_pref, ps->component); chopper_append_c(chop, "a=candidate:"); chopper_append_str(chop, &ifa->ice_foundation); chopper_append_printf(chop, " %u UDP %lu ", ps->component, priority); insert_ice_address(chop, sfd); chopper_append_c(chop, " typ "); chopper_append_c(chop, ice_candidate_type_str(type)); /* raddr and rport are required for non-host candidates: rfc5245 section-15.1 */ if(type != ICT_HOST) insert_raddr_rport(chop, ps, ifa); chopper_append_c(chop, "\r\n"); }
/* called with call->master_lock held in W */ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologue *monologue, struct sdp_ng_flags *flags) { struct sdp_session *session; struct sdp_media *sdp_media; GList *l, *k, *m, *j; int media_index, sess_conn; struct call_media *call_media; struct packet_stream *ps, *ps_rtcp; m = monologue->medias.head; for (l = sessions->head; l; l = l->next) { session = l->data; if (!m) goto error; call_media = m->data; if (call_media->index != 1) goto error; j = call_media->streams.head; if (!j) goto error; ps = j->data; sess_conn = 0; if (flags->replace_sess_conn) sess_conn = 1; else { for (k = session->media_streams.head; k; k = k->next) { sdp_media = k->data; if (!sdp_media->connection.parsed) { sess_conn = 1; break; } } } if (session->origin.parsed && flags->replace_origin && !flags->ice_force_relay) { if (replace_network_address(chop, &session->origin.address, ps, flags)) goto error; } if (session->connection.parsed && sess_conn && !flags->ice_force_relay) { if (replace_network_address(chop, &session->connection.address, ps, flags)) goto error; } if (!MEDIA_ISSET(call_media, PASSTHRU)) { if (process_session_attributes(chop, &session->attributes, flags)) goto error; } media_index = 1; for (k = session->media_streams.head; k; k = k->next) { sdp_media = k->data; if (!m) goto error; call_media = m->data; if (call_media->index != media_index) goto error; j = call_media->streams.head; if (!j) goto error; ps = j->data; if (!flags->ice_force_relay) { if (replace_media_port(chop, sdp_media, ps)) goto error; if (replace_consecutive_port_count(chop, sdp_media, ps, j)) goto error; if (replace_transport_protocol(chop, sdp_media, call_media)) goto error; if (sdp_media->connection.parsed) { if (replace_network_address(chop, &sdp_media->connection.address, ps, flags)) goto error; } } if (process_media_attributes(chop, sdp_media, flags, call_media)) goto error; copy_up_to_end_of(chop, &sdp_media->s); ps_rtcp = NULL; if (ps->rtcp_sibling) { ps_rtcp = ps->rtcp_sibling; j = j->next; if (!j) goto error; assert(j->data == ps_rtcp); } if (!sdp_media->port_num || !ps->sfd) goto next; if (MEDIA_ARESET2(call_media, SEND, RECV)) chopper_append_c(chop, "a=sendrecv\r\n"); else if (MEDIA_ISSET(call_media, SEND)) chopper_append_c(chop, "a=sendonly\r\n"); else if (MEDIA_ISSET(call_media, RECV)) chopper_append_c(chop, "a=recvonly\r\n"); else chopper_append_c(chop, "a=inactive\r\n"); if (call_media->protocol && call_media->protocol->rtp) { if (MEDIA_ISSET(call_media, RTCP_MUX) && flags->opmode == OP_ANSWER) { chopper_append_c(chop, "a=rtcp:"); chopper_append_printf(chop, "%hu", ps->sfd->fd.localport); chopper_append_c(chop, "\r\na=rtcp-mux\r\n"); ps_rtcp = NULL; } else if (ps_rtcp && !flags->ice_force_relay) { chopper_append_c(chop, "a=rtcp:"); chopper_append_printf(chop, "%hu", ps_rtcp->sfd->fd.localport); if (!MEDIA_ISSET(call_media, RTCP_MUX)) chopper_append_c(chop, "\r\n"); else chopper_append_c(chop, "\r\na=rtcp-mux\r\n"); } } else ps_rtcp = NULL; insert_crypto(call_media, chop); insert_dtls(call_media, chop); if (MEDIA_ISSET(call_media, ICE) && call_media->ice_agent) { chopper_append_c(chop, "a=ice-ufrag:"); chopper_append_str(chop, &call_media->ice_agent->ufrag[1]); chopper_append_c(chop, "\r\na=ice-pwd:"); chopper_append_str(chop, &call_media->ice_agent->pwd[1]); chopper_append_c(chop, "\r\n"); } if (!flags->ice_remove) insert_candidates(chop, ps, ps_rtcp, flags, sdp_media); next: media_index++; m = m->next; } } copy_remainder(chop); return 0; error: ilog(LOG_ERROR, "Error rewriting SDP"); return -1; }
static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp, struct sdp_ng_flags *flags, struct sdp_media *sdp_media) { GList *l; struct interface_address *ifa; unsigned int pref; struct call_media *media; struct local_interface *lif; struct ice_agent *ag; unsigned int type_pref, local_pref; enum ice_candidate_type cand_type; struct ice_candidate *cand; media = rtp->media; cand_type = ICT_HOST; if (flags->ice_force_relay) cand_type = ICT_RELAY; if (MEDIA_ISSET(media, PASSTHRU)) new_priority(sdp_media, cand_type, &type_pref, &local_pref); else { type_pref = ice_type_preference(cand_type); local_pref = -1; } ag = media->ice_agent; lif = ag ? ag->local_interface : media->interface; if (ag && AGENT_ISSET(ag, COMPLETED)) { ifa = g_atomic_pointer_get(&media->local_address); insert_candidate(chop, rtp, 1, type_pref, ifa->preference, cand_type, ifa); if (rtcp) /* rtcp-mux only possible in answer */ insert_candidate(chop, rtcp, 2, type_pref, ifa->preference, cand_type, ifa); if (flags->opmode == OP_OFFER && AGENT_ISSET(ag, CONTROLLING)) { GQueue rc; GList *l; chopper_append_c(chop, "a=remote-candidates:"); ice_remote_candidates(&rc, ag); for (l = rc.head; l; l = l->next) { if (l != rc.head) chopper_append_c(chop, " "); cand = l->data; chopper_append_printf(chop, "%lu %s %u", cand->component_id, smart_ntop_buf(&cand->endpoint.ip46), cand->endpoint.port); } chopper_append_c(chop, "\r\n"); g_queue_clear(&rc); } return; } for (l = lif->list.head; l; l = l->next) { ifa = l->data; pref = (local_pref == -1) ? ifa->preference : local_pref; insert_candidate(chop, rtp, 1, type_pref, pref, cand_type, ifa); if (rtcp) /* rtcp-mux only possible in answer */ insert_candidate(chop, rtcp, 2, type_pref, pref, cand_type, ifa); if (local_pref != -1) local_pref++; } }