changeset 40:77d980126efd

libsip started with primary parsing function
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 04 Sep 2022 16:33:31 -0800
parents 64b9f0f90726
children e57bc4c885a7
files libsip/Makefile libsip/parse.h libsip/primary_parse.c
diffstat 3 files changed, 197 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libsip/Makefile	Sun Sep 04 16:33:31 2022 -0800
@@ -0,0 +1,13 @@
+CC=	gcc
+CFLAGS=	-O2
+OBJS=	primary_parse.o
+LIB=	libsip.a
+
+all:	${LIB}
+
+${LIB}:	${OBJS}
+	ar rcu $@ ${OBJS}
+	ranlib $@
+
+clean:
+	rm -f *.[oa] errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libsip/parse.h	Sun Sep 04 16:33:31 2022 -0800
@@ -0,0 +1,33 @@
+/*
+ * Here we define the structure we are going to use for receiving
+ * and parsing SIP UDP packets.
+ */
+
+#define	MAX_SIP_RX_PACKET	3072
+#define	MAX_HEADER_FIELDS	64
+
+struct sip_parse_hdr {
+	char	*field_name;
+	char	*field_value;
+};
+
+struct sip_pkt_rx {
+	/* recvfrom on UDP socket, input to parser */
+	char		pkt_buffer[MAX_SIP_RX_PACKET];
+	unsigned	pkt_length;
+	/* filled by parser */
+	int		parse_msgtype;
+	char		*req_method;
+	char		*req_uri;
+	unsigned	status_code;
+	char		*status_str;
+	/* header fields */
+	struct sip_parse_hdr hdr_fields[MAX_HEADER_FIELDS];
+	unsigned	num_hdr_fields;
+	/* optional message body */
+	char		*msg_body;
+	unsigned	msg_body_len;
+};
+
+#define	SIP_MSG_TYPE_REQ	1
+#define	SIP_MSG_TYPE_RESP	2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libsip/primary_parse.c	Sun Sep 04 16:33:31 2022 -0800
@@ -0,0 +1,151 @@
+/*
+ * 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 (strncmp(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 (strcmp(cp, "SIP/2.0"))
+		return(0);
+	else
+		return(1);
+}
+
+parse_incoming_sip_msg(msg)
+	struct sip_pkt_rx *msg;
+{
+	char *msg_end = msg->pkt_buffer + msg->pkt_length;
+	char *cp, *endp, *nextp;
+	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);
+		while (cp < endp && isspace(*cp))
+			cp++;
+		msg->hdr_fields[hdr_cnt++].field_value = 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';
+	}
+	msg->num_hdr_fields = hdr_cnt;
+	msg->msg_body = nextp;
+	msg->msg_body_len = msg_end - nextp;
+	return(0);
+}