From 392313ff735af6b17672787c83fa80fe5439710f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 26 Mar 2016 20:02:06 +0100 Subject: [PATCH] sdp: Extract SDP traversing into a separate module The code will still know about SIP and the sip_call_leg but is now separate of the call handling logic. --- src/Makefile.am | 3 +- src/sdp.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ src/sdp.h | 10 +++ src/sip.c | 137 +--------------------------------------- 4 files changed, 176 insertions(+), 135 deletions(-) create mode 100644 src/sdp.c create mode 100644 src/sdp.h diff --git a/src/Makefile.am b/src/Makefile.am index 5fb445d..d71d4f7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,9 +3,10 @@ bin_PROGRAMS = osmo-sip-connector AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(SOFIASIP_CFLAGS) noinst_HEADERS = \ - evpoll.h vty.h mncc_protocol.h app.h mncc.h sip.h call.h + evpoll.h vty.h mncc_protocol.h app.h mncc.h sip.h call.h sdp.h osmo_sip_connector_SOURCES = \ + sdp.c \ app.c \ call.c \ sip.c \ diff --git a/src/sdp.c b/src/sdp.c new file mode 100644 index 0000000..78c314f --- /dev/null +++ b/src/sdp.c @@ -0,0 +1,161 @@ +/* + * (C) 2016 by Holger Hans Peter Freyther + * + * 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 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 . + * + */ + +#include "sdp.h" +#include "call.h" +#include "logging.h" + +#include + +#include +#include + +#include + +/* + * We want to decide on the audio codec later but we need to see + * if it is even including some of the supported ones. + */ +bool sdp_screen_sdp(const sip_t *sip) +{ + const char *sdp_data; + sdp_parser_t *parser; + sdp_session_t *sdp; + sdp_media_t *media; + + if (!sip->sip_payload || !sip->sip_payload->pl_data) { + LOGP(DSIP, LOGL_ERROR, "No SDP file\n"); + return false; + } + + sdp_data = sip->sip_payload->pl_data; + parser = sdp_parse(NULL, sdp_data, strlen(sdp_data), 0); + if (!parser) { + LOGP(DSIP, LOGL_ERROR, "Failed to parse SDP\n"); + return false; + } + + sdp = sdp_session(parser); + if (!sdp) { + LOGP(DSIP, LOGL_ERROR, "No sdp session\n"); + sdp_parser_free(parser); + return false; + } + + for (media = sdp->sdp_media; media; media = media->m_next) { + sdp_rtpmap_t *map; + + if (media->m_proto != sdp_proto_rtp) + continue; + if (media->m_type != sdp_media_audio) + continue; + + for (map = media->m_rtpmaps; map; map = map->rm_next) { + if (strcasecmp(map->rm_encoding, "GSM") == 0) + goto success; + if (strcasecmp(map->rm_encoding, "GSM-EFR") == 0) + goto success; + if (strcasecmp(map->rm_encoding, "GSM-HR-08") == 0) + goto success; + if (strcasecmp(map->rm_encoding, "AMR") == 0) + goto success; + } + } + + sdp_parser_free(parser); + return false; + +success: + sdp_parser_free(parser); + return true; +} + +bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip) +{ + sdp_connection_t *conn; + sdp_session_t *sdp; + sdp_parser_t *parser; + sdp_media_t *media; + const char *sdp_data; + bool found_conn = false, found_map = false; + + if (!sip->sip_payload || !sip->sip_payload->pl_data) { + LOGP(DSIP, LOGL_ERROR, "leg(%p) but no SDP file\n", leg); + return false; + } + + sdp_data = sip->sip_payload->pl_data; + parser = sdp_parse(NULL, sdp_data, strlen(sdp_data), 0); + if (!parser) { + LOGP(DSIP, LOGL_ERROR, "leg(%p) failed to parse SDP\n", + leg); + return false; + } + + sdp = sdp_session(parser); + if (!sdp) { + LOGP(DSIP, LOGL_ERROR, "leg(%p) no sdp session\n", leg); + sdp_parser_free(parser); + return false; + } + + for (conn = sdp->sdp_connection; conn; conn = conn->c_next) { + struct in_addr addr; + + if (conn->c_addrtype != sdp_addr_ip4) + continue; + inet_aton(conn->c_address, &addr); + leg->base.ip = addr.s_addr; + found_conn = true; + break; + } + + for (media = sdp->sdp_media; media; media = media->m_next) { + sdp_rtpmap_t *map; + + if (media->m_proto != sdp_proto_rtp) + continue; + if (media->m_type != sdp_media_audio) + continue; + + for (map = media->m_rtpmaps; map; map = map->rm_next) { + if (strcasecmp(map->rm_encoding, leg->wanted_codec) != 0) + continue; + + leg->base.port = media->m_port; + leg->base.payload_type = map->rm_pt; + found_map = true; + break; + } + + if (found_map) + break; + } + + if (!found_conn || !found_map) { + LOGP(DSIP, LOGL_ERROR, "leg(%p) did not find %d/%d\n", + leg, found_conn, found_map); + sdp_parser_free(parser); + return false; + } + + sdp_parser_free(parser); + return true; +} diff --git a/src/sdp.h b/src/sdp.h new file mode 100644 index 0000000..d19d7b5 --- /dev/null +++ b/src/sdp.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include + +struct sip_call_leg; + +bool sdp_screen_sdp(const sip_t *sip); +bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip); diff --git a/src/sip.c b/src/sip.c index 78a3d0c..32a9264 100644 --- a/src/sip.c +++ b/src/sip.c @@ -22,10 +22,10 @@ #include "app.h" #include "call.h" #include "logging.h" +#include "sdp.h" #include -#include #include #include @@ -34,137 +34,6 @@ extern void *tall_mncc_ctx; -/* - * We want to decide on the audio codec later but we need to see - * if it is even including some of the supported ones. - */ -static bool screen_sdp(const sip_t *sip) -{ - const char *sdp_data; - sdp_parser_t *parser; - sdp_session_t *sdp; - sdp_media_t *media; - - if (!sip->sip_payload || !sip->sip_payload->pl_data) { - LOGP(DSIP, LOGL_ERROR, "No SDP file\n"); - return false; - } - - sdp_data = sip->sip_payload->pl_data; - parser = sdp_parse(NULL, sdp_data, strlen(sdp_data), 0); - if (!parser) { - LOGP(DSIP, LOGL_ERROR, "Failed to parse SDP\n"); - return false; - } - - sdp = sdp_session(parser); - if (!sdp) { - LOGP(DSIP, LOGL_ERROR, "No sdp session\n"); - sdp_parser_free(parser); - return false; - } - - for (media = sdp->sdp_media; media; media = media->m_next) { - sdp_rtpmap_t *map; - - if (media->m_proto != sdp_proto_rtp) - continue; - if (media->m_type != sdp_media_audio) - continue; - - for (map = media->m_rtpmaps; map; map = map->rm_next) { - if (strcasecmp(map->rm_encoding, "GSM") == 0) - goto success; - if (strcasecmp(map->rm_encoding, "GSM-EFR") == 0) - goto success; - if (strcasecmp(map->rm_encoding, "GSM-HR-08") == 0) - goto success; - if (strcasecmp(map->rm_encoding, "AMR") == 0) - goto success; - } - } - - sdp_parser_free(parser); - return false; - -success: - sdp_parser_free(parser); - return true; -} - -static bool extract_sdp(struct sip_call_leg *leg, const sip_t *sip) -{ - sdp_connection_t *conn; - sdp_session_t *sdp; - sdp_parser_t *parser; - sdp_media_t *media; - const char *sdp_data; - bool found_conn = false, found_map = false; - - if (!sip->sip_payload || !sip->sip_payload->pl_data) { - LOGP(DSIP, LOGL_ERROR, "leg(%p) but no SDP file\n", leg); - return false; - } - - sdp_data = sip->sip_payload->pl_data; - parser = sdp_parse(NULL, sdp_data, strlen(sdp_data), 0); - if (!parser) { - LOGP(DSIP, LOGL_ERROR, "leg(%p) failed to parse SDP\n", - leg); - return false; - } - - sdp = sdp_session(parser); - if (!sdp) { - LOGP(DSIP, LOGL_ERROR, "leg(%p) no sdp session\n", leg); - sdp_parser_free(parser); - return false; - } - - for (conn = sdp->sdp_connection; conn; conn = conn->c_next) { - struct in_addr addr; - - if (conn->c_addrtype != sdp_addr_ip4) - continue; - inet_aton(conn->c_address, &addr); - leg->base.ip = addr.s_addr; - found_conn = true; - break; - } - - for (media = sdp->sdp_media; media; media = media->m_next) { - sdp_rtpmap_t *map; - - if (media->m_proto != sdp_proto_rtp) - continue; - if (media->m_type != sdp_media_audio) - continue; - - for (map = media->m_rtpmaps; map; map = map->rm_next) { - if (strcasecmp(map->rm_encoding, leg->wanted_codec) != 0) - continue; - - leg->base.port = media->m_port; - leg->base.payload_type = map->rm_pt; - found_map = true; - break; - } - - if (found_map) - break; - } - - if (!found_conn || !found_map) { - LOGP(DSIP, LOGL_ERROR, "leg(%p) did not find %d/%d\n", - leg, found_conn, found_map); - sdp_parser_free(parser); - return false; - } - - sdp_parser_free(parser); - return true; -} - static void call_progress(struct sip_call_leg *leg, const sip_t *sip) { struct call_leg *other = call_leg_other(&leg->base); @@ -187,7 +56,7 @@ static void call_connect(struct sip_call_leg *leg, const sip_t *sip) return; } - if (!extract_sdp(leg, sip)) { + if (!sdp_extract_sdp(leg, sip)) { LOGP(DSIP, LOGL_ERROR, "leg(%p) incompatible audio, releasing\n", leg); nua_cancel(leg->nua_handle, TAG_END()); other->release_call(other); @@ -205,7 +74,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, { LOGP(DSIP, LOGL_DEBUG, "Incoming call handle(%p)\n", nh); - if (!screen_sdp(sip)) { + if (!sdp_screen_sdp(sip)) { LOGP(DSIP, LOGL_ERROR, "No supported codec.\n"); nua_respond(nh, SIP_406_NOT_ACCEPTABLE, TAG_END()); nua_handle_destroy(nh);