FreeCalypso > hg > themwi-system-sw
view sip-in/mgw_ops.c @ 123:a36b731bfef9
sip-manual-out: implement sending BYE and CANCEL
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 29 Sep 2022 17:21:11 -0800 |
parents | c1c94b7fc2e2 |
children | 5685412bd6aa |
line wrap: on
line source
/* * In this module we implement all transactions from themwi-sip-in * toward 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 *call_list; struct call * find_call_with_mgw_xact(xact_id) uint32_t xact_id; { struct call *call; for (call = call_list; call; call = call->next) if (call->mgw_xact && call->mgw_xact_id == xact_id) return call; return 0; } uint32_t get_new_tmgw_xact_id() { static uint32_t next_xact_id; for (;;) { next_xact_id++; if (!find_call_with_mgw_xact(next_xact_id)) return next_xact_id; } } void tmgw_send_crcx(call) struct call *call; { struct tmgw_ctrl_req req; bzero(&req, sizeof req); req.opcode = TMGW_CTRL_OP_CRCX; req.transact_ref = get_new_tmgw_xact_id(); req.ep_id = TMGW_EP_TYPE_GATEWAY; req.setup_mask = TMGW_CTRL_MASK_PSTN_CONN; bcopy(&call->pstn_rtp_remote, &req.pstn_addr, sizeof(struct sockaddr_in)); req.pstn_payload_type = call->use_pcma ? PSTN_CODEC_PCMA : PSTN_CODEC_PCMU; send_req_to_tmgw(&req); call->mgw_xact = TMGW_CTRL_OP_CRCX; call->mgw_xact_id = req.transact_ref; } void tmgw_send_mdcx_connect(call) struct call *call; { struct tmgw_ctrl_req req; bzero(&req, sizeof req); req.opcode = TMGW_CTRL_OP_MDCX; req.transact_ref = get_new_tmgw_xact_id(); req.ep_id = call->mgw_ep_id; req.setup_mask = TMGW_CTRL_MASK_GSM_CONN | TMGW_CTRL_MASK_FWD_MODE; bcopy(&call->gsm_rtp_osmo, &req.gsm_addr, sizeof(struct sockaddr_storage)); req.gsm_payload_type = call->gsm_payload_type; req.gsm_payload_msg_type = call->gsm_payload_msg_type; req.fwd_mode = TMGW_FWD_MODE_SENDRECV; send_req_to_tmgw(&req); call->mgw_state = MGW_STATE_CONNECTING; call->mgw_xact = TMGW_CTRL_OP_MDCX; call->mgw_xact_id = req.transact_ref; } void tmgw_send_dlcx(call) struct call *call; { struct tmgw_ctrl_req req; bzero(&req, sizeof req); req.opcode = TMGW_CTRL_OP_DLCX; req.transact_ref = get_new_tmgw_xact_id(); req.ep_id = call->mgw_ep_id; send_req_to_tmgw(&req); call->mgw_state = MGW_STATE_DELETING; call->mgw_xact = TMGW_CTRL_OP_DLCX; call->mgw_xact_id = req.transact_ref; } 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_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_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_fail(call, msg); return; case OVERALL_STATE_TEARDOWN: return; default: goto bad_state; } } } 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); } 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; default: syslog(LOG_CRIT, "FATAL: invalid opcode 0x%x in call->msg_xact", opc); exit(1); } }