view utils/sip-rx-test.c @ 152:7176dc850d7a

sip-in hold/retr error handling: simply send BYE Because we know that the SIP state is CONNECTED at the time of any such error event, we can call initiate_bye() instead of disconnect_sip(), and thereby get rid of struct gsm_mncc_cause which will never be used in this scenario anyway.
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 11 Oct 2022 16:11:21 -0800
parents 5995660dcbac
children
line wrap: on
line source

/*
 * This test program is the next level above sip-udp-dump: it binds
 * to UDP port 5060, waits for a packet to come in, and when a SIP
 * packet does arrive (call one of the numbers from BulkVS while this
 * test program is running, to make BulkVS send SIP INVITE), it does
 * two things with the captured packet:
 *
 * 1) The captured packet is written raw into one file named on the
 *    command line;
 *
 * 2) The packet is parsed with parse_incoming_sip_msg(), and the
 *    parsed structure is written out into the other file named on
 *    the command line.
 *
 * This program is intended to serve as a unit test for the parsing
 * function.
 */

#include <sys/types.h>
#include <sys/file.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 <unistd.h>
#include "../libsip/parse.h"

static int sock;
static struct sockaddr_in sin;
static struct sip_pkt_rx pkt;

static void
save_raw_packet(filename)
	char *filename;
{
	int fd;

	fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
	if (fd < 0) {
		perror(filename);
		exit(1);
	}
	write(fd, pkt.pkt_buffer, pkt.pkt_length);
	close(fd);
}

static void
write_parse_output(filename)
	char *filename;
{
	FILE *of;
	unsigned n;

	of = fopen(filename, "w");
	if (!of) {
		perror(filename);
		exit(1);
	}
	switch (pkt.parse_msgtype) {
	case SIP_MSG_TYPE_REQ:
		fprintf(of, "Message is a request\n");
		fprintf(of, "Method: %s\n", pkt.req_method);
		fprintf(of, "Request-URI: %s\n", pkt.req_uri);
		break;
	case SIP_MSG_TYPE_RESP:
		fprintf(of, "Message is a response\n");
		fprintf(of, "Status code: %u\n", pkt.status_code);
		fprintf(of, "Status string: %s\n", pkt.status_str);
		break;
	default:
		fprintf(of, "Parsed returned unknown message type %d\n",
			pkt.parse_msgtype);
	}
	fprintf(of, "Number of header fields: %u\n", pkt.num_hdr_fields);
	for (n = 0; n < pkt.num_hdr_fields; n++) {
		fprintf(of, "Header field %u:\n", n);
		fprintf(of, "  Field name: %s\n",
			pkt.hdr_fields[n].field_name);
		fprintf(of, "  Field value: %s\n",
			pkt.hdr_fields[n].field_value);
	}
	fprintf(of, "Message body length: %u\n", pkt.msg_body_len);
	fclose(of);
}

main(argc, argv)
	char **argv;
{
	int rc;
	socklen_t addrlen;

	if (argc != 3) {
		fprintf(stderr, "usage: %s raw-file parsed-file\n", argv[0]);
		exit(1);
	}
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		perror("socket");
		exit(1);
	}
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons(5060);
	rc = bind(sock, (struct sockaddr *) &sin, sizeof sin);
	if (rc < 0) {
		perror("bind");
		exit(1);
	}
	addrlen = sizeof sin;
	rc = recvfrom(sock, pkt.pkt_buffer, MAX_SIP_RX_PACKET, 0,
			(struct sockaddr *) &sin, &addrlen);
	if (rc < 0) {
		perror("recvfrom");
		exit(1);
	}
	pkt.pkt_length = rc;
	printf("Rx from %s:%u, %u bytes\n", inet_ntoa(sin.sin_addr),
		ntohs(sin.sin_port), pkt.pkt_length);
	save_raw_packet(argv[1]);
	rc = parse_incoming_sip_msg(&pkt);
	if (rc < 0) {
		printf("Parse error: %d\n", rc);
		exit(0);
	}
	write_parse_output(argv[2]);
	exit(0);
}