diff mgw/crcx.c @ 32:b3f74df7b808

beginning of themwi-mgw
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 09 Jul 2022 22:51:44 -0800
parents
children 7dae2bae56a1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mgw/crcx.c	Sat Jul 09 22:51:44 2022 -0800
@@ -0,0 +1,164 @@
+/*
+ * 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 <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_PROT;
+		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);
+}