FreeCalypso > hg > themwi-system-sw
diff sip-in/mgw_resp.c @ 151:0ecbc3dc8f93
sip-in: split mgw_resp.c from mgw_ops.c
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 11 Oct 2022 15:58:42 -0800 |
parents | sip-in/mgw_ops.c@e499e8db8b82 |
children | 7176dc850d7a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/mgw_resp.c Tue Oct 11 15:58:42 2022 -0800 @@ -0,0 +1,290 @@ +/* + * 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/mncc.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 struct gsm_mncc_cause mgw_hold_retrieve_error = { + .coding = GSM48_CAUSE_CODING_GSM, + .location = GSM48_CAUSE_LOC_PRN_S_LU, + .value = GSM48_CC_CAUSE_NETWORK_OOO, +}; + +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); + disconnect_sip(call, &mgw_hold_retrieve_error); + } +} + +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); + disconnect_sip(call, &mgw_hold_retrieve_error); + } +} + +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); + } +}