view libsip/primary_parse.c @ 8:eaf0e8f81a22

test-fsk: don't feed RTP to modem Rx during ringing
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 06 Mar 2024 21:33:49 -0800
parents 35c0d9f03c0a
children
line wrap: on
line source

/*
 * In this module we are going to implement the first stage of
 * parsing for incoming SIP UDP packets, using struct sip_pkt_rx
 * defined in parse.h.
 */

#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include "parse.h"

static
find_crlf(ptr, msg_end, endp, nextp)
	char *ptr, *msg_end, **endp, **nextp;
{
	for (;;) {
		if (ptr >= msg_end)
			return(0);
		switch (*ptr) {
		case '\0':
			return(0);
		case '\n':
			*endp = ptr;
			*nextp = ptr + 1;
			return(1);
		case '\r':
			*endp = ptr;
			ptr++;
			if (ptr >= msg_end)
				return(0);
			if (*ptr != '\n')
				return(0);
			*nextp = ptr + 1;
			return(1);
		}
		ptr++;
	}
}

static
try_status_line(msg)
	struct sip_pkt_rx *msg;
{
	if (strncasecmp(msg->pkt_buffer, "SIP/2.0 ", 8))
		return(0);
	if (!isdigit(msg->pkt_buffer[8]))
		return(0);
	if (!isdigit(msg->pkt_buffer[9]))
		return(0);
	if (!isdigit(msg->pkt_buffer[10]))
		return(0);
	if (msg->pkt_buffer[11] != ' ')
		return(0);
	msg->status_code = atoi(msg->pkt_buffer + 8);
	msg->status_str = msg->pkt_buffer + 8;
	return(1);
}

static
try_request_line(msg)
	struct sip_pkt_rx *msg;
{
	char *cp;

	cp = msg->pkt_buffer;
	if (!isupper(*cp))
		return(0);
	while (isalnum(*cp))
		cp++;
	if (*cp != ' ')
		return(0);
	msg->req_method = msg->pkt_buffer;
	*cp++ = '\0';
	msg->req_uri = cp;
	while (*cp && !isspace(*cp))
		cp++;
	if (*cp != ' ')
		return(0);
	*cp++ = '\0';
	if (strcasecmp(cp, "SIP/2.0"))
		return(0);
	else
		return(1);
}

static void
trim_trailing_spaces(sp)
	char *sp;
{
	char *ep;

	ep = index(sp, '\0');
	while (ep > sp && isspace(ep[-1]))
		ep--;
	*ep = '\0';
}

parse_incoming_sip_msg(msg)
	struct sip_pkt_rx *msg;
{
	char *msg_end = msg->pkt_buffer + msg->pkt_length;
	char *cp, *endp, *nextp, *sp;
	unsigned hdr_cnt;
	int rc;

	/* begin by isolating the Request-Line or Status-Line */
	rc = find_crlf(msg->pkt_buffer, msg_end, &endp, &nextp);
	if (!rc)
		return(-1);
	*endp = '\0';
	if (try_status_line(msg))
		msg->parse_msgtype = SIP_MSG_TYPE_RESP;
	else if (try_request_line(msg))
		msg->parse_msgtype = SIP_MSG_TYPE_REQ;
	else
		return(-1);
	/* now preparse header fields */
	cp = nextp;
	for (hdr_cnt = 0; ; ) {
		rc = find_crlf(cp, msg_end, &endp, &nextp);
		if (!rc)
			return(-1);
		if (endp == cp)		/* final CRLF? */
			break;
		if (!isalpha(*cp))
			return(-1);
		if (hdr_cnt >= MAX_HEADER_FIELDS)
			return(-2);
		msg->hdr_fields[hdr_cnt].field_name = cp;
		while (cp < endp && (isalnum(*cp) || *cp == '-'))
			cp++;
		if (cp >= endp)
			return(-1);
		if (*cp == ':')
			*cp++ = '\0';
		else if (isspace(*cp)) {
			*cp++ = '\0';
			while (cp < endp && isspace(*cp))
				cp++;
			if (cp >= endp)
				return(-1);
			if (*cp++ != ':')
				return(-1);
		} else
			return(-1);
		sp = cp;
		cp = nextp;
		while (cp < msg_end && (*cp == ' ' || *cp == '\t')) {
			rc = find_crlf(cp, msg_end, &endp, &nextp);
			if (!rc)
				return(-1);
			cp = nextp;
		}
		*endp = '\0';
		while (isspace(*sp))
			sp++;
		trim_trailing_spaces(sp);
		msg->hdr_fields[hdr_cnt++].field_value = sp;
	}
	msg->num_hdr_fields = hdr_cnt;
	msg->msg_body = nextp;
	msg->msg_body_len = msg_end - nextp;
	return(0);
}