From bd733d8e91801af15fe82a936ea2bbe4efa2fbfe Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Thu, 15 Aug 2019 06:12:54 +0200 Subject: add sdp to mncc Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae --- src/call.c | 10 ++++++++++ src/call.h | 2 ++ src/mncc.c | 37 +++++++++++++++++++++++++++++++------ src/sdp.c | 16 +++++++++++++++- src/sip.c | 46 ++++++++++++++++++++++++++++++---------------- 5 files changed, 88 insertions(+), 23 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 d1732f9..a40fd3b 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 0725d4c..e707b88 100644 --- a/src/mncc.c +++ b/src/mncc.c @@ -184,6 +184,8 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other) mncc.callref = leg->callref; mncc.addr = other->addr; mncc.payload_type = other->payload_type; + + OSMO_STRLCPY_ARRAY(mncc.sdp, other->sdp); /* * FIXME: mncc.payload_msg_type should already be compatible.. but * payload_type should be different.. @@ -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->addr.ss_family != AF_UNSPEC || osmo_sockaddr_port((const struct sockaddr *)&rtp->addr) != 0 || @@ -434,6 +438,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 */ LOGP(DMNCC, LOGL_INFO, "RTP continue leg(%u) ip(%s), port(%u) pt(%u) ptm(%u)\n", @@ -503,6 +509,8 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc) } /* TODO.. bearer caps and better audio handling */ + printf("MNCC_SETUP_IND SDP: <<\n%s>>\n", data->sdp); + if (!continue_setup(conn, data)) { LOGP(DMNCC, LOGL_ERROR, "MNCC screening parameters failed leg(%u)\n", data->callref); @@ -530,6 +538,8 @@ 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)); + 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); @@ -639,6 +649,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; @@ -673,6 +685,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); @@ -691,6 +705,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); @@ -769,6 +785,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); @@ -798,6 +816,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); @@ -820,6 +840,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); @@ -899,12 +921,15 @@ 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); + printf("call->initial->sdp == %s\n", call->initial->sdp); + } else + printf("no call->initial\n"); + 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/sdp.c b/src/sdp.c index f1909d4..0d07f7e 100644 --- a/src/sdp.c +++ b/src/sdp.c @@ -191,7 +191,9 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec) continue; for (map = media->m_rtpmaps; map; map = map->rm_next) { - if (!any_codec && strcasecmp(map->rm_encoding, leg->wanted_codec) != 0) + if (!any_codec + && leg->wanted_codec + && strcasecmp(map->rm_encoding, leg->wanted_codec) != 0) continue; port = media->m_port; @@ -226,8 +228,19 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec) return true; } +/* One leg has sent a SIP or MNCC message, which is now translated/forwarded to the counterpart MNCC or SIP. + * Take as much from the source's SDP as possible, but make sure the connection mode reflects the 'mode' arg (sendrecv, + * recvonly, sendonly, inactive). + * @param leg The target receiving the SDP. + * @param other The source of which we are to reflect the SDP. + * For example, if the MNCC sent an MNCC_SETUP_IND, the SDP from the MNCC is found in 'other', while 'leg' reflects the + * SIP side that should receive this SDP in the SIP Invite that is being composed by the caller. + */ char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode_t mode) { + /* TODO: make sure SDP reflects the requested mode */ + return talloc_strdup(leg, other->sdp); +#if 0 char *fmtp_str = NULL, *sdp; char *mode_attribute; char ip_addr[INET6_ADDRSTRLEN]; @@ -277,4 +290,5 @@ char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode mode_attribute); talloc_free(fmtp_str); return sdp; +#endif } diff --git a/src/sip.c b/src/sip.c index ba9730a..6a02df2 100644 --- a/src/sip.c +++ b/src/sip.c @@ -45,6 +45,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) @@ -75,8 +81,10 @@ static void call_progress(struct sip_call_leg *leg, const sip_t *sip, int status return; /* Extract SDP for session in progress with matching codec */ + /* if (status == 183) sdp_extract_sdp(leg, sip, false); + */ LOGP(DSIP, LOGL_INFO, "leg(%p) is now progressing.\n", leg); other->ring_call(other); @@ -93,12 +101,14 @@ static void call_connect(struct sip_call_leg *leg, const sip_t *sip) return; } + /* if (!sdp_extract_sdp(leg, sip, false)) { LOGP(DSIP, LOGL_ERROR, "leg(%p) incompatible audio, releasing\n", leg); nua_cancel(leg->nua_handle, TAG_END()); other->release_call(other); return; } + */ LOGP(DSIP, LOGL_INFO, "leg(%p) is now connected(%s).\n", leg, sip->sip_call_id->i_id); leg->state = SIP_CC_CONNECTED; @@ -116,20 +126,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, LOGP(DSIP, LOGL_INFO, "Incoming call(%s) handle(%p)\n", sip->sip_call_id->i_id, nh); - 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); - return; - } - call = call_sip_create(); - if (!call) { - LOGP(DSIP, LOGL_ERROR, "No supported codec.\n"); - nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); - nua_handle_destroy(nh); - return; - } + OSMO_ASSERT(call); if (sip->sip_to) to = sip->sip_to->a_url->url_user; @@ -147,6 +145,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, leg->state = SIP_CC_DLG_CNFD; leg->dir = SIP_DIR_MO; + + /* * FIXME/TODO.. we need to select the codec at some point. But it is * not this place. It starts with the TCH/F vs. TCH/H selection based @@ -154,6 +154,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, * are GSM related... and do not belong here. Just pick the first codec * so the IP address, port and payload type is set. */ + /* if (!sdp_extract_sdp(leg, sip, true)) { LOGP(DSIP, LOGL_ERROR, "leg(%p) no audio, releasing\n", leg); nua_respond(nh, SIP_406_NOT_ACCEPTABLE, TAG_END()); @@ -161,6 +162,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, call_leg_release(&leg->base); return; } + */ LOGP(DSIP, LOGL_INFO, "SDP Extracted: IP=(%s) PORT=(%u) PAYLOAD=(%u).\n", osmo_sockaddr_ntop((const struct sockaddr *)&leg->base.addr, ip_addr), osmo_sockaddr_port((const struct sockaddr *)&leg->base.addr), @@ -177,6 +179,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)); @@ -217,6 +221,8 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons osmo_sockaddr_ntop((struct sockaddr*)&leg->base.addr, ip_addr), osmo_sockaddr_port((struct sockaddr*)&leg->base.addr)); + 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 +336,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 +374,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 +403,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) { @@ -599,6 +610,9 @@ static int send_invite(struct sip_agent *agent, struct sip_call_leg *leg, agent->app->sip.remote_port); char *sdp = sdp_create_file(leg, other, sdp_sendrecv); + LOGP(DSIP, LOGL_DEBUG, "Will send INVITE with SDP: %s\n", + sdp); + leg->state = SIP_CC_INITIAL; leg->dir = SIP_DIR_MT; nua_invite(leg->nua_handle, -- cgit v1.2.3