From 8970c497bc254c834dc62ea13cd4ba17e16d03be Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Wed, 11 Oct 2017 13:33:42 +0200 Subject: [PATCH] sdp: refactoring sdp parser/generator move SDP generator function write_response_sdp() from mgcp_protocol.c to mgcp_sdp.c and use msgb_printf() instead of snprintf() move prototypes for mgcp_parse_sdp_data() and mgcp_set_audio_info() to mgcp_sdp.h change parameter list of mgcp_parse_sdp_data() so that it takes the rtp conn directly, rather than struct mgcp_rtp_end. add doxygen comments to all public functions Change-Id: I9f88c93872ff913bc211f560b26901267f577324 --- include/osmocom/mgcp/Makefile.am | 1 + include/osmocom/mgcp/mgcp_internal.h | 3 - include/osmocom/mgcp/mgcp_sdp.h | 35 ++++++++ src/libosmo-mgcp/mgcp_protocol.c | 115 +++++---------------------- src/libosmo-mgcp/mgcp_sdp.c | 104 +++++++++++++++++++++++- 5 files changed, 158 insertions(+), 100 deletions(-) create mode 100644 include/osmocom/mgcp/mgcp_sdp.h diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am index 646b88731..cd8f59927 100644 --- a/include/osmocom/mgcp/Makefile.am +++ b/include/osmocom/mgcp/Makefile.am @@ -4,4 +4,5 @@ noinst_HEADERS = \ mgcp_conn.h \ mgcp_stat.h \ mgcp_ep.h \ + mgcp_sdp.h \ $(NULL) diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h index 751aba50a..d4c8dc947 100644 --- a/include/osmocom/mgcp/mgcp_internal.h +++ b/include/osmocom/mgcp/mgcp_internal.h @@ -317,9 +317,6 @@ enum { #define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1 #define PTYPE_UNDEFINED (-1) -int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p); -int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec, - int payload_type, const char *audio_name); /*! get the ip-address where the mgw application is bound on. * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters diff --git a/include/osmocom/mgcp/mgcp_sdp.h b/include/osmocom/mgcp/mgcp_sdp.h new file mode 100644 index 000000000..da23cbaba --- /dev/null +++ b/include/osmocom/mgcp/mgcp_sdp.h @@ -0,0 +1,35 @@ +/* + * SDP generation and parsing + * + * (C) 2009-2015 by Holger Hans Peter Freyther + * (C) 2009-2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#pragma once +#include + +int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, + struct mgcp_conn_rtp *conn, + struct mgcp_parse_data *p); + +int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec, + int payload_type, const char *audio_name); + +int mgcp_write_response_sdp(const struct mgcp_endpoint *endp, + const struct mgcp_conn_rtp *conn, struct msgb *sdp, + const char *addr); diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c index c00cdc6dc..6c611f7f7 100644 --- a/src/libosmo-mgcp/mgcp_protocol.c +++ b/src/libosmo-mgcp/mgcp_protocol.c @@ -39,6 +39,7 @@ #include #include #include +#include struct mgcp_request { char *name; @@ -191,80 +192,6 @@ static struct msgb *create_err_response(struct mgcp_endpoint *endp, return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL); } -static int write_response_sdp(struct mgcp_endpoint *endp, - struct mgcp_conn_rtp *conn, - char *sdp_record, size_t size, const char *addr) -{ - const char *fmtp_extra; - const char *audio_name; - int payload_type; - int len; - int nchars; - - if (!conn) - return -1; - - endp->cfg->get_net_downlink_format_cb(endp, &payload_type, - &audio_name, &fmtp_extra, conn); - - len = snprintf(sdp_record, size, - "v=0\r\n" - "o=- %u 23 IN IP4 %s\r\n" - "s=-\r\n" - "c=IN IP4 %s\r\n" - "t=0 0\r\n", conn->conn->id, addr, addr); - - if (len < 0 || len >= size) - goto buffer_too_small; - - if (payload_type >= 0) { - nchars = snprintf(sdp_record + len, size - len, - "m=audio %d RTP/AVP %d\r\n", - conn->end.local_port, payload_type); - if (nchars < 0 || nchars >= size - len) - goto buffer_too_small; - - len += nchars; - - if (audio_name && endp->tcfg->audio_send_name) { - nchars = snprintf(sdp_record + len, size - len, - "a=rtpmap:%d %s\r\n", - payload_type, audio_name); - - if (nchars < 0 || nchars >= size - len) - goto buffer_too_small; - - len += nchars; - } - - if (fmtp_extra) { - nchars = snprintf(sdp_record + len, size - len, - "%s\r\n", fmtp_extra); - - if (nchars < 0 || nchars >= size - len) - goto buffer_too_small; - - len += nchars; - } - } - if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) { - nchars = snprintf(sdp_record + len, size - len, - "a=ptime:%u\r\n", - conn->end.packet_duration_ms); - if (nchars < 0 || nchars >= size - len) - goto buffer_too_small; - - len += nchars; - } - - return len; - -buffer_too_small: - LOGP(DLMGCP, LOGL_ERROR, "SDP buffer too small: %zu (needed %d)\n", - size, len); - return -1; -} - /* Format MGCP response string (with SDP attached) */ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn, @@ -272,11 +199,15 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, const char *trans_id) { const char *addr = endp->cfg->local_ip; - char sdp_record[4096]; - int len; - int nchars; + struct msgb *sdp; + int rc; + struct msgb *result; char osmux_extension[strlen("\nX-Osmux: 255") + 1]; + sdp = msgb_alloc_headroom(4096, 128, "sdp record"); + if (!sdp) + return NULL; + if (!addr) addr = mgcp_net_src_addr(endp); @@ -287,21 +218,19 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, osmux_extension[0] = '\0'; } - len = snprintf(sdp_record, sizeof(sdp_record), - "I: %u%s\n\n", conn->conn->id, osmux_extension); - if (len < 0) - return NULL; + rc = msgb_printf(sdp, "I: %u%s\n\n", conn->conn->id, osmux_extension); + if (rc < 0) + goto error; - nchars = write_response_sdp(endp, conn, sdp_record + len, - sizeof(sdp_record) - len - 1, addr); - if (nchars < 0) - return NULL; - - len += nchars; - - sdp_record[sizeof(sdp_record) - 1] = '\0'; - - return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record); + rc = mgcp_write_response_sdp(endp, conn, sdp, addr); + if (rc < 0) + goto error; + result = create_resp(endp, 200, " OK", msg, trans_id, NULL, (char*) sdp->data); + msgb_free(sdp); + return result; +error: + msgb_free(sdp); + return NULL; } /* Send out dummy packet to keep the connection open, if the connection is an @@ -689,7 +618,7 @@ mgcp_header_done: /* set up RTP media parameters */ if (have_sdp) - mgcp_parse_sdp_data(endp, &conn->end, p); + mgcp_parse_sdp_data(endp, conn, p); else if (endp->local_options.codec) mgcp_set_audio_info(p->cfg, &conn->end.codec, PTYPE_UNDEFINED, endp->local_options.codec); @@ -836,7 +765,7 @@ mgcp_header_done: conn->conn->mode = conn->conn->mode_orig; if (have_sdp) - mgcp_parse_sdp_data(endp, &conn->end, p); + mgcp_parse_sdp_data(endp, conn, p); set_local_cx_options(endp->tcfg->endpoints, &endp->local_options, local_options); diff --git a/src/libosmo-mgcp/mgcp_sdp.c b/src/libosmo-mgcp/mgcp_sdp.c index 75683511a..e6bf9c209 100644 --- a/src/libosmo-mgcp/mgcp_sdp.c +++ b/src/libosmo-mgcp/mgcp_sdp.c @@ -20,6 +20,7 @@ * */ +#include #include #include #include @@ -38,6 +39,12 @@ struct sdp_rtp_map { int channels; }; +/*! Set codec configuration depending on payload type and codec name. + * \param[in] ctx talloc context. + * \param[out] codec configuration (caller provided memory). + * \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined). + * \param[in] audio_name audio codec name (e.g. "GSM/8000/1"). + * \returns 0 on success, -1 on failure. */ int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec, int payload_type, const char *audio_name) { @@ -107,7 +114,7 @@ int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec, return 0; } -void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used) +static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used) { int i; @@ -137,7 +144,8 @@ void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used) } } -void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, int payload, char *audio_name) +static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, + int payload, const char *audio_name) { int i; @@ -163,7 +171,9 @@ void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, int payload, LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload, audio_name); } -int is_codec_compatible(struct mgcp_endpoint *endp, struct sdp_rtp_map *codec) +/* Check if the codec matches what is set up in the trunk config */ +static int is_codec_compatible(const struct mgcp_endpoint *endp, + const struct sdp_rtp_map *codec) { char *bts_codec; char audio_codec[64]; @@ -182,7 +192,17 @@ int is_codec_compatible(struct mgcp_endpoint *endp, struct sdp_rtp_map *codec) return strcasecmp(audio_codec, codec->codec_name) == 0; } -int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) +/*! Analyze SDP input string. + * \param[in] endp trunk endpoint. + * \param[out] conn associated rtp connection. + * \param[out] caller provided memory to store the parsing results. + * \returns 0 on success, -1 on failure. + * + * Note: In conn (conn->end) the function returns the packet duration, + * the rtp port and the rtcp port */ +int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, + struct mgcp_conn_rtp *conn, + struct mgcp_parse_data *p) { struct sdp_rtp_map codecs[10]; int codecs_used = 0; @@ -191,7 +211,13 @@ int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, st int i; int codecs_assigned = 0; void *tmp_ctx = talloc_new(NULL); + struct mgcp_rtp_end *rtp; + OSMO_ASSERT(endp); + OSMO_ASSERT(conn); + OSMO_ASSERT(p); + + rtp = &conn->end; memset(&codecs, 0, sizeof(codecs)); for_each_line(line, p->save) { @@ -304,3 +330,73 @@ int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, st return codecs_assigned > 0; } +/*! Generate SDP response string. + * \param[in] endp trunk endpoint. + * \param[in] conn associated rtp connection. + * \param[out] sdp msg buffer to append resulting SDP string data. + * \param[in] addr IPV4 address string (e.g. 192.168.100.1). + * \returns 0 on success, -1 on failure. */ +int mgcp_write_response_sdp(const struct mgcp_endpoint *endp, + const struct mgcp_conn_rtp *conn, struct msgb *sdp, + const char *addr) +{ + const char *fmtp_extra; + const char *audio_name; + int payload_type; + int rc; + + OSMO_ASSERT(endp); + OSMO_ASSERT(conn); + OSMO_ASSERT(sdp); + OSMO_ASSERT(addr); + + /* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */ + endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp, + &payload_type, &audio_name, + &fmtp_extra, + (struct mgcp_conn_rtp *)conn); + + rc = msgb_printf(sdp, + "v=0\r\n" + "o=- %u 23 IN IP4 %s\r\n" + "s=-\r\n" + "c=IN IP4 %s\r\n" + "t=0 0\r\n", conn->conn->id, addr, addr); + + if (rc < 0) + goto buffer_too_small; + + if (payload_type >= 0) { + rc = msgb_printf(sdp, "m=audio %d RTP/AVP %d\r\n", + conn->end.local_port, payload_type); + if (rc < 0) + goto buffer_too_small; + + if (audio_name && endp->tcfg->audio_send_name) { + rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n", + payload_type, audio_name); + + if (rc < 0) + goto buffer_too_small; + } + + if (fmtp_extra) { + rc = msgb_printf(sdp, "%s\r\n", fmtp_extra); + + if (rc < 0) + goto buffer_too_small; + } + } + if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) { + rc = msgb_printf(sdp, "a=ptime:%u\r\n", + conn->end.packet_duration_ms); + if (rc < 0) + goto buffer_too_small; + } + + return 0; + +buffer_too_small: + LOGP(DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n"); + return -1; +}