inline int rtsp_media_aggregate_control_enable(void *sdp) { const char* control; // rfc 2326 C.1.1 Control URL (p80) // If found at the session level, the attribute indicates the URL for aggregate control control = sdp_attribute_find(sdp, "control"); return (control && *control) ? 1 : 0; }
// rfc 2326 C.1.1 Control URL (p81) // look for a base URL in the following order: // 1. The RTSP Content-Base field // 2. The RTSP Content-Location field // 3. The RTSP request URL static int rtsp_get_session_uri(void *sdp, char* uri, size_t bytes, const char* requri, const char* baseuri, const char* location) { char path[256] = {0}; const char* control; // C.1.1 Control URL (p81) // If this attribute contains only an asterisk (*), then the URL is // treated as if it were an empty embedded URL, and thus inherits the entire base URL. control = sdp_attribute_find(sdp, "control"); if(!control || 0==*control || '*' == *control) control = ""; strncpy(uri, control, bytes-1); if(!isAbsoluteURL(uri) && baseuri && *baseuri) { if(*uri) { uri_join(path, sizeof(path), baseuri, uri); baseuri = path; } strncpy(uri, baseuri, bytes-1); } if(!isAbsoluteURL(uri) && location && *location) { if(*uri) { uri_join(path, sizeof(path), location, uri); location = path; } strncpy(uri, location, bytes-1); } if(!isAbsoluteURL(uri) && requri && *requri) { if(*uri) { uri_join(path, sizeof(path), requri, uri); requri = path; } strncpy(uri, requri, bytes-1); } return 0; }
/** Find a mapped attribute. * * A mapped attribute has form 'a=<name>:<pt> <value>' where pt is a RTP * payload type, integer in range 0..127. For example, "a=atmmap" [@RFC3108] * is a mapped attribute. Note that common mapped attributes, "a=rtpmap" and * "a=fmtp" are already parsed as list of #sdp_rtpmap_t in #sdp_media_t. * * @param a pointer to first attribute in the list * @param name name of the attribute * @param pt payload type number (must be 0..127) * @param return_result return value parameter for mapped attribute value * * @return Pointer to a matching attribute structure, or NULL. * * If a matching attribute is found, @a return_result will point to part of * the attribute after the payload type and whitespace. */ sdp_attribute_t *sdp_attribute_mapped_find(sdp_attribute_t const *a, char const *name, int pt, char **return_result) { char pt_value[4]; size_t pt_len; if (return_result) *return_result = NULL; if (0 > pt || pt > 127) return NULL; snprintf(pt_value, sizeof(pt_value), "%u", (unsigned)pt); pt_len = strlen(pt_value); for (; (a = sdp_attribute_find(a, name)); a = a->a_next) { char const *value = a->a_value; size_t wlen; if (strncmp(value, pt_value, pt_len)) continue; wlen = strspn(value + pt_len, " \t"); if (wlen == 0 || value[pt_len + wlen] == '\0') continue; if (return_result) *return_result = (char *)value + pt_len + wlen; return (sdp_attribute_t *)a; } return NULL; }
char *janus_sdp_anonymize(const char *sdp) { if(sdp == NULL) return NULL; sdp_session_t *anon = NULL; sdp_parser_t *parser = sdp_parse(home, sdp, strlen(sdp), 0); if(!(anon = sdp_session(parser))) { JANUS_LOG(LOG_ERR, "Error parsing/merging SDP: %s\n", sdp_parsing_error(parser)); sdp_parser_free(parser); return NULL; } /* c= */ if(anon->sdp_connection && anon->sdp_connection->c_address) { anon->sdp_connection->c_address = "1.1.1.1"; } /* a= */ if(anon->sdp_attributes) { /* These are attributes we handle ourselves, the plugins don't need them */ while(sdp_attribute_find(anon->sdp_attributes, "ice-ufrag")) sdp_attribute_remove(&anon->sdp_attributes, "ice-ufrag"); while(sdp_attribute_find(anon->sdp_attributes, "ice-pwd")) sdp_attribute_remove(&anon->sdp_attributes, "ice-pwd"); while(sdp_attribute_find(anon->sdp_attributes, "ice-options")) sdp_attribute_remove(&anon->sdp_attributes, "ice-options"); while(sdp_attribute_find(anon->sdp_attributes, "fingerprint")) sdp_attribute_remove(&anon->sdp_attributes, "fingerprint"); while(sdp_attribute_find(anon->sdp_attributes, "group")) sdp_attribute_remove(&anon->sdp_attributes, "group"); while(sdp_attribute_find(anon->sdp_attributes, "msid-semantic")) sdp_attribute_remove(&anon->sdp_attributes, "msid-semantic"); } /* m= */ if(anon->sdp_media) { int audio = 0, video = 0; #ifdef HAVE_SCTP int data = 0; #endif sdp_media_t *m = anon->sdp_media; while(m) { if(m->m_type == sdp_media_audio && m->m_port > 0) { audio++; m->m_port = audio == 1 ? 1 : 0; } else if(m->m_type == sdp_media_video && m->m_port > 0) { video++; m->m_port = video == 1 ? 1 : 0; #ifdef HAVE_SCTP } else if(m->m_type == sdp_media_application) { if(m->m_proto_name != NULL && !strcasecmp(m->m_proto_name, "DTLS/SCTP") && m->m_port != 0) { data++; m->m_port = data == 1 ? 1 : 0; } else { m->m_port = 0; } #endif } else { m->m_port = 0; } /* c= */ if(m->m_connections) { sdp_connection_t *c = m->m_connections; while(c) { if(c->c_address) { c->c_address = "1.1.1.1"; } c = c->c_next; } } /* a= */ if(m->m_attributes) { /* These are attributes we handle ourselves, the plugins don't need them */ while(sdp_attribute_find(m->m_attributes, "ice-ufrag")) sdp_attribute_remove(&m->m_attributes, "ice-ufrag"); while(sdp_attribute_find(m->m_attributes, "ice-pwd")) sdp_attribute_remove(&m->m_attributes, "ice-pwd"); while(sdp_attribute_find(m->m_attributes, "ice-options")) sdp_attribute_remove(&m->m_attributes, "ice-options"); while(sdp_attribute_find(m->m_attributes, "crypto")) sdp_attribute_remove(&m->m_attributes, "crypto"); while(sdp_attribute_find(m->m_attributes, "fingerprint")) sdp_attribute_remove(&m->m_attributes, "fingerprint"); while(sdp_attribute_find(m->m_attributes, "setup")) sdp_attribute_remove(&m->m_attributes, "setup"); while(sdp_attribute_find(m->m_attributes, "connection")) sdp_attribute_remove(&m->m_attributes, "connection"); while(sdp_attribute_find(m->m_attributes, "group")) sdp_attribute_remove(&m->m_attributes, "group"); while(sdp_attribute_find(m->m_attributes, "mid")) sdp_attribute_remove(&m->m_attributes, "mid"); while(sdp_attribute_find(m->m_attributes, "msid")) sdp_attribute_remove(&m->m_attributes, "msid"); while(sdp_attribute_find(m->m_attributes, "msid-semantic")) sdp_attribute_remove(&m->m_attributes, "msid-semantic"); while(sdp_attribute_find(m->m_attributes, "rtcp")) sdp_attribute_remove(&m->m_attributes, "rtcp"); while(sdp_attribute_find(m->m_attributes, "rtcp-mux")) sdp_attribute_remove(&m->m_attributes, "rtcp-mux"); while(sdp_attribute_find(m->m_attributes, "candidate")) sdp_attribute_remove(&m->m_attributes, "candidate"); while(sdp_attribute_find(m->m_attributes, "ssrc")) sdp_attribute_remove(&m->m_attributes, "ssrc"); while(sdp_attribute_find(m->m_attributes, "ssrc-group")) sdp_attribute_remove(&m->m_attributes, "ssrc-group"); while(sdp_attribute_find(m->m_attributes, "extmap")) /* TODO Actually implement RTP extensions */ sdp_attribute_remove(&m->m_attributes, "extmap"); while(sdp_attribute_find(m->m_attributes, "sctpmap")) sdp_attribute_remove(&m->m_attributes, "sctpmap"); } if(m->m_type != sdp_media_application && m->m_mode == sdp_sendrecv) { /* FIXME sendrecv hack: sofia-sdp doesn't print sendrecv, but we want it to */ sdp_attribute_t *fakedir = calloc(1, sizeof(sdp_attribute_t)); fakedir->a_size = sizeof(sdp_attribute_t); fakedir->a_name = g_strdup("jfmod"); fakedir->a_value = g_strdup("sr"); sdp_attribute_append(&m->m_attributes, fakedir); } m = m->m_next; } } char buf[BUFSIZE]; sdp_printer_t *printer = sdp_print(home, anon, buf, BUFSIZE, 0); if(sdp_message(printer)) { int retval = sdp_message_size(printer); sdp_printer_free(printer); sdp_parser_free(parser); /* FIXME Take care of the sendrecv hack, if needed */ char *replace = strstr(buf, "a=jfmod:sr"); while(replace != NULL) { memcpy(replace, "a=sendrecv", strlen("a=sendrecv")); replace++; replace = strstr(replace, "a=jfmod:sr"); } JANUS_LOG(LOG_VERB, " -------------------------------------------\n"); JANUS_LOG(LOG_VERB, " >> Anonymized (%zu --> %d bytes)\n", strlen(sdp), retval); JANUS_LOG(LOG_VERB, " -------------------------------------------\n"); JANUS_LOG(LOG_VERB, "%s\n", buf); return g_strdup(buf); } else { JANUS_LOG(LOG_ERR, "Error anonymizing SDP: %s\n", sdp_printing_error(printer)); sdp_printer_free(printer); sdp_parser_free(parser); return NULL; } }
char *janus_sdp_anonymize(const char *sdp) { if(sdp == NULL) return NULL; //~ su_home_t home[1] = { SU_HOME_INIT(home) }; sdp_session_t *anon = NULL; sdp_parser_t *parser = sdp_parse(home, sdp, strlen(sdp), 0); if(!(anon = sdp_session(parser))) { JANUS_DEBUG("Error parsing/merging SDP: %s\n", sdp_parsing_error(parser)); return NULL; } //~ /* o= */ //~ if(anon->sdp_origin && anon->sdp_origin->o_username) { //~ free(anon->sdp_origin->o_username); //~ anon->sdp_origin->o_username = strdup("JANUS"); //~ } /* c= */ if(anon->sdp_connection && anon->sdp_connection->c_address) { //~ free(anon->sdp_connection->c_address); anon->sdp_connection->c_address = strdup("1.1.1.1"); } /* a= */ if(anon->sdp_attributes) { /* FIXME These are attributes we handle ourselves, the plugins don't need them */ while(sdp_attribute_find(anon->sdp_attributes, "ice-ufrag")) sdp_attribute_remove(&anon->sdp_attributes, "ice-ufrag"); while(sdp_attribute_find(anon->sdp_attributes, "ice-pwd")) sdp_attribute_remove(&anon->sdp_attributes, "ice-pwd"); while(sdp_attribute_find(anon->sdp_attributes, "ice-options")) sdp_attribute_remove(&anon->sdp_attributes, "ice-options"); while(sdp_attribute_find(anon->sdp_attributes, "fingerprint")) sdp_attribute_remove(&anon->sdp_attributes, "fingerprint"); while(sdp_attribute_find(anon->sdp_attributes, "group")) sdp_attribute_remove(&anon->sdp_attributes, "group"); while(sdp_attribute_find(anon->sdp_attributes, "msid-semantic")) sdp_attribute_remove(&anon->sdp_attributes, "msid-semantic"); } /* m= */ int a_sendrecv = 0, v_sendrecv = 0; if(anon->sdp_media) { int audio = 0, video = 0; sdp_media_t *m = anon->sdp_media; while(m) { if(m->m_type == sdp_media_audio) { audio++; m->m_port = audio == 1 ? 1 : 0; } else if(m->m_type == sdp_media_video) { video++; m->m_port = audio == 1 ? 1 : 0; } else { m->m_port = 0; } /* c= */ if(m->m_connections) { sdp_connection_t *c = m->m_connections; while(c) { if(c->c_address) { //~ free(c->c_address); c->c_address = strdup("1.1.1.1"); } c = c->c_next; } } /* a= */ if(m->m_attributes) { /* FIXME These are attributes we handle ourselves, the plugins don't need them */ while(sdp_attribute_find(m->m_attributes, "ice-ufrag")) sdp_attribute_remove(&m->m_attributes, "ice-ufrag"); while(sdp_attribute_find(m->m_attributes, "ice-pwd")) sdp_attribute_remove(&m->m_attributes, "ice-pwd"); while(sdp_attribute_find(m->m_attributes, "ice-options")) sdp_attribute_remove(&m->m_attributes, "ice-options"); while(sdp_attribute_find(m->m_attributes, "crypto")) sdp_attribute_remove(&m->m_attributes, "crypto"); while(sdp_attribute_find(m->m_attributes, "fingerprint")) sdp_attribute_remove(&m->m_attributes, "fingerprint"); while(sdp_attribute_find(m->m_attributes, "setup")) sdp_attribute_remove(&m->m_attributes, "setup"); while(sdp_attribute_find(m->m_attributes, "connection")) sdp_attribute_remove(&m->m_attributes, "connection"); while(sdp_attribute_find(m->m_attributes, "group")) sdp_attribute_remove(&m->m_attributes, "group"); while(sdp_attribute_find(m->m_attributes, "msid-semantic")) sdp_attribute_remove(&m->m_attributes, "msid-semantic"); while(sdp_attribute_find(m->m_attributes, "rtcp")) sdp_attribute_remove(&m->m_attributes, "rtcp"); while(sdp_attribute_find(m->m_attributes, "rtcp-mux")) sdp_attribute_remove(&m->m_attributes, "rtcp-mux"); while(sdp_attribute_find(m->m_attributes, "candidate")) sdp_attribute_remove(&m->m_attributes, "candidate"); while(sdp_attribute_find(m->m_attributes, "ssrc")) sdp_attribute_remove(&m->m_attributes, "ssrc"); while(sdp_attribute_find(m->m_attributes, "extmap")) /* TODO Actually implement RTP extensions */ sdp_attribute_remove(&m->m_attributes, "extmap"); } /* FIXME sendrecv hack: sofia-sdp doesn't print sendrecv, but we want it to */ if(m->m_mode == sdp_sendrecv) { m->m_mode = sdp_inactive; if(m->m_type == sdp_media_audio) a_sendrecv = 1; else if(m->m_type == sdp_media_video) v_sendrecv = 1; } m = m->m_next; } } char buf[BUFSIZE]; sdp_printer_t *printer = sdp_print(home, anon, buf, BUFSIZE, 0); if(sdp_message(printer)) { int retval = sdp_message_size(printer); sdp_printer_free(printer); /* FIXME Take care of the sendrecv hack */ if(a_sendrecv || v_sendrecv) { char *replace = strstr(buf, "a=inactive"); while(replace != NULL) { memcpy(replace, "a=sendrecv", strlen("a=sendrecv")); replace++; replace = strstr(replace, "a=inactive"); } } JANUS_PRINT(" -------------------------------------------\n"); JANUS_PRINT(" >> Anonymized (%zu --> %d bytes)\n", strlen(sdp), retval); JANUS_PRINT(" -------------------------------------------\n"); JANUS_PRINT("%s\n", buf); return g_strdup(buf); } else { JANUS_DEBUG("Error anonymizing SDP: %s\n", sdp_printing_error(printer)); return NULL; } }