FreeCalypso > hg > themwi-system-sw
view sip-in/mgw_resp.c @ 175:623c64ae6102
doc/Codec-library-depend: libgsmefr is here and actively used
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 10 Jan 2023 18:05:55 -0800 |
parents | 7176dc850d7a |
children |
line wrap: on
line source
/* * In this module we implement our handling of all responses * from themwi-mgw. */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <syslog.h> #include "../include/gsm48_const.h" #include "../include/tmgw_ctrl.h" #include "../include/tmgw_const.h" #include "call.h" extern struct call *find_call_with_mgw_xact(); static void handle_crcx_fail(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { call->overall_state = OVERALL_STATE_TEARDOWN; strcpy(call->invite_fail, "503 Gateway resource allocation failure"); signal_invite_error(call); } static void crcx_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (msg->res == TMGW_RESP_OK) { call->mgw_state = MGW_STATE_ALLOCATED; call->mgw_ep_id = msg->ep_id; bcopy(&msg->gsm_addr, &call->gsm_rtp_tmgw, sizeof(struct sockaddr_storage)); bcopy(&msg->pstn_addr, &call->pstn_rtp_local, sizeof(struct sockaddr_in)); switch (call->overall_state) { case OVERALL_STATE_CRCX: proceed_with_call_setup(call); return; case OVERALL_STATE_TEARDOWN: tmgw_send_dlcx(call); return; default: bad_state: syslog(LOG_CRIT, "FATAL: invalid overall state 0x%x on CRCX response", call->overall_state); exit(1); } } else { switch (call->overall_state) { case OVERALL_STATE_CRCX: handle_crcx_fail(call, msg); return; case OVERALL_STATE_TEARDOWN: transition_dead_sip(call); return; default: goto bad_state; } } } static void handle_mdcx_connect_fail(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { call->overall_state = OVERALL_STATE_TEARDOWN; switch (msg->res) { case TMGW_RESP_ERR_RSRC: disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_RESOURCE_UNAVAIL); strcpy(call->invite_fail, "503 Gateway resource allocation failure"); break; case TMGW_RESP_ERR_NOTSUP: disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); strcpy(call->invite_fail, "502 Gateway internal error"); break; default: disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_PROTO_ERR); strcpy(call->invite_fail, "502 Gateway internal error"); } signal_invite_error(call); } static void mdcx_connect_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (msg->res == TMGW_RESP_OK) { call->mgw_state = MGW_STATE_COMPLETE; switch (call->overall_state) { case OVERALL_STATE_ANSWERED: signal_invite_200(call); return; case OVERALL_STATE_TEARDOWN: tmgw_send_dlcx(call); return; default: bad_state: syslog(LOG_CRIT, "FATAL: invalid overall state 0x%x on MDCX response", call->overall_state); exit(1); } } else { tmgw_send_dlcx(call); switch (call->overall_state) { case OVERALL_STATE_ANSWERED: handle_mdcx_connect_fail(call, msg); return; case OVERALL_STATE_TEARDOWN: return; default: goto bad_state; } } } static void mdcx_hold_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (call->overall_state == OVERALL_STATE_TEARDOWN) { tmgw_send_dlcx(call); return; } if (msg->res == TMGW_RESP_OK) { call->mgw_state = MGW_STATE_HELD; mncc_send_hold_ack(call); } else { call->overall_state = OVERALL_STATE_TEARDOWN; tmgw_send_dlcx(call); disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_NETWORK_OOO); initiate_bye(call); } } static void mdcx_retrieve_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (call->overall_state == OVERALL_STATE_TEARDOWN) { tmgw_send_dlcx(call); return; } if (msg->res == TMGW_RESP_OK) { call->mgw_state = MGW_STATE_COMPLETE; mncc_send_retrieve_ack(call); } else { call->overall_state = OVERALL_STATE_TEARDOWN; tmgw_send_dlcx(call); disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_NETWORK_OOO); initiate_bye(call); } } static void mdcx_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { switch (call->mgw_state) { case MGW_STATE_CONNECTING: mdcx_connect_response(call, msg); return; case MGW_STATE_HOLD_OP: mdcx_hold_response(call, msg); return; case MGW_STATE_RETRIEVE_OP: mdcx_retrieve_response(call, msg); return; default: syslog(LOG_CRIT, "FATAL: invalid MGW state 0x%x on MDCX response", call->mgw_state); exit(1); } } static void dlcx_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (msg->res != TMGW_RESP_OK) { syslog(LOG_CRIT, "FATAL: TMGW DLCX failed with code 0x%x", msg->res); exit(1); } call->mgw_state = MGW_STATE_NO_EXIST; transition_dead_sip(call); } static void dtmf_start_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (call->overall_state == OVERALL_STATE_TEARDOWN) { tmgw_send_dlcx(call); return; } if (msg->res == TMGW_RESP_OK) mncc_dtmf_start_ok(call); else mncc_dtmf_start_err(call); if (call->dtmf_pending_stop) tmgw_send_dtmf_stop(call); else call->mgw_state = MGW_STATE_COMPLETE; } static void dtmf_stop_response(call, msg) struct call *call; struct tmgw_ctrl_resp *msg; { if (call->overall_state == OVERALL_STATE_TEARDOWN) { tmgw_send_dlcx(call); return; } mncc_dtmf_stop_ok(call); call->mgw_state = MGW_STATE_COMPLETE; call->dtmf_pending_stop = 0; } void process_tmgw_response(msg) struct tmgw_ctrl_resp *msg; { struct call *call; unsigned opc; call = find_call_with_mgw_xact(msg->transact_ref); if (!call) { syslog(LOG_CRIT, "FATAL: response from TMGW xact 0x%x does not match any call", msg->transact_ref); exit(1); } opc = call->mgw_xact; call->mgw_xact = 0; switch (opc) { case TMGW_CTRL_OP_CRCX: crcx_response(call, msg); return; case TMGW_CTRL_OP_MDCX: mdcx_response(call, msg); return; case TMGW_CTRL_OP_DLCX: dlcx_response(call, msg); return; case TMGW_CTRL_OP_DTMF_START: dtmf_start_response(call, msg); return; case TMGW_CTRL_OP_DTMF_STOP: dtmf_stop_response(call, msg); return; default: syslog(LOG_CRIT, "FATAL: invalid opcode 0x%x in call->msg_xact", opc); exit(1); } }