view mncc/extsock.c @ 124:7e04d28fae8b

sip-in: default use-100rel to no BulkVS servers act badly when we send a reliable 180 Ringing response to an incoming call, even though they advertise 100rel support in the Supported header in the INVITE packet, and we probably won't be implementing 100rel for outbound because doing per-the-spec PRACK as a UAC is just too burdensome. Therefore, we need to consider 100rel extension as not-really-supported in themwi-system-sw.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 01 Oct 2022 15:54:50 -0800
parents 660126bd5f59
children
line wrap: on
line source

/*
 * 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);
}