From c6db2ac7c7b578b96c9b13c5f0b60ff28bbcdac4 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Thu, 15 Aug 2019 06:12:54 +0200 Subject: [PATCH] forward full SDP between MNCC and SIP Populate the new 'sdp' field added in MNCC v6, to enable full SDP codec negotiation between osmo-msc and SIP. Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae --- src/call.c | 10 ++++++++++ src/call.h | 2 ++ src/mncc.c | 42 +++++++++++++++++++++++++++++++----------- src/sip.c | 22 ++++++++++++++++++---- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/call.c b/src/call.c index 9f593ea..487be56 100644 --- a/src/call.c +++ b/src/call.c @@ -172,3 +172,13 @@ const char *call_leg_state(struct call_leg *leg) return "Unknown call type"; } } + +void call_leg_update_sdp(struct call_leg *leg, const char *sdp) +{ + /* If no SDP was received, keep whatever SDP was previously seen. */ + if (!sdp || !*sdp) + return; + OSMO_STRLCPY_ARRAY(leg->sdp, sdp); + LOGP(DAPP, LOGL_NOTICE, "call(%u) leg(0x%p) received SDP: %s\n", + leg->call->id, leg, leg->sdp); +} diff --git a/src/call.h b/src/call.h index 7f67066..9bf68eb 100644 --- a/src/call.h +++ b/src/call.h @@ -162,6 +162,8 @@ void calls_init(void); struct call_leg *call_leg_other(struct call_leg *leg); +void call_leg_update_sdp(struct call_leg *cl, const char *sdp); + void call_leg_release(struct call_leg *leg); diff --git a/src/mncc.c b/src/mncc.c index 16eed96..cee4def 100644 --- a/src/mncc.c +++ b/src/mncc.c @@ -184,11 +184,13 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other) mncc.callref = leg->callref; mncc.ip = ntohl(other->ip); mncc.port = other->port; + + /* Send payload_type as legacy compatibility, in addition full SDP. */ mncc.payload_type = other->payload_type; - /* - * FIXME: mncc.payload_msg_type should already be compatible.. but - * payload_type should be different.. - */ + + /* Send full SDP info forwarded from SIP, since MNCC protocol version 6: */ + OSMO_STRLCPY_ARRAY(mncc.sdp, other->sdp); + struct in_addr net = { .s_addr = other->ip }; inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr)); LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n", ip_addr, mncc.port); @@ -396,6 +398,8 @@ static void check_rtp_connect(struct mncc_connection *conn, const char *buf, int return mncc_send(conn, MNCC_REJ_REQ, rtp->callref); } + call_leg_update_sdp(&leg->base, rtp->sdp); + /* extract information about where the RTP is */ if (rtp->ip != 0 || rtp->port != 0 || rtp->payload_type != 0) return; @@ -433,6 +437,8 @@ static void check_rtp_create(struct mncc_connection *conn, const char *buf, int leg->base.payload_type = rtp->payload_type; leg->base.payload_msg_type = rtp->payload_msg_type; + call_leg_update_sdp(&leg->base, rtp->sdp); + /* TODO.. now we can continue with the call */ struct in_addr net = { .s_addr = leg->base.ip }; inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr)); @@ -501,7 +507,6 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc) return mncc_send(conn, MNCC_REJ_REQ, data->callref); } - /* TODO.. bearer caps and better audio handling */ if (!continue_setup(conn, data)) { LOGP(DMNCC, LOGL_ERROR, "MNCC screening parameters failed leg(%u)\n", data->callref); @@ -529,6 +534,9 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc) memcpy(&leg->calling, &data->calling, sizeof(leg->calling)); memcpy(&leg->imsi, data->imsi, sizeof(leg->imsi)); + /* forward full SDP description of audio codecs */ + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_INFO, "Created call(%u) with MNCC leg(%u) IMSI(%.16s)\n", call->id, leg->callref, data->imsi); @@ -638,6 +646,8 @@ static void check_stp_cmpl_ind(struct mncc_connection *conn, const char *buf, in if (!leg) return; + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_INFO, "leg(%u) is now connected.\n", leg->callref); stop_cmd_timer(leg, MNCC_SETUP_COMPL_IND); leg->state = MNCC_CC_CONNECTED; @@ -672,6 +682,8 @@ static void check_cnf_ind(struct mncc_connection *conn, const char *buf, int rc) if (!leg) return; + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_DEBUG, "leg(%u) confirmed. creating RTP socket.\n", leg->callref); @@ -690,6 +702,8 @@ static void check_alrt_ind(struct mncc_connection *conn, const char *buf, int rc if (!leg) return; + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_DEBUG, "leg(%u) is alerting.\n", leg->callref); @@ -768,6 +782,8 @@ static void check_stp_cnf(struct mncc_connection *conn, const char *buf, int rc) if (!leg) return; + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_DEBUG, "leg(%u) setup completed\n", leg->callref); other_leg = call_leg_other(&leg->base); @@ -797,6 +813,8 @@ static void check_dtmf_start(struct mncc_connection *conn, const char *buf, int if (!leg) return; + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_DEBUG, "leg(%u) DTMF key=%c\n", leg->callref, data->keypad); other_leg = call_leg_other(&leg->base); @@ -819,6 +837,8 @@ static void check_dtmf_stop(struct mncc_connection *conn, const char *buf, int r if (!leg) return; + call_leg_update_sdp(&leg->base, data->sdp); + LOGP(DMNCC, LOGL_DEBUG, "leg(%u) DTMF key=%c\n", leg->callref, data->keypad); mncc_fill_header(&out_mncc, MNCC_STOP_DTMF_RSP, leg->callref); @@ -898,12 +918,12 @@ int mncc_create_remote_leg(struct mncc_connection *conn, struct call *call) OSMO_STRLCPY_ARRAY(mncc.called.number, call->dest); } - /* - * TODO/FIXME: - * - Determine/request channel based on offered audio codecs - * - Screening, redirect? - * - Synth. the bearer caps based on codecs? - */ + /* The call->initial leg is a SIP call leg that starts an MT call. There was SDP received in the SIP INVITE that + * started this call. This here will be the call->remote, always forwarding the SDP that came in on + * call->initial. */ + if (call->initial) + OSMO_STRLCPY_ARRAY(mncc.sdp, call->initial->sdp); + rc = write(conn->fd.fd, &mncc, sizeof(mncc)); if (rc != sizeof(mncc)) { LOGP(DMNCC, LOGL_ERROR, "Failed to send message leg(%u)\n", diff --git a/src/sip.c b/src/sip.c index c635542..83b0715 100644 --- a/src/sip.c +++ b/src/sip.c @@ -43,6 +43,12 @@ static void sip_dtmf_call(struct call_leg *_leg, int keypad); static void sip_hold_call(struct call_leg *_leg); static void sip_retrieve_call(struct call_leg *_leg); +static const char *sip_get_sdp(const sip_t *sip) +{ + if (!sip || !sip->sip_payload) + return NULL; + return sip->sip_payload->pl_data; +} /* Find a SIP Call leg by given nua_handle */ static struct sip_call_leg *sip_find_leg(nua_handle_t *nh) @@ -82,7 +88,6 @@ static void call_progress(struct sip_call_leg *leg, const sip_t *sip, int status static void call_connect(struct sip_call_leg *leg, const sip_t *sip) { - /* extract SDP file and if compatible continue */ struct call_leg *other = call_leg_other(&leg->base); if (!other) { @@ -177,6 +182,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, nua_handle_bind(nh, leg); leg->sdp_payload = talloc_strdup(leg, sip->sip_payload->pl_data); + call_leg_update_sdp(&leg->base, sip_get_sdp(sip)); + app_route_call(call, talloc_strdup(leg, from), talloc_strdup(leg, to)); @@ -218,6 +225,8 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr)); LOGP(DSIP, LOGL_DEBUG, "pre re-INVITE have IP:port (%s:%u)\n", ip_addr, leg->base.port); + call_leg_update_sdp(&leg->base, sip_get_sdp(sip)); + if (mode == sdp_sendonly) { /* SIP side places call on HOLD */ sdp = sdp_create_file(leg, other, sdp_recvonly); @@ -330,6 +339,8 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, struct sip_call_leg *leg; leg = (struct sip_call_leg *) hmagic; + call_leg_update_sdp(&leg->base, sip_get_sdp(sip)); + /* MT call is moving forward */ /* The dialogue is now confirmed */ @@ -366,8 +377,10 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, * respond to the re-INVITE query. */ if (sip->sip_payload && sip->sip_payload->pl_data) { struct sip_call_leg *leg = sip_find_leg(nh); - if (leg) + if (leg) { + call_leg_update_sdp(&leg->base, sip_get_sdp(sip)); sip_handle_reinvite(leg, nh, sip); + } } } else if (event == nua_r_bye || event == nua_r_cancel) { /* our bye or hang up is answered */ @@ -393,9 +406,10 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, if (status == 100) { struct sip_call_leg *leg = sip_find_leg(nh); - if (leg) + if (leg) { + call_leg_update_sdp(&leg->base, sip_get_sdp(sip)); sip_handle_reinvite(leg, nh, sip); - else + } else new_call((struct sip_agent *) magic, nh, sip); } } else if (event == nua_i_cancel) {