view utils/sip-out-test.c @ 112:6aa63cf4620a

sip-in call clearing: select timeout implemented
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 28 Sep 2022 18:59:55 -0800
parents ffb563a17f23
children
line wrap: on
line source

/*
 * This program is a contraption for testing manually constructed
 * outgoing SIP calls to BulkVS.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>

#define	MAX_SIP_TX_PACKET	1472

static struct in_addr local_ip, remote_ip;
static unsigned local_sip_port, local_rtp_port, remote_port;
static char *invite_filename, *log_filename;
static char invite_packet[MAX_SIP_TX_PACKET];
static unsigned invite_packet_len;
static FILE *logF;
static struct timeval curtime;

static void
read_invite_file()
{
	FILE *inf;
	char linebuf[128], *cp, *dp;
	int lineno;
	unsigned size_accum, linelen;

	inf = fopen(invite_filename, "r");
	if (!inf) {
		perror(invite_filename);
		exit(1);
	}
	size_accum = 0;
	dp = invite_packet;
	for (lineno = 1; fgets(linebuf, sizeof(linebuf), inf); lineno++) {
		cp = index(linebuf, '\n');
		if (!cp) {
			fprintf(stderr,
				"%s line %d: too long or missing newline\n",
				invite_filename, lineno);
			exit(1);
		}
		*cp = '\0';
		linelen = cp - linebuf;
		if (size_accum + linelen + 2 > MAX_SIP_TX_PACKET) {
			fprintf(stderr, "%s line %d: packet overflow\n",
				invite_filename, lineno);
			exit(1);
		}
		bcopy(linebuf, dp, linelen);
		dp += linelen;
		*dp++ = '\r';
		*dp++ = '\n';
		size_accum += linelen + 2;
	}
	fclose(inf);
	if (!size_accum) {
		fprintf(stderr, "error: %s is empty\n", invite_filename);
		exit(1);
	}
	invite_packet_len = size_accum;
}

static void
log_common(msg, msglen, sin, dir, outf)
	char *msg, *dir;
	unsigned msglen;
	struct sockaddr_in *sin;
	FILE *outf;
{
	unsigned sec, ms;

	sec = curtime.tv_sec % 86400;
	ms = curtime.tv_usec / 1000;
	fprintf(outf, "Msg %s %s:%u %u bytes %02u:%02u:%02u.%03u\n", dir,
		inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), msglen,
		sec / 3600, (sec / 60) % 60, sec % 60, ms);
	fwrite(msg, 1, msglen, outf);
	putc('\n', outf);
	fflush(outf);
}

static void
log_sip_msg_rx(msg, msglen, sin)
	char *msg;
	unsigned msglen;
	struct sockaddr_in *sin;
{
	log_common(msg, msglen, sin, "from", stdout);
	if (logF)
		log_common(msg, msglen, sin, "from", logF);
}

static void
log_sip_msg_tx(msg, msglen, sin)
	char *msg;
	unsigned msglen;
	struct sockaddr_in *sin;
{
	log_common(msg, msglen, sin, "to", stdout);
	if (logF)
		log_common(msg, msglen, sin, "to", logF);
}

main(argc, argv)
	char **argv;
{
	struct sockaddr_in sin_local, sin_rtp, sin_rtcp, sin_remote, sin_rx;
	int sock_sip, sock_rtp, sock_rtcp, max_fd;
	socklen_t addrlen;
	fd_set fds;
	char recv_buf[4096];
	int rc;

	/* grok command line arguments */
	if (argc < 7 || argc > 8) {
		fprintf(stderr,
"usage: %s local-ip local-sip local-rtp remote-ip remote-sip inv-file [logfile]\n",
			argv[0]);
		exit(1);
	}
	local_ip.s_addr = inet_addr(argv[1]);
	if (local_ip.s_addr == INADDR_NONE) {
		fprintf(stderr, "error: invalid IP address \"%s\"\n", argv[1]);
		exit(1);
	}
	local_sip_port = atoi(argv[2]);
	local_rtp_port = atoi(argv[3]);
	remote_ip.s_addr = inet_addr(argv[4]);
	if (remote_ip.s_addr == INADDR_NONE) {
		fprintf(stderr, "error: invalid IP address \"%s\"\n", argv[4]);
		exit(1);
	}
	remote_port = atoi(argv[5]);
	invite_filename = argv[6];
	log_filename = argv[7];
	/* fill sin structures */
	sin_local.sin_family = AF_INET;
	sin_local.sin_addr = local_ip;
	sin_local.sin_port = htons(local_sip_port);
	sin_rtp.sin_family = AF_INET;
	sin_rtp.sin_addr = local_ip;
	sin_rtp.sin_port = htons(local_rtp_port);
	sin_rtcp.sin_family = AF_INET;
	sin_rtcp.sin_addr = local_ip;
	sin_rtcp.sin_port = htons(local_rtp_port+1);
	sin_remote.sin_family = AF_INET;
	sin_remote.sin_addr = remote_ip;
	sin_remote.sin_port = htons(remote_port);
	/* create and bind sockets */
	sock_sip = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_sip < 0) {
		perror("socket");
		exit(1);
	}
	rc = bind(sock_sip, (struct sockaddr *) &sin_local,
		  sizeof(struct sockaddr_in));
	if (rc < 0) {
		perror("bind");
		exit(1);
	}
	sock_rtp = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_rtp < 0) {
		perror("socket");
		exit(1);
	}
	rc = bind(sock_rtp, (struct sockaddr *) &sin_rtp,
		  sizeof(struct sockaddr_in));
	if (rc < 0) {
		perror("bind");
		exit(1);
	}
	sock_rtcp = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_rtcp < 0) {
		perror("socket");
		exit(1);
	}
	rc = bind(sock_rtcp, (struct sockaddr *) &sin_rtcp,
		  sizeof(struct sockaddr_in));
	if (rc < 0) {
		perror("bind");
		exit(1);
	}
	/* read the INVITE packet */
	read_invite_file();
	/* open the log file, if we have one */
	if (log_filename) {
		logF = fopen(log_filename, "a");
		if (!logF) {
			perror(log_filename);
			exit(1);
		}
	}
	/* now get down to business */
	max_fd = sock_sip;
	if (sock_rtp > max_fd)
		max_fd = sock_rtp;
	if (sock_rtcp > max_fd)
		max_fd = sock_rtcp;
	addrlen = sizeof(struct sockaddr_in);
	rc = sendto(sock_sip, invite_packet, invite_packet_len, 0,
			(struct sockaddr *) &sin_remote, addrlen);
	if (rc < 0) {
		perror("sendto");
		exit(1);
	}
	gettimeofday(&curtime, 0);
	log_sip_msg_tx(invite_packet, invite_packet_len, &sin_remote);
	/* main select loop */
	for (;;) {
		FD_ZERO(&fds);
		FD_SET(sock_sip, &fds);
		FD_SET(sock_rtp, &fds);
		FD_SET(sock_rtcp, &fds);
		rc = select(max_fd+1, &fds, 0, 0, 0);
		if (rc < 0) {
			if (errno == EINTR)
				continue;
			perror("select");
			exit(1);
		}
		gettimeofday(&curtime, 0);
		if (FD_ISSET(sock_sip, &fds)) {
			addrlen = sizeof(struct sockaddr_in);
			rc = recvfrom(sock_sip, recv_buf, sizeof recv_buf, 0,
					(struct sockaddr *) &sin_rx, &addrlen);
			if (rc < 0) {
				perror("recvfrom");
				exit(1);
			}
			log_sip_msg_rx(recv_buf, rc, &sin_rx);
		}
		if (FD_ISSET(sock_rtp, &fds)) {
			addrlen = sizeof(struct sockaddr_in);
			rc = recvfrom(sock_rtp, recv_buf, sizeof recv_buf, 0,
					(struct sockaddr *) &sin_rx, &addrlen);
			if (rc < 0) {
				perror("recvfrom");
				exit(1);
			}
		}
		if (FD_ISSET(sock_rtcp, &fds)) {
			addrlen = sizeof(struct sockaddr_in);
			rc = recvfrom(sock_rtp, recv_buf, sizeof recv_buf, 0,
					(struct sockaddr *) &sin_rx, &addrlen);
			if (rc < 0) {
				perror("recvfrom");
				exit(1);
			}
		}
	}
}