From 79f4f70de1a6014d53b245b8069c833ce943f943 Mon Sep 17 00:00:00 2001 From: Chris Hiszpanski Date: Fri, 23 Apr 2021 11:17:03 -0400 Subject: Update inline license blocks and expand tabs --- src/sdp.c | 1013 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 509 insertions(+), 504 deletions(-) (limited to 'src/sdp.c') diff --git a/src/sdp.c b/src/sdp.c index baa1ece..154088c 100644 --- a/src/sdp.c +++ b/src/sdp.c @@ -1,24 +1,27 @@ /** - * liburtc - * Copyright 2020 Chris Hiszpanski - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. + * Copyright (c) 2019-2021 Chris Hiszpanski. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. */ #include @@ -48,47 +51,47 @@ * \return 0 on success. Negative on error. */ static int sdp_parse_attr_group(struct sdp *sdp, char *val) { - char *id = val; + char *id = val; - val = strsep(&id, " "); + val = strsep(&id, " "); - if (0 == strcmp("BUNDLE", val)) { - for (int i = 0; id && i < SDP_MAX_BUNDLE_IDS; i++) { - strncpy(sdp->mid[i], strsep(&id, " "), SDP_MAX_BUNDLE_ID_SIZE); - } - } - return 0; + if (0 == strcmp("BUNDLE", val)) { + for (int i = 0; id && i < SDP_MAX_BUNDLE_IDS; i++) { + strncpy(sdp->mid[i], strsep(&id, " "), SDP_MAX_BUNDLE_ID_SIZE); + } + } + return 0; } static int sdp_parse_attr_msid_semantic(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } static int sdp_parse_attr_rtcp(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } static int sdp_parse_attr_ice_ufrag(struct sdp *sdp, const char *val) { - if (sdp->ufrag != strncpy(sdp->ufrag, val, sizeof(sdp->ufrag))) { - return -1; - } - return 0; + if (sdp->ufrag != strncpy(sdp->ufrag, val, sizeof(sdp->ufrag))) { + return -1; + } + return 0; } static int sdp_parse_attr_ice_password(struct sdp *sdp, const char *val) { - if (sdp->pwd != strncpy(sdp->pwd, val, sizeof(sdp->pwd))) { - return -1; - } - return 0; + if (sdp->pwd != strncpy(sdp->pwd, val, sizeof(sdp->pwd))) { + return -1; + } + return 0; } static int sdp_parse_attr_ice_options(struct sdp *sdp, const char *val) { - if (0 == strcmp("trickle", val)) { - sdp->ice_options.trickle = true; - } - return 0; + if (0 == strcmp("trickle", val)) { + sdp->ice_options.trickle = true; + } + return 0; } /** @@ -102,59 +105,59 @@ static int sdp_parse_attr_ice_options(struct sdp *sdp, const char *val) { * \return 0 on success. Negative on error. */ static int sdp_parse_attr_fingerprint(struct sdp *sdp, char *val) { - char *fingerprint = val; - - val = strsep(&fingerprint, " "); - - if (fingerprint) { - if (0 == strcmp("sha-256", val)) { - if (32 != sscanf(fingerprint, - "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:" - "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:" - "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:" - "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX", - &sdp->fingerprint.sha256[0], &sdp->fingerprint.sha256[1], - &sdp->fingerprint.sha256[2], &sdp->fingerprint.sha256[3], - &sdp->fingerprint.sha256[4], &sdp->fingerprint.sha256[5], - &sdp->fingerprint.sha256[6], &sdp->fingerprint.sha256[7], - &sdp->fingerprint.sha256[8], &sdp->fingerprint.sha256[9], - &sdp->fingerprint.sha256[10], &sdp->fingerprint.sha256[11], - &sdp->fingerprint.sha256[12], &sdp->fingerprint.sha256[13], - &sdp->fingerprint.sha256[14], &sdp->fingerprint.sha256[15], - &sdp->fingerprint.sha256[16], &sdp->fingerprint.sha256[17], - &sdp->fingerprint.sha256[18], &sdp->fingerprint.sha256[19], - &sdp->fingerprint.sha256[20], &sdp->fingerprint.sha256[21], - &sdp->fingerprint.sha256[22], &sdp->fingerprint.sha256[23], - &sdp->fingerprint.sha256[24], &sdp->fingerprint.sha256[25], - &sdp->fingerprint.sha256[26], &sdp->fingerprint.sha256[27], - &sdp->fingerprint.sha256[28], &sdp->fingerprint.sha256[29], - &sdp->fingerprint.sha256[30], &sdp->fingerprint.sha256[31] - )) { - return -URTC_ERR_SDP_MALFORMED; - } - } else { - return -URTC_ERR_SDP_UNSUPPORTED_FINGERPRINT_ALGO; - } - } else { - return -URTC_ERR_SDP_MALFORMED; - } - - return 0; + char *fingerprint = val; + + val = strsep(&fingerprint, " "); + + if (fingerprint) { + if (0 == strcmp("sha-256", val)) { + if (32 != sscanf(fingerprint, + "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:" + "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:" + "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:" + "%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX", + &sdp->fingerprint.sha256[0], &sdp->fingerprint.sha256[1], + &sdp->fingerprint.sha256[2], &sdp->fingerprint.sha256[3], + &sdp->fingerprint.sha256[4], &sdp->fingerprint.sha256[5], + &sdp->fingerprint.sha256[6], &sdp->fingerprint.sha256[7], + &sdp->fingerprint.sha256[8], &sdp->fingerprint.sha256[9], + &sdp->fingerprint.sha256[10], &sdp->fingerprint.sha256[11], + &sdp->fingerprint.sha256[12], &sdp->fingerprint.sha256[13], + &sdp->fingerprint.sha256[14], &sdp->fingerprint.sha256[15], + &sdp->fingerprint.sha256[16], &sdp->fingerprint.sha256[17], + &sdp->fingerprint.sha256[18], &sdp->fingerprint.sha256[19], + &sdp->fingerprint.sha256[20], &sdp->fingerprint.sha256[21], + &sdp->fingerprint.sha256[22], &sdp->fingerprint.sha256[23], + &sdp->fingerprint.sha256[24], &sdp->fingerprint.sha256[25], + &sdp->fingerprint.sha256[26], &sdp->fingerprint.sha256[27], + &sdp->fingerprint.sha256[28], &sdp->fingerprint.sha256[29], + &sdp->fingerprint.sha256[30], &sdp->fingerprint.sha256[31] + )) { + return -URTC_ERR_SDP_MALFORMED; + } + } else { + return -URTC_ERR_SDP_UNSUPPORTED_FINGERPRINT_ALGO; + } + } else { + return -URTC_ERR_SDP_MALFORMED; + } + + return 0; } static int sdp_parse_attr_setup(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } static int sdp_parse_attr_mid(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } static int sdp_parse_attr_extmap(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } /** @@ -170,36 +173,36 @@ static int sdp_parse_attr_extmap(struct sdp *sdp, const char *val) { * \return 0 on success. Negative on error. */ static int sdp_parse_attr_rtpmap(struct sdp *sdp, char *val) { - if (!val) return -URTC_ERR_SDP_MALFORMED; - - unsigned int pt; // payload type - char en[7]; // encoding name - unsigned int cr; // clock rate - - if (3 != sscanf(val, "%3d %6[a-zA-Z0-9]%*c%5d", &pt, en, &cr)) { - return -URTC_ERR_SDP_MALFORMED_ATTRIBUTE; - } - - if (0 == strcmp("H264", en)) { - for (int i = 0; i < sdp->video.count; i++) { - if (sdp->video.params[i].type == pt) { - sdp->video.params[i].clock = cr; - sdp->video.params[i].codec = SDP_CODEC_H264; - } - } - } - - return 0; + if (!val) return -URTC_ERR_SDP_MALFORMED; + + unsigned int pt; // payload type + char en[7]; // encoding name + unsigned int cr; // clock rate + + if (3 != sscanf(val, "%3d %6[a-zA-Z0-9]%*c%5d", &pt, en, &cr)) { + return -URTC_ERR_SDP_MALFORMED_ATTRIBUTE; + } + + if (0 == strcmp("H264", en)) { + for (int i = 0; i < sdp->video.count; i++) { + if (sdp->video.params[i].type == pt) { + sdp->video.params[i].clock = cr; + sdp->video.params[i].codec = SDP_CODEC_H264; + } + } + } + + return 0; } static int sdp_parse_attr_rtcp_feedback(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } static int sdp_parse_attr_fmtp(struct sdp *sdp, const char *val) { - /* not implemented */ - return 0; + /* not implemented */ + return 0; } /** @@ -211,54 +214,54 @@ static int sdp_parse_attr_fmtp(struct sdp *sdp, const char *val) { * \return 0 on success. Negative on error. */ static int sdp_parse_attribute(struct sdp *sdp, char *attr) { - char *value = attr; - - // Find colon separating attribute from value - attr = strsep(&value, ":"); - - if (value) { - if (0 == strcmp("group", attr)) { - return sdp_parse_attr_group(sdp, value); - } else if (0 == strcmp("msid-semantic", attr)) { - return sdp_parse_attr_msid_semantic(sdp, value); - } else if (0 == strcmp("rtcp", attr)) { - return sdp_parse_attr_rtcp(sdp, value); - } else if (0 == strcmp("ice-ufrag", attr)) { - return sdp_parse_attr_ice_ufrag(sdp, value); - } else if (0 == strcmp("ice-pwd", attr)) { - return sdp_parse_attr_ice_password(sdp, value); - } else if (0 == strcmp("ice-options", attr)) { - return sdp_parse_attr_ice_options(sdp, value); - } else if (0 == strcmp("fingerprint", attr)) { - return sdp_parse_attr_fingerprint(sdp, value); - } else if (0 == strcmp("setup", attr)) { - return sdp_parse_attr_setup(sdp, value); - } else if (0 == strcmp("mid", attr)) { - return sdp_parse_attr_mid(sdp, value); - } else if (0 == strcmp("extmap", attr)) { - return sdp_parse_attr_extmap(sdp, value); - } else if (0 == strcmp("rtpmap", attr)) { - return sdp_parse_attr_rtpmap(sdp, value); - } else if (0 == strcmp("rtcp-fb", attr)) { - return sdp_parse_attr_rtcp_feedback(sdp, value); - } else if (0 == strcmp("fmtp", attr)) { - return sdp_parse_attr_fmtp(sdp, value); - } - } else /* flag */ { - if (0 == strcmp("recvonly", attr)) { - sdp->mode = SDP_MODE_RECEIVE_ONLY; - } else if (0 == strcmp("sendonly", attr)) { - sdp->mode = SDP_MODE_SEND_ONLY; - } else if (0 == strcmp("sendrecv", attr)) { - sdp->mode = SDP_MODE_SEND_AND_RECEIVE; - } else if (0 == strcmp("rtcp-mux", attr)) { - sdp->rtcp_mux = true; - } else if (0 == strcmp("rtcp-rsize", attr)) { - sdp->rtcp_rsize = true; - } - } - - return 0; + char *value = attr; + + // Find colon separating attribute from value + attr = strsep(&value, ":"); + + if (value) { + if (0 == strcmp("group", attr)) { + return sdp_parse_attr_group(sdp, value); + } else if (0 == strcmp("msid-semantic", attr)) { + return sdp_parse_attr_msid_semantic(sdp, value); + } else if (0 == strcmp("rtcp", attr)) { + return sdp_parse_attr_rtcp(sdp, value); + } else if (0 == strcmp("ice-ufrag", attr)) { + return sdp_parse_attr_ice_ufrag(sdp, value); + } else if (0 == strcmp("ice-pwd", attr)) { + return sdp_parse_attr_ice_password(sdp, value); + } else if (0 == strcmp("ice-options", attr)) { + return sdp_parse_attr_ice_options(sdp, value); + } else if (0 == strcmp("fingerprint", attr)) { + return sdp_parse_attr_fingerprint(sdp, value); + } else if (0 == strcmp("setup", attr)) { + return sdp_parse_attr_setup(sdp, value); + } else if (0 == strcmp("mid", attr)) { + return sdp_parse_attr_mid(sdp, value); + } else if (0 == strcmp("extmap", attr)) { + return sdp_parse_attr_extmap(sdp, value); + } else if (0 == strcmp("rtpmap", attr)) { + return sdp_parse_attr_rtpmap(sdp, value); + } else if (0 == strcmp("rtcp-fb", attr)) { + return sdp_parse_attr_rtcp_feedback(sdp, value); + } else if (0 == strcmp("fmtp", attr)) { + return sdp_parse_attr_fmtp(sdp, value); + } + } else /* flag */ { + if (0 == strcmp("recvonly", attr)) { + sdp->mode = SDP_MODE_RECEIVE_ONLY; + } else if (0 == strcmp("sendonly", attr)) { + sdp->mode = SDP_MODE_SEND_ONLY; + } else if (0 == strcmp("sendrecv", attr)) { + sdp->mode = SDP_MODE_SEND_AND_RECEIVE; + } else if (0 == strcmp("rtcp-mux", attr)) { + sdp->rtcp_mux = true; + } else if (0 == strcmp("rtcp-rsize", attr)) { + sdp->rtcp_rsize = true; + } + } + + return 0; } /** @@ -277,58 +280,58 @@ static int sdp_parse_attribute(struct sdp *sdp, char *attr) { * \return 0 on success. Negative on error. */ static int sdp_parse_media_description(struct sdp *sdp, char *value) { - char *next = value; - - value = strsep(&next, " "); - - if (0 == strcmp("audio", value)) { - /* not implemented */ - } else if (0 == strcmp("video", value)) { - if (!next) return -URTC_ERR_SDP_MALFORMED_MEDIA; - - /* get port */ - value = strsep(&next, " "); - if (1 != sscanf(value, "%5hd", &sdp->video.port)) { - return -URTC_ERR_SDP_MALFORMED_MEDIA; - } - if (!next) return -URTC_ERR_SDP_MALFORMED_MEDIA; - - /* get protocol: only "UDP/TLS/RTP/SAVPF" supported */ - value = strsep(&next, " "); - if (0 != strcmp("UDP/TLS/RTP/SAVPF", value)) { - return -URTC_ERR_SDP_UNSUPPORTED_MEDIA_PROTOCOL; - } - if (!next) return -URTC_ERR_SDP_MALFORMED_MEDIA; - - /* get RTP payload types */ - sdp->video.count = 0; - for ( - value = strsep(&next, " "); - value && sdp->video.count < SDP_MAX_RTP_PAYLOAD_TYPES; - value = strsep(&next, " ") - ) { - unsigned int *v = &sdp->video.params[sdp->video.count].type; - if (1 != sscanf(value, "%3d", v)) { - return -URTC_ERR_SDP_MALFORMED_MEDIA; - } - sdp->video.count++; - } - - } else if (0 == strcmp("text", value)) { - /* ignore */ - } else if (0 == strcmp("message", value)) { - /* ignore */ - } else if (0 == strcmp("application", value)) { - /* ignore */ - } else { - return -URTC_ERR_SDP_UNSUPPORTED_MEDIA_TYPE; - } - - return 0; + char *next = value; + + value = strsep(&next, " "); + + if (0 == strcmp("audio", value)) { + /* not implemented */ + } else if (0 == strcmp("video", value)) { + if (!next) return -URTC_ERR_SDP_MALFORMED_MEDIA; + + /* get port */ + value = strsep(&next, " "); + if (1 != sscanf(value, "%5hd", &sdp->video.port)) { + return -URTC_ERR_SDP_MALFORMED_MEDIA; + } + if (!next) return -URTC_ERR_SDP_MALFORMED_MEDIA; + + /* get protocol: only "UDP/TLS/RTP/SAVPF" supported */ + value = strsep(&next, " "); + if (0 != strcmp("UDP/TLS/RTP/SAVPF", value)) { + return -URTC_ERR_SDP_UNSUPPORTED_MEDIA_PROTOCOL; + } + if (!next) return -URTC_ERR_SDP_MALFORMED_MEDIA; + + /* get RTP payload types */ + sdp->video.count = 0; + for ( + value = strsep(&next, " "); + value && sdp->video.count < SDP_MAX_RTP_PAYLOAD_TYPES; + value = strsep(&next, " ") + ) { + unsigned int *v = &sdp->video.params[sdp->video.count].type; + if (1 != sscanf(value, "%3d", v)) { + return -URTC_ERR_SDP_MALFORMED_MEDIA; + } + sdp->video.count++; + } + + } else if (0 == strcmp("text", value)) { + /* ignore */ + } else if (0 == strcmp("message", value)) { + /* ignore */ + } else if (0 == strcmp("application", value)) { + /* ignore */ + } else { + return -URTC_ERR_SDP_UNSUPPORTED_MEDIA_TYPE; + } + + return 0; } static int sdp_parse_connection_data(struct sdp *sdp, const char *value) { - return 0; + return 0; } /** @@ -345,12 +348,12 @@ static int sdp_parse_connection_data(struct sdp *sdp, const char *value) { * \return 0 on success. Negative on error. */ static int sdp_parse_version(struct sdp *sdp, const char *value) { - if (0 != strcmp("0", value)) { - return -URTC_ERR_SDP_MALFORMED_VERSION; - } - sdp->version = 0; + if (0 != strcmp("0", value)) { + return -URTC_ERR_SDP_MALFORMED_VERSION; + } + sdp->version = 0; - return 0; + return 0; } /** @@ -370,23 +373,23 @@ static int sdp_parse_version(struct sdp *sdp, const char *value) { * \return 0 on success. Negative on error. */ static int sdp_parse_origin(struct sdp *sdp, const char *value) { - if (3 != sscanf(value, - "%" TOSTRING(SDP_MAX_USERNAME_SIZE) "s " - "%" TOSTRING(SDP_MAX_SESSION_ID_SIZE) "[0-9] " - "%" TOSTRING(SDP_MAX_SESSION_VERSION_SIZE) "[0-9] " - "IN IP4 127.0.0.1", - sdp->username, - sdp->session_id, - sdp->session_version - )) { - return -URTC_ERR_SDP_MALFORMED_ORIGIN; - } - - return 0; + if (3 != sscanf(value, + "%" TOSTRING(SDP_MAX_USERNAME_SIZE) "s " + "%" TOSTRING(SDP_MAX_SESSION_ID_SIZE) "[0-9] " + "%" TOSTRING(SDP_MAX_SESSION_VERSION_SIZE) "[0-9] " + "IN IP4 127.0.0.1", + sdp->username, + sdp->session_id, + sdp->session_version + )) { + return -URTC_ERR_SDP_MALFORMED_ORIGIN; + } + + return 0; } static int sdp_parse_session_name(struct sdp *sdp, const char *value) { - return 0; + return 0; } /** @@ -402,14 +405,14 @@ static int sdp_parse_session_name(struct sdp *sdp, const char *value) { * \return 0 on success. Negative on error. */ static int sdp_parse_timing(struct sdp *sdp, const char *value) { - if (2 != sscanf(value, "%10lli %10lli", - (unsigned long long *)&sdp->start_time, - (unsigned long long *)&sdp->stop_time - )) { - return -URTC_ERR_SDP_MALFORMED_TIMING; - } - - return 0; + if (2 != sscanf(value, "%10lli %10lli", + (unsigned long long *)&sdp->start_time, + (unsigned long long *)&sdp->stop_time + )) { + return -URTC_ERR_SDP_MALFORMED_TIMING; + } + + return 0; } /** @@ -421,279 +424,281 @@ static int sdp_parse_timing(struct sdp *sdp, const char *value) { * \return 0 on success, negative on error. */ static int sdp_parse_line(struct sdp *sdp, char *line) { - if (!line) return -URTC_ERR_BAD_ARGUMENT; - if (0 == strlen(line)) return 0; - if (strlen(line) < 3) return -URTC_ERR_SDP_MALFORMED; - if ('=' != line[1]) return -URTC_ERR_SDP_MALFORMED; - - char type = line[0]; - char *value = line + 2; - - switch (type) { - case 'a': - return sdp_parse_attribute(sdp, value); - case 'c': - return sdp_parse_connection_data(sdp, value); - case 'o': - return sdp_parse_origin(sdp, value); - case 'm': - return sdp_parse_media_description(sdp, value); - case 's': - return sdp_parse_session_name(sdp, value); - case 't': - return sdp_parse_timing(sdp, value); - case 'v': - return sdp_parse_version(sdp, value); - default: - /* ignore unsupported types */ - return 0; - } + if (!line) return -URTC_ERR_BAD_ARGUMENT; + if (0 == strlen(line)) return 0; + if (strlen(line) < 3) return -URTC_ERR_SDP_MALFORMED; + if ('=' != line[1]) return -URTC_ERR_SDP_MALFORMED; + + char type = line[0]; + char *value = line + 2; + + switch (type) { + case 'a': + return sdp_parse_attribute(sdp, value); + case 'c': + return sdp_parse_connection_data(sdp, value); + case 'o': + return sdp_parse_origin(sdp, value); + case 'm': + return sdp_parse_media_description(sdp, value); + case 's': + return sdp_parse_session_name(sdp, value); + case 't': + return sdp_parse_timing(sdp, value); + case 'v': + return sdp_parse_version(sdp, value); + default: + /* ignore unsupported types */ + return 0; + } } int sdp_parse(struct sdp *dst, const char *str) { - if (!str) return -URTC_ERR_BAD_ARGUMENT; - if (!dst) return -URTC_ERR_BAD_ARGUMENT; - - err_t retval = 0; - - /* make a malleable copy of string for parser */ - char *copy = malloc(strlen(str)); - if (copy) { - strcpy(copy, str); - - for (char *in = copy, *line = strsep(&in, "\r\n"); in; line = strsep(&in, "\r\n")) { - retval = sdp_parse_line(dst, line); - if (retval != 0) { - log(ERROR, "sdp_parse_line returned %i for %s", retval, line); - break; - } - } - - free(copy); - } else { - return -URTC_ERR_INSUFFICIENT_MEMORY; - } - - return retval; + if (!str) return -URTC_ERR_BAD_ARGUMENT; + if (!dst) return -URTC_ERR_BAD_ARGUMENT; + + err_t retval = 0; + + /* make a malleable copy of string for parser */ + char *copy = malloc(strlen(str)); + if (copy) { + strcpy(copy, str); + + for (char *in = copy, *line = strsep(&in, "\r\n"); in; line = strsep(&in, "\r\n")) { + retval = sdp_parse_line(dst, line); + if (retval != 0) { + log(ERROR, "sdp_parse_line returned %i for %s", retval, line); + break; + } + } + + free(copy); + } else { + return -URTC_ERR_INSUFFICIENT_MEMORY; + } + + return retval; } int sdp_serialize(char *dst, size_t len, const struct sdp *src) { - int n; - - // sanity check - if (!dst) return -URTC_ERR_BAD_ARGUMENT; - if (!src) return -URTC_ERR_BAD_ARGUMENT; - - // write version - n = snprintf(dst, len, "v=%u\n", src->version); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write originator and session identifier - n = snprintf(dst, len, - "o=liburtc/0.0.0 %s %s IN IP4 127.0.0.1\n", - src->session_id, - src->session_version - ); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write session name - n = snprintf(dst, len, "s=%s\n", - 0 == strlen(src->session_name) ? " " : src->session_name); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write uri - n = snprintf(dst, len, "u=http://www.liburtc.org\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write time descriptor - n = snprintf(dst, len, "t=%" PRIu64 " %" PRIu64 "\n", - src->start_time, src->stop_time); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write session attribute - n = snprintf(dst, len, "a=group:BUNDLE"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - for (int i = 0; i < SDP_MAX_BUNDLE_IDS; i++) { - if (strlen(src->mid[i]) > 0) { - n = snprintf(dst, len, " %s", src->mid[i]); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - } - } - n = snprintf(dst, len, "\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write video media description - if (src->video.count > 0) { - n = snprintf( - dst, len, "m=video %hd UDP/TLS/RTP/SAVPF", src->video.port - ); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - for (int i = 0; i < src->video.count; i++) { - if (src->video.params[i].codec == SDP_CODEC_H264) { - n = snprintf(dst, len, " %d", src->video.params[i].type); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n > len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - } - } - n = snprintf(dst, len, "\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - } - - // TODO write rtcp attribute - - // write connection information (TODO IPv6) - n = snprintf(dst, len, "c=IN IP4 0.0.0.0\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write media attribute: ice ufrag - n = snprintf(dst, len, "a=ice-ufrag:%s\n", src->ufrag); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write media attribute: ice pwd - n = snprintf(dst, len, "a=ice-pwd:%s\n", src->pwd); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write media attribute: trickle ICE - if (src->ice_options.trickle) { - n = snprintf(dst, len, "a=ice-options:trickle\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - } - - // write media attribute: fingerprint - n = snprintf(dst, len, - "a=fingerprint:sha-256 " - "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" - "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" - "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" - "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX\n", - src->fingerprint.sha256[0], src->fingerprint.sha256[1], - src->fingerprint.sha256[2], src->fingerprint.sha256[3], - src->fingerprint.sha256[4], src->fingerprint.sha256[5], - src->fingerprint.sha256[6], src->fingerprint.sha256[7], - src->fingerprint.sha256[8], src->fingerprint.sha256[9], - src->fingerprint.sha256[10], src->fingerprint.sha256[11], - src->fingerprint.sha256[12], src->fingerprint.sha256[13], - src->fingerprint.sha256[14], src->fingerprint.sha256[15], - src->fingerprint.sha256[16], src->fingerprint.sha256[17], - src->fingerprint.sha256[18], src->fingerprint.sha256[19], - src->fingerprint.sha256[20], src->fingerprint.sha256[21], - src->fingerprint.sha256[22], src->fingerprint.sha256[23], - src->fingerprint.sha256[24], src->fingerprint.sha256[25], - src->fingerprint.sha256[26], src->fingerprint.sha256[27], - src->fingerprint.sha256[28], src->fingerprint.sha256[29], - src->fingerprint.sha256[30], src->fingerprint.sha256[31] - ); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // TODO write setup, mid - - // write media attribute: mode - switch (src->mode) { - case SDP_MODE_RECEIVE_ONLY: - n = snprintf(dst, len, "a=recvonly\n"); - break; - case SDP_MODE_SEND_ONLY: - n = snprintf(dst, len, "a=sendonly\n"); - break; - case SDP_MODE_SEND_AND_RECEIVE: - n = snprintf(dst, len, "a=sendrecv\n"); - break; - default: - return -URTC_ERR_SDP_MALFORMED; - break; - } - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - // write media attribute: rtcp mux - if (src->rtcp_mux) { - n = snprintf(dst, len, "a=rtcp-mux\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - } - - // write media attribute: rtcp rsize - if (src->rtcp_rsize) { - n = snprintf(dst, len, "a=rtcp-rsize\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - n -= n; - } - - // write dynamic profiles - for (int i = 0; i < src->video.count; i++) { - if (src->video.params[i].codec == SDP_CODEC_H264) { - n = snprintf(dst, len, "a=rtpmap:%d H264/%d\n", - src->video.params[i].type, - src->video.params[i].clock - ); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - } - } - - // write media attribute: media id - // TODO fix hardcoded media id - n = snprintf(dst, len, "a=mid:0\n"); - if (n < 0) return -URTC_ERR_SDP_MALFORMED; - if (n >= len) return -URTC_ERR_SDP_MALFORMED; - dst += n; - len -= n; - - return 0; + int n; + + // sanity check + if (!dst) return -URTC_ERR_BAD_ARGUMENT; + if (!src) return -URTC_ERR_BAD_ARGUMENT; + + // write version + n = snprintf(dst, len, "v=%u\n", src->version); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write originator and session identifier + n = snprintf(dst, len, + "o=liburtc/0.0.0 %s %s IN IP4 127.0.0.1\n", + src->session_id, + src->session_version + ); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write session name + n = snprintf(dst, len, "s=%s\n", + 0 == strlen(src->session_name) ? " " : src->session_name); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write uri + n = snprintf(dst, len, "u=http://www.liburtc.org\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write time descriptor + n = snprintf(dst, len, "t=%" PRIu64 " %" PRIu64 "\n", + src->start_time, src->stop_time); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write session attribute + n = snprintf(dst, len, "a=group:BUNDLE"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + for (int i = 0; i < SDP_MAX_BUNDLE_IDS; i++) { + if (strlen(src->mid[i]) > 0) { + n = snprintf(dst, len, " %s", src->mid[i]); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + } + } + n = snprintf(dst, len, "\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write video media description + if (src->video.count > 0) { + n = snprintf( + dst, len, "m=video %hd UDP/TLS/RTP/SAVPF", src->video.port + ); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + for (int i = 0; i < src->video.count; i++) { + if (src->video.params[i].codec == SDP_CODEC_H264) { + n = snprintf(dst, len, " %d", src->video.params[i].type); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n > len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + } + } + n = snprintf(dst, len, "\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + } + + // TODO write rtcp attribute + + // write connection information (TODO IPv6) + n = snprintf(dst, len, "c=IN IP4 0.0.0.0\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write media attribute: ice ufrag + n = snprintf(dst, len, "a=ice-ufrag:%s\n", src->ufrag); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write media attribute: ice pwd + n = snprintf(dst, len, "a=ice-pwd:%s\n", src->pwd); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write media attribute: trickle ICE + if (src->ice_options.trickle) { + n = snprintf(dst, len, "a=ice-options:trickle\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + } + + // write media attribute: fingerprint + n = snprintf(dst, len, + "a=fingerprint:sha-256 " + "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" + "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" + "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:" + "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX\n", + src->fingerprint.sha256[0], src->fingerprint.sha256[1], + src->fingerprint.sha256[2], src->fingerprint.sha256[3], + src->fingerprint.sha256[4], src->fingerprint.sha256[5], + src->fingerprint.sha256[6], src->fingerprint.sha256[7], + src->fingerprint.sha256[8], src->fingerprint.sha256[9], + src->fingerprint.sha256[10], src->fingerprint.sha256[11], + src->fingerprint.sha256[12], src->fingerprint.sha256[13], + src->fingerprint.sha256[14], src->fingerprint.sha256[15], + src->fingerprint.sha256[16], src->fingerprint.sha256[17], + src->fingerprint.sha256[18], src->fingerprint.sha256[19], + src->fingerprint.sha256[20], src->fingerprint.sha256[21], + src->fingerprint.sha256[22], src->fingerprint.sha256[23], + src->fingerprint.sha256[24], src->fingerprint.sha256[25], + src->fingerprint.sha256[26], src->fingerprint.sha256[27], + src->fingerprint.sha256[28], src->fingerprint.sha256[29], + src->fingerprint.sha256[30], src->fingerprint.sha256[31] + ); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // TODO write setup, mid + + // write media attribute: mode + switch (src->mode) { + case SDP_MODE_RECEIVE_ONLY: + n = snprintf(dst, len, "a=recvonly\n"); + break; + case SDP_MODE_SEND_ONLY: + n = snprintf(dst, len, "a=sendonly\n"); + break; + case SDP_MODE_SEND_AND_RECEIVE: + n = snprintf(dst, len, "a=sendrecv\n"); + break; + default: + return -URTC_ERR_SDP_MALFORMED; + break; + } + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + // write media attribute: rtcp mux + if (src->rtcp_mux) { + n = snprintf(dst, len, "a=rtcp-mux\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + } + + // write media attribute: rtcp rsize + if (src->rtcp_rsize) { + n = snprintf(dst, len, "a=rtcp-rsize\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + n -= n; + } + + // write dynamic profiles + for (int i = 0; i < src->video.count; i++) { + if (src->video.params[i].codec == SDP_CODEC_H264) { + n = snprintf(dst, len, "a=rtpmap:%d H264/%d\n", + src->video.params[i].type, + src->video.params[i].clock + ); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + } + } + + // write media attribute: media id + // TODO fix hardcoded media id + n = snprintf(dst, len, "a=mid:0\n"); + if (n < 0) return -URTC_ERR_SDP_MALFORMED; + if (n >= len) return -URTC_ERR_SDP_MALFORMED; + dst += n; + len -= n; + + return 0; } + +/* vim: set expandtab ts=8 sw=4 tw=0 : */ -- cgit v1.2.3