diff sip-out/mgw_resp.c @ 154:e54b0a9e322f

beginning of themwi-sip-out
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 11 Oct 2022 23:04:01 -0800
parents sip-in/mgw_ops.c@0ecbc3dc8f93
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sip-out/mgw_resp.c	Tue Oct 11 23:04:01 2022 -0800
@@ -0,0 +1,212 @@
+/*
+ * 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 "../include/out_routes.h"
+#include "call.h"
+
+extern struct call *find_call_with_mgw_xact();
+
+static void
+crcx_response(call, msg)
+	struct call *call;
+	struct tmgw_ctrl_resp *msg;
+{
+	int cause;
+
+	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:
+			send_rtp_connect(call);
+			start_sip_out(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:
+			call->overall_state = OVERALL_STATE_TEARDOWN;
+			switch (msg->res) {
+			case TMGW_RESP_ERR_RSRC:
+				cause = GSM48_CC_CAUSE_RESOURCE_UNAVAIL;
+				break;
+			case TMGW_RESP_ERR_NOTSUP:
+				cause = GSM48_CC_CAUSE_BEARER_CA_UNAVAIL;
+				break;
+			default:
+				cause = GSM48_CC_CAUSE_PROTO_ERR;
+			}
+			disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, cause);
+			return;
+		case OVERALL_STATE_TEARDOWN:
+			check_dead_call(call);
+			return;
+		default:
+			goto bad_state;
+		}
+	}
+}
+
+static void
+mdcx_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->overall_state = OVERALL_STATE_TEARDOWN;
+		tmgw_send_dlcx(call);
+		if (msg->res == TMGW_RESP_ERR_RSRC &&
+		    (call->mgw_state == MGW_STATE_MDCX_IBT ||
+		     call->mgw_state == MGW_STATE_MDCX_CONN))
+			disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
+		else
+			disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_NETWORK_OOO);
+		disconnect_sip(call);
+		return;
+	}
+	switch (call->mgw_state) {
+	case MGW_STATE_MDCX_IBT:
+		call->mgw_state = MGW_STATE_IBT_CONN;
+		mncc_signal_ibt_ring(call);
+		if (call->sip_state == SIP_STATE_CONNECTED)
+			tmgw_send_mdcx_connect(call, 0);
+		return;
+	case MGW_STATE_MDCX_CONN:
+		call->mgw_state = MGW_STATE_COMPLETE;
+		mncc_signal_answer_sup(call);
+		return;
+	case MGW_STATE_MDCX_HOLD:
+		call->mgw_state = MGW_STATE_HELD;
+		mncc_send_hold_ack(call);
+		return;
+	case MGW_STATE_MDCX_RETR:
+		call->mgw_state = MGW_STATE_COMPLETE;
+		mncc_send_retrieve_ack(call);
+		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;
+	check_dead_call(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);
+	}
+}