view mgw/crcx.c @ 97:9aed16c30622

mgw p2g: set M bit when restarting forwarding after no-forward
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 25 Sep 2022 20:05:02 -0800
parents 020ba624bdd8
children 738be11ac432
line wrap: on
line source

/*
 * In this module we implement our CRCX operation.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include <unistd.h>
#include "../include/tmgw_ctrl.h"
#include "../include/tmgw_const.h"
#include "struct.h"
#include "select.h"

extern struct endpoint *find_ep_by_id();
extern void udp_sink_rcvr();

extern struct bind_range_cfg bind_range_gsm, bind_range_pstn;

static unsigned
get_new_ep_id(conn)
	struct ctrl_conn *conn;
{
	unsigned id;

	for (;;) {
		id = conn->next_ep_id++;
		if (!find_ep_by_id(conn, id))
			return id;
	}
}

static int
get_local_port_pair(ep, roe, brc)
	struct endpoint *ep;
	struct rtp_one_end *roe;
	struct bind_range_cfg *brc;
{
	struct sockaddr_in sin;
	unsigned tries, rtp_port;
	int rc;

	sin.sin_family = AF_INET;
	sin.sin_addr = brc->bind_ip;
	for (tries = brc->port_tries; tries; tries--) {
		rtp_port = brc->port_next;
		brc->port_next += 2;
		if (brc->port_next >= brc->port_range_end)
			brc->port_next = brc->port_range_start;
		sin.sin_port = htons(rtp_port);
		roe->rtp_fd = socket(AF_INET, SOCK_DGRAM, 0);
		if (roe->rtp_fd < 0) {
			syslog(LOG_CRIT, "socket(AF_INET, SOCK_DGRAM, 0): %m");
			return(-1);
		}
		rc = bind(roe->rtp_fd, (struct sockaddr *) &sin, sizeof sin);
		if (rc < 0) {
			close(roe->rtp_fd);
			continue;
		}
		bcopy(&sin, &roe->bound_addr, sizeof(struct sockaddr_in));
		sin.sin_port = htons(rtp_port+1);
		roe->rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0);
		if (roe->rtcp_fd < 0) {
			syslog(LOG_CRIT, "socket(AF_INET, SOCK_DGRAM, 0): %m");
			close(roe->rtp_fd);
			return(-1);
		}
		rc = bind(roe->rtcp_fd, (struct sockaddr *) &sin, sizeof sin);
		if (rc < 0) {
			close(roe->rtp_fd);
			close(roe->rtcp_fd);
			continue;
		}
		/* all good - make the file descriptors live for select */
		update_max_fd(roe->rtp_fd);
		FD_SET(roe->rtp_fd, &select_for_read);
		select_handlers[roe->rtp_fd] = udp_sink_rcvr;
		select_data[roe->rtp_fd] = (void *) ep;
		update_max_fd(roe->rtcp_fd);
		FD_SET(roe->rtcp_fd, &select_for_read);
		select_handlers[roe->rtcp_fd] = udp_sink_rcvr;
		select_data[roe->rtcp_fd] = (void *) ep;
		return(0);
	}
	/* couldn't find a free port pair */
	return(-1);
}

void
process_crcx(conn, req, resp)
	struct ctrl_conn *conn;
	struct tmgw_ctrl_req *req;
	struct tmgw_ctrl_resp *resp;
{
	struct endpoint *ep;
	int rc;

	/* ep_id in request encodes ep_type */
	switch (req->ep_id) {
	case TMGW_EP_TYPE_DUMMY_GSM:
	case TMGW_EP_TYPE_DUMMY_PSTN:
	case TMGW_EP_TYPE_GATEWAY:
		break;
	default:
		resp->res = TMGW_RESP_ERR_PARAM;
		return;
	}
	ep = malloc(sizeof(struct endpoint));
	if (!ep) {
		syslog(LOG_CRIT, "malloc for endpoint: %m");
		resp->res = TMGW_RESP_ERR_RSRC;
		return;
	}
	bzero(ep, sizeof(struct endpoint));
	ep->ep_type = req->ep_id;
	ep->ep_id = get_new_ep_id(conn);
	if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK) {
		rc = get_local_port_pair(ep, &ep->rtp_gsm, &bind_range_gsm);
		if (rc < 0) {
			syslog(LOG_ERR,
				"unable to get local port pair on GSM side");
			free(ep);
			resp->res = TMGW_RESP_ERR_RSRC;
			return;
		}
	}
	if (ep->ep_type & TMGW_EP_HAS_PSTN_SOCK) {
		rc = get_local_port_pair(ep, &ep->rtp_pstn, &bind_range_pstn);
		if (rc < 0) {
			syslog(LOG_ERR,
				"unable to get local port pair on PSTN side");
			if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK)
				free_rtp_end(&ep->rtp_gsm);
			free(ep);
			resp->res = TMGW_RESP_ERR_RSRC;
			return;
		}
	}
	rc = mdcx_operation(ep, req, resp);
	if (rc < 0) {
		if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK)
			free_rtp_end(&ep->rtp_gsm);
		if (ep->ep_type & TMGW_EP_HAS_PSTN_SOCK)
			free_rtp_end(&ep->rtp_pstn);
		free(ep);
		return;
	}
	/* all good - accept the new endpoint and return OK */
	ep->next = conn->endp_list;
	conn->endp_list = ep;
	resp->res = TMGW_RESP_OK;
	resp->ep_id = ep->ep_id;
	bcopy(&ep->rtp_gsm.bound_addr, &resp->gsm_addr,
		sizeof(struct sockaddr_in));
	bcopy(&ep->rtp_pstn.bound_addr, &resp->pstn_addr,
		sizeof(struct sockaddr_in));
	syslog(LOG_INFO, "CRCX endpoint type %u id %u", ep->ep_type, ep->ep_id);
}