diff mncc/extsock.c @ 2:053f04687106

mncc: initial import from old ThemWi
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 08 Jun 2024 23:12:12 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mncc/extsock.c	Sat Jun 08 23:12:12 2024 +0000
@@ -0,0 +1,243 @@
+/*
+ * In this module we gather functions that deal with external
+ * socket connections, both externally-originating MT calls
+ * and outbound MO calls.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include "../include/mncc.h"
+#include "../include/gsm48_const.h"
+#include "struct.h"
+#include "gsm_call.h"
+
+extern char *mncc_msg_name();
+
+void
+extsock_dec_refcount(conn)
+	struct socket_conn *conn;
+{
+	if (!conn->ncalls) {
+		syslog(LOG_CRIT, "FATAL BUG: ncalls=0 on socket call clearing");
+		exit(1);
+	}
+	conn->ncalls--;
+}
+
+static void
+send_rel_on_broken_socket(call)
+	struct gsm_call *call;
+{
+	struct gsm_mncc msg;
+
+	bzero(&msg, sizeof(struct gsm_mncc));
+	msg.msg_type = MNCC_REL_REQ;
+	msg.callref = call->callref;
+	mncc_set_cause(&msg, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_DEST_OOO);
+	send_mncc_to_gsm(&msg, sizeof(struct gsm_mncc));
+}
+
+static void
+broken_socket_clear_calls(conn)
+	struct socket_conn *conn;
+{
+	extern struct gsm_call *call_list_head;
+	struct gsm_call *call;
+
+	for (call = call_list_head; call; call = call->next) {
+		if (call->gc_flag)
+			continue;
+		if (call->socket == conn) {
+			syslog(LOG_WARNING,
+	"clearing broken socket call: GSM callref 0x%x, socket ref 0x%x",
+				call->callref, call->socket_ref);
+			send_rel_on_broken_socket(call);
+			extsock_dec_refcount(conn);
+			call->gc_flag = 1;
+		}
+	}
+	if (conn->ncalls) {
+		syslog(LOG_CRIT,
+		    "FATAL BUG: ncalls!=0 after broken socket call clearing");
+		exit(1);
+	}
+}
+
+static void
+report_runt(msg)
+	union mncc_msg *msg;
+{
+	syslog(LOG_CRIT,
+		"MNCC message type 0x%x from ThemWi call socket is too short!",
+		msg->msg_type);
+}
+
+static void
+handle_setup_req(conn, msg, msglen)
+	struct socket_conn *conn;
+	struct gsm_mncc *msg;
+	unsigned msglen;
+{
+	struct gsm_call *call;
+
+	if (msglen < sizeof(struct gsm_mncc)) {
+		report_runt(msg);
+		return;
+	}
+	syslog(LOG_DEBUG, "Rx MNCC_SETUP_REQ from socket, callref=0x%x",
+		msg->callref);
+	call = find_socket_call(conn, msg->callref);
+	if (call) {
+		syslog(LOG_ERR,
+			"duplicate MNCC_SETUP_REQ from socket for callref 0x%x",
+			msg->callref);
+		/* drop it like OsmoMSC's mncc_builtin does */
+		return;
+	}
+	/* further processing */
+	process_ext_mtcall_setup(conn, msg);
+}
+
+static void
+handle_signaling_msg(conn, msg, msglen)
+	struct socket_conn *conn;
+	struct gsm_mncc *msg;
+	unsigned msglen;
+{
+	struct gsm_call *call;
+
+	if (msglen < sizeof(struct gsm_mncc)) {
+		report_runt(msg);
+		return;
+	}
+	syslog(LOG_DEBUG, "Rx %s from socket, callref=0x%x",
+		mncc_msg_name(msg->msg_type), msg->callref);
+	call = find_socket_call(conn, msg->callref);
+	if (!call) {
+		syslog(LOG_ERR,
+		"MNCC message from ThemWi call socket: callref 0x%x not found",
+			msg->callref);
+		/* drop it like OsmoMSC's mncc_builtin does */
+		return;
+	}
+	/* forward to GSM MNCC interface */
+	msg->callref = call->callref;
+	send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
+	if (msg->msg_type == MNCC_REJ_REQ) {
+		extsock_dec_refcount(conn);
+		call->gc_flag = 1;
+	}
+}
+
+static void
+handle_rtp_msg(conn, msg, msglen)
+	struct socket_conn *conn;
+	struct gsm_mncc_rtp *msg;
+	unsigned msglen;
+{
+	struct gsm_call *call;
+
+	if (msglen < sizeof(struct gsm_mncc_rtp)) {
+		report_runt(msg);
+		return;
+	}
+	syslog(LOG_DEBUG, "Rx %s from socket, callref=0x%x",
+		mncc_msg_name(msg->msg_type), msg->callref);
+	call = find_socket_call(conn, msg->callref);
+	if (!call) {
+		syslog(LOG_ERR,
+		"MNCC message from ThemWi call socket: callref 0x%x not found",
+			msg->callref);
+		/* drop it like OsmoMSC's mncc_builtin does */
+		return;
+	}
+	/* forward to GSM MNCC interface */
+	msg->callref = call->callref;
+	send_mncc_to_gsm(msg, sizeof(struct gsm_mncc_rtp));
+}
+
+void
+extsock_read_select(conn)
+	struct socket_conn *conn;
+{
+	union mncc_msg msg;
+	int rc;
+
+	rc = recv(conn->fd, &msg, sizeof msg, 0);
+	if (rc < 4) {
+		if (conn->ncalls) {
+			syslog(LOG_ERR, "ext socket broken with calls present");
+			broken_socket_clear_calls(conn);
+		} else
+			syslog(LOG_INFO, "normal closing of ext socket");
+		close(conn->fd);
+		conn->fd = -1;
+		return;
+	}
+	switch (msg.msg_type) {
+	case MNCC_SETUP_REQ:
+		handle_setup_req(conn, &msg, rc);
+		return;
+	case MNCC_SETUP_RSP:
+	case MNCC_SETUP_COMPL_REQ:
+	case MNCC_CALL_PROC_REQ:
+	case MNCC_PROGRESS_REQ:
+	case MNCC_ALERT_REQ:
+	case MNCC_NOTIFY_REQ:
+	case MNCC_DISC_REQ:
+	case MNCC_REL_REQ:
+	case MNCC_FACILITY_REQ:
+	case MNCC_START_DTMF_RSP:
+	case MNCC_START_DTMF_REJ:
+	case MNCC_STOP_DTMF_RSP:
+	case MNCC_MODIFY_REQ:
+	case MNCC_MODIFY_RSP:
+	case MNCC_MODIFY_REJ:
+	case MNCC_HOLD_CNF:
+	case MNCC_HOLD_REJ:
+	case MNCC_RETRIEVE_CNF:
+	case MNCC_RETRIEVE_REJ:
+	case MNCC_USERINFO_REQ:
+	case MNCC_REJ_REQ:
+		handle_signaling_msg(conn, &msg, rc);
+		return;
+	case MNCC_RTP_CREATE:
+	case MNCC_RTP_CONNECT:
+	case MNCC_RTP_FREE:
+		handle_rtp_msg(conn, &msg, rc);
+		return;
+	default:
+		syslog(LOG_CRIT,
+		    "unknown MNCC message type 0x%x from ThemWi call socket",
+			msg.msg_type);
+	}
+}
+
+mncc_signal_to_socket(call, msg)
+	struct gsm_call *call;
+	struct gsm_mncc *msg;
+{
+	msg->callref = call->socket_ref;
+	return send(call->socket->fd, msg, sizeof(struct gsm_mncc), 0);
+}
+
+mncc_signal_to_socket_nocall(conn, msg)
+	struct socket_conn *conn;
+	struct gsm_mncc *msg;
+{
+	return send(conn->fd, msg, sizeof(struct gsm_mncc), 0);
+}
+
+mncc_rtp_to_socket(call, msg)
+	struct gsm_call *call;
+	struct gsm_mncc_rtp *msg;
+{
+	msg->callref = call->socket_ref;
+	return send(call->socket->fd, msg, sizeof(struct gsm_mncc_rtp), 0);
+}