view sip-out/mncc_sock.c @ 275:def9f6e4f49e default tip

doc/Use-outside-USA: Fake-NANP-numbers article is here
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 27 Nov 2023 21:49:19 -0800
parents e54b0a9e322f
children
line wrap: on
line source

/*
 * In this module we implement the MNCC socket interface to themwi-sip-out.
 * We have an outcall socket on which we accept connections, and each
 * accepted connection becomes a struct mncc_conn for us.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.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 <unistd.h>
#include "../include/mncc.h"
#include "../include/out_routes.h"
#include "call.h"

static char outcall_socket_pathname[] = "/var/gsm/outcall_socket";

int mncc_listener;
struct mncc_conn *mncc_conn_list;

create_outcall_socket()
{
	struct sockaddr_un sa;
	unsigned sa_len;
	int rc;

	mncc_listener = socket(AF_UNIX, SOCK_SEQPACKET, 0);
	if (mncc_listener < 0) {
		syslog(LOG_CRIT, "socket(AF_UNIX, SOCK_SEQPACKET, 0): %m");
		return(-1);
	}
	unlink(outcall_socket_pathname);
	fill_sockaddr_un(outcall_socket_pathname, &sa, &sa_len);
	rc = bind(mncc_listener, (struct sockaddr *) &sa, sa_len);
	if (rc < 0) {
		syslog(LOG_ERR, "bind to %s: %m", outcall_socket_pathname);
		return(-1);
	}
	rc = listen(mncc_listener, 3);
	if (rc < 0) {
		syslog(LOG_CRIT, "listen on UNIX socket: %m");
		return(-1);
	}
	chmod(outcall_socket_pathname, 0775);
	update_max_fd(mncc_listener);
	return(0);
}

void
mncc_listener_select()
{
	struct sockaddr_un sa;
	socklen_t sa_len;
	int fd;
	struct mncc_conn *conn;

	sa_len = sizeof sa;
	fd = accept(mncc_listener, (struct sockaddr *) &sa, &sa_len);
	if (fd < 0) {
		syslog(LOG_CRIT, "accept on UNIX socket: %m");
		exit(1);
	}
	conn = malloc(sizeof(struct mncc_conn));
	if (!conn) {
		syslog(LOG_CRIT, "malloc for outcall socket conn: %m");
		close(fd);
		return;
	}
	syslog(LOG_INFO, "new outcall socket connection");
	conn->fd = fd;
	conn->next = mncc_conn_list;
	mncc_conn_list = conn;
	update_max_fd(fd);
}

static void
dispatch_mncc_msg(mncc, msg, msglen)
	struct mncc_conn *mncc;
	union mncc_msg *msg;
	unsigned msglen;
{
	switch (msg->msg_type) {
	case MNCC_SETUP_IND:
		handle_setup_ind(mncc, msg, msglen);
		return;
	case MNCC_SETUP_COMPL_IND:
	case MNCC_NOTIFY_IND:
	case MNCC_DISC_IND:
	case MNCC_FACILITY_IND:
	case MNCC_START_DTMF_IND:
	case MNCC_STOP_DTMF_IND:
	case MNCC_MODIFY_IND:
	case MNCC_HOLD_IND:
	case MNCC_RETRIEVE_IND:
	case MNCC_USERINFO_IND:
	case MNCC_REL_IND:
	case MNCC_REL_CNF:
		handle_mncc_signal(mncc, msg, msglen);
		return;
	case MNCC_RTP_CREATE:
		handle_rtp_create(mncc, msg, msglen);
		return;
	case MNCC_RTP_CONNECT:
		syslog(LOG_ERR, "MNCC_RTP_CONNECT error from OsmoMSC");
		return;
	case MNCC_RTP_FREE:
		syslog(LOG_ERR, "MNCC_RTP_FREE bogon from OsmoMSC");
		return;
	default:
		syslog(LOG_CRIT,
			"FATAL: received unexpected MNCC message type 0x%x",
			msg->msg_type);
		exit(1);
	}
}

void
mncc_socket_select(conn)
	struct mncc_conn *conn;
{
	union mncc_msg msg;
	int rc;

	rc = recv(conn->fd, &msg, sizeof msg, 0);
	if (rc <= 0) {
		syslog(LOG_ERR, "outcall socket disconnected");
		close(conn->fd);
		conn->fd = -1;
		shutdown_mncc_socket(conn);
		return;
	}
	if (rc < 4) {
		syslog(LOG_CRIT, "short read from MNCC socket: %d bytes", rc);
		exit(1);
	}
	dispatch_mncc_msg(conn, &msg, rc);
}

send_mncc_to_sock(mncc, msg, msglen)
	struct mncc_conn *mncc;
	union mncc_msg *msg;
	unsigned msglen;
{
	return send(mncc->fd, msg, msglen, 0);
}