view rtp-mgr/ctrl_prot.c @ 180:565477d07418

themwi-rtp-mgr: close file descriptors after sending them across
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 11 Mar 2023 20:41:23 -0800
parents b79d6334f543
children 3962d9345a09
line wrap: on
line source

/*
 * In this module we implement our control socket protocol.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.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/tmgw_const.h"
#include "../include/rtp_alloc.h"
#include "struct.h"
#include "select.h"

extern struct bind_range_cfg bind_range_gsm, bind_range_pstn;

static void
free_rtp_end(roe)
	struct rtp_one_end *roe;
{
	close(roe->rtp_fd);
	close(roe->rtcp_fd);
}

static void
close_fds(fd_list, num_fd)
	int *fd_list, num_fd;
{
	int i;

	for (i = 0; i < num_fd; i++)
		close(fd_list[i]);
}

void
ctrl_message_handler(fd)
{
	struct rtp_alloc_req req;
	struct rtp_alloc_resp resp;
	struct rtp_one_end rtp_gsm, rtp_pstn;
	struct iovec iov;
	struct msghdr msg;
	int fd_out[4], num_fd, *fd_bufptr;
	union {
		char buf[CMSG_SPACE(sizeof fd_out)];
		struct cmsghdr align;
	} cmsgu;
	struct cmsghdr *cmsg;
	int rc;

	/* receive request */
	rc = recv(fd, &req, sizeof req, 0);
	if (rc < sizeof req) {
		syslog(LOG_DEBUG, "ctrl connection closing");
		close(fd);
		FD_CLR(fd, &select_for_read);
		return;
	}
	/* start preparing response */
	bzero(&resp, sizeof resp);
	resp.transact_ref = req.transact_ref;
	switch (req.ep_type) {
	case TMGW_EP_TYPE_DUMMY_GSM:
	case TMGW_EP_TYPE_DUMMY_PSTN:
	case TMGW_EP_TYPE_GATEWAY:
		break;
	default:
		resp.res = RTP_ALLOC_ERR_PARAM;
error_resp:	send(fd, &resp, sizeof resp, 0);
		return;
	}
	/* allocate resources */
	if (req.ep_type & TMGW_EP_HAS_GSM_SOCK) {
		rc = get_rtp_port_pair(&rtp_gsm, &bind_range_gsm);
		if (rc < 0) {
			syslog(LOG_ERR,
				"unable to get local port pair on GSM side");
			resp.res = RTP_ALLOC_ERR_RSRC;
			goto error_resp;
		}
	}
	if (req.ep_type & TMGW_EP_HAS_PSTN_SOCK) {
		rc = get_rtp_port_pair(&rtp_pstn, &bind_range_pstn);
		if (rc < 0) {
			syslog(LOG_ERR,
				"unable to get local port pair on PSTN side");
			if (req.ep_type & TMGW_EP_HAS_GSM_SOCK)
				free_rtp_end(&rtp_gsm);
			resp.res = RTP_ALLOC_ERR_RSRC;
			goto error_resp;
		}
	}
	/* finish ordinary body of response */
	resp.res = RTP_ALLOC_OK;
	if (req.ep_type & TMGW_EP_HAS_GSM_SOCK)
		bcopy(&rtp_gsm.bound_addr, &resp.gsm_addr,
			sizeof(struct sockaddr_in));
	if (req.ep_type & TMGW_EP_HAS_PSTN_SOCK)
		bcopy(&rtp_pstn.bound_addr, &resp.pstn_addr,
			sizeof(struct sockaddr_in));
	iov.iov_base = &resp;
	iov.iov_len = sizeof resp;
	/* file descriptor passing voodoo */
	switch (req.ep_type) {
	case TMGW_EP_TYPE_DUMMY_GSM:
		num_fd = 2;
		fd_out[0] = rtp_gsm.rtp_fd;
		fd_out[1] = rtp_gsm.rtcp_fd;
		break;
	case TMGW_EP_TYPE_DUMMY_PSTN:
		num_fd = 2;
		fd_out[0] = rtp_pstn.rtp_fd;
		fd_out[1] = rtp_pstn.rtcp_fd;
		break;
	case TMGW_EP_TYPE_GATEWAY:
		num_fd = 4;
		fd_out[0] = rtp_gsm.rtp_fd;
		fd_out[1] = rtp_gsm.rtcp_fd;
		fd_out[2] = rtp_pstn.rtp_fd;
		fd_out[3] = rtp_pstn.rtcp_fd;
	}
	bzero(&msg, sizeof msg);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = cmsgu.buf;
	msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fd);
	cmsg = CMSG_FIRSTHDR(&msg);
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fd);
	fd_bufptr = (int *) CMSG_DATA(cmsg);
	bcopy(fd_out, fd_bufptr, sizeof(int) * num_fd);
	sendmsg(fd, &msg, 0);
	close_fds(fd_out, num_fd);
}