xref: /titanic_44/usr/src/lib/libsip/common/sip_reass.c (revision 2c2c41837e330b002c4220a39638150db504fe0e)
140cb5e5dSvi117747 /*
240cb5e5dSvi117747  * CDDL HEADER START
340cb5e5dSvi117747  *
440cb5e5dSvi117747  * The contents of this file are subject to the terms of the
540cb5e5dSvi117747  * Common Development and Distribution License (the "License").
640cb5e5dSvi117747  * You may not use this file except in compliance with the License.
740cb5e5dSvi117747  *
840cb5e5dSvi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5dSvi117747  * or http://www.opensolaris.org/os/licensing.
1040cb5e5dSvi117747  * See the License for the specific language governing permissions
1140cb5e5dSvi117747  * and limitations under the License.
1240cb5e5dSvi117747  *
1340cb5e5dSvi117747  * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5dSvi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5dSvi117747  * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5dSvi117747  * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5dSvi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5dSvi117747  *
1940cb5e5dSvi117747  * CDDL HEADER END
2040cb5e5dSvi117747  */
2140cb5e5dSvi117747 
2240cb5e5dSvi117747 /*
23*2c2c4183Svi117747  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5dSvi117747  * Use is subject to license terms.
2540cb5e5dSvi117747  */
2640cb5e5dSvi117747 
2740cb5e5dSvi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2840cb5e5dSvi117747 
29*2c2c4183Svi117747 #include <stdlib.h>
30*2c2c4183Svi117747 #include <assert.h>
31*2c2c4183Svi117747 #include <ctype.h>
32*2c2c4183Svi117747 #include <pthread.h>
33*2c2c4183Svi117747 #include <strings.h>
34*2c2c4183Svi117747 #include <sip.h>
35*2c2c4183Svi117747 
3640cb5e5dSvi117747 #include "sip_miscdefs.h"
3740cb5e5dSvi117747 
3840cb5e5dSvi117747 /*
3940cb5e5dSvi117747  * Local version of case insensitive strstr().
4040cb5e5dSvi117747  */
4140cb5e5dSvi117747 static char *
sip_reass_strstr(const char * as1,const char * as2)4240cb5e5dSvi117747 sip_reass_strstr(const char *as1, const char *as2)
4340cb5e5dSvi117747 {
4440cb5e5dSvi117747 	const char	*s1;
4540cb5e5dSvi117747 	const char	*s2;
4640cb5e5dSvi117747 	const char	*tptr;
4740cb5e5dSvi117747 	char	c;
4840cb5e5dSvi117747 
4940cb5e5dSvi117747 	s1 = as1;
5040cb5e5dSvi117747 	s2 = as2;
5140cb5e5dSvi117747 
5240cb5e5dSvi117747 	if (s2 == NULL || *s2 == '\0')
5340cb5e5dSvi117747 		return ((char *)s1);
5440cb5e5dSvi117747 	c = *s2;
5540cb5e5dSvi117747 
5640cb5e5dSvi117747 	while (*s1)
5740cb5e5dSvi117747 		if (tolower(*s1++) == c) {
5840cb5e5dSvi117747 			tptr = s1;
5940cb5e5dSvi117747 			while ((c = *++s2) == tolower(*s1++) && c)
6040cb5e5dSvi117747 				;
6140cb5e5dSvi117747 			if (c == 0)
6240cb5e5dSvi117747 				return ((char *)tptr - 1);
6340cb5e5dSvi117747 			s1 = tptr;
6440cb5e5dSvi117747 			s2 = as2;
6540cb5e5dSvi117747 			c = *s2;
6640cb5e5dSvi117747 		}
6740cb5e5dSvi117747 
6840cb5e5dSvi117747 	return (NULL);
6940cb5e5dSvi117747 }
7040cb5e5dSvi117747 
7140cb5e5dSvi117747 /*
7240cb5e5dSvi117747  * Get the value in the content-length field and add it to the header length
7340cb5e5dSvi117747  * and return the total length. returns -1 if the length cannot be determined
7440cb5e5dSvi117747  * or if the message does not contain the entire message.
7540cb5e5dSvi117747  */
7640cb5e5dSvi117747 static int
sip_get_msglen(char * p,size_t msglen)7740cb5e5dSvi117747 sip_get_msglen(char *p, size_t msglen)
7840cb5e5dSvi117747 {
7940cb5e5dSvi117747 	int	value = 0;
8040cb5e5dSvi117747 	int 	hlen;
8140cb5e5dSvi117747 	char	*c;
8240cb5e5dSvi117747 	char	*e;
8340cb5e5dSvi117747 	int	base = 10;
8440cb5e5dSvi117747 	char	*edge;
8540cb5e5dSvi117747 	int	digits = 0;
8640cb5e5dSvi117747 
8740cb5e5dSvi117747 	edge = p + msglen;
8840cb5e5dSvi117747 	if ((c = sip_reass_strstr(p, "content-length")) == NULL)
8940cb5e5dSvi117747 		return (-1);
9040cb5e5dSvi117747 	hlen = c - p;
9140cb5e5dSvi117747 	if ((hlen +  strlen("content-length")) >= msglen)
9240cb5e5dSvi117747 		return (-1);
9340cb5e5dSvi117747 	c += strlen("content-length");
9440cb5e5dSvi117747 	e = c + 1;
9540cb5e5dSvi117747 	while (*e == ' ' || *e == ':') {
9640cb5e5dSvi117747 		e++;
9740cb5e5dSvi117747 		if (e == edge)
9840cb5e5dSvi117747 			return (-1);
9940cb5e5dSvi117747 	}
10040cb5e5dSvi117747 	while (*e  != '\r' && *e != ' ') {
10140cb5e5dSvi117747 		if (e == edge)
10240cb5e5dSvi117747 			return (-1);
10340cb5e5dSvi117747 		if (*e >= '0' && *e <= '9')
10440cb5e5dSvi117747 			digits = *e - '0';
10540cb5e5dSvi117747 		else
10640cb5e5dSvi117747 			return (-1);
10740cb5e5dSvi117747 		value = (value * base) + digits;
10840cb5e5dSvi117747 		e++;
10940cb5e5dSvi117747 	}
11040cb5e5dSvi117747 	while (*e != '\r') {
11140cb5e5dSvi117747 		e++;
11240cb5e5dSvi117747 		if (e == edge)
11340cb5e5dSvi117747 			return (-1);
11440cb5e5dSvi117747 	}
11540cb5e5dSvi117747 	hlen = e - p + 4;	/* 4 for 2 CRLFs ?? */
11640cb5e5dSvi117747 	value += hlen;
11740cb5e5dSvi117747 
11840cb5e5dSvi117747 	return (value);
11940cb5e5dSvi117747 }
12040cb5e5dSvi117747 
12140cb5e5dSvi117747 /*
12240cb5e5dSvi117747  * We have determined that msg does not contain a *single* complete message.
12340cb5e5dSvi117747  * Add it to the reassembly list and check if we have a complete message.
12440cb5e5dSvi117747  * a NULL 'msg' means we are just checking if there are more complete
12540cb5e5dSvi117747  * messages in the list that can be passed up.
12640cb5e5dSvi117747  */
12740cb5e5dSvi117747 char *
sip_get_tcp_msg(sip_conn_object_t obj,char * msg,size_t * msglen)12840cb5e5dSvi117747 sip_get_tcp_msg(sip_conn_object_t obj, char *msg, size_t *msglen)
12940cb5e5dSvi117747 {
13040cb5e5dSvi117747 	int			value;
13140cb5e5dSvi117747 	sip_conn_obj_pvt_t	*pvt_data;
13240cb5e5dSvi117747 	sip_reass_entry_t	*reass;
13340cb5e5dSvi117747 	void			**obj_val;
13440cb5e5dSvi117747 	char			*msgbuf = NULL;
13540cb5e5dSvi117747 	int			splitlen;
13640cb5e5dSvi117747 	char			*splitbuf;
13740cb5e5dSvi117747 
13840cb5e5dSvi117747 	if (msg != NULL) {
13940cb5e5dSvi117747 		assert(*msglen > 0);
14040cb5e5dSvi117747 		msgbuf = (char *)malloc(*msglen + 1);
14140cb5e5dSvi117747 		if (msgbuf == NULL)
14240cb5e5dSvi117747 			return (NULL);
14340cb5e5dSvi117747 		(void) strncpy(msgbuf, msg, *msglen);
14440cb5e5dSvi117747 		msgbuf[*msglen] = '\0';
14540cb5e5dSvi117747 		msg = msgbuf;
14640cb5e5dSvi117747 	}
14740cb5e5dSvi117747 	obj_val = (void *)obj;
14840cb5e5dSvi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
14940cb5e5dSvi117747 	/*
15040cb5e5dSvi117747 	 * connection object not initialized
15140cb5e5dSvi117747 	 */
15240cb5e5dSvi117747 	if (pvt_data == NULL) {
15340cb5e5dSvi117747 		if (msg == NULL)
15440cb5e5dSvi117747 			return (NULL);
15540cb5e5dSvi117747 		value = sip_get_msglen(msg, *msglen);
15640cb5e5dSvi117747 		if (value == *msglen) {
15740cb5e5dSvi117747 			return (msg);
15840cb5e5dSvi117747 		} else {
15940cb5e5dSvi117747 			if (msgbuf != NULL)
16040cb5e5dSvi117747 				free(msgbuf);
16140cb5e5dSvi117747 			return (NULL);
16240cb5e5dSvi117747 		}
16340cb5e5dSvi117747 	}
16440cb5e5dSvi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_reass_lock);
16540cb5e5dSvi117747 	reass = pvt_data->sip_conn_obj_reass;
16640cb5e5dSvi117747 	assert(reass != NULL);
16740cb5e5dSvi117747 	if (reass->sip_reass_msg == NULL) {
16840cb5e5dSvi117747 		assert(reass->sip_reass_msglen == 0);
16940cb5e5dSvi117747 		if (msg == NULL) {
17040cb5e5dSvi117747 			(void) pthread_mutex_unlock(
17140cb5e5dSvi117747 			    &pvt_data->sip_conn_obj_reass_lock);
17240cb5e5dSvi117747 			return (NULL);
17340cb5e5dSvi117747 		}
17440cb5e5dSvi117747 		value = sip_get_msglen(msg, *msglen);
17540cb5e5dSvi117747 		if (value == *msglen) {
17640cb5e5dSvi117747 			(void) pthread_mutex_unlock(
17740cb5e5dSvi117747 			    &pvt_data->sip_conn_obj_reass_lock);
17840cb5e5dSvi117747 			return (msg);
17940cb5e5dSvi117747 		}
18040cb5e5dSvi117747 		reass->sip_reass_msg = msg;
18140cb5e5dSvi117747 		reass->sip_reass_msglen = *msglen;
18240cb5e5dSvi117747 		if (value != -1 && value < reass->sip_reass_msglen)
18340cb5e5dSvi117747 			goto tryone;
18440cb5e5dSvi117747 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
18540cb5e5dSvi117747 		return (NULL);
18640cb5e5dSvi117747 	} else if (msg != NULL) {
18740cb5e5dSvi117747 		/*
18840cb5e5dSvi117747 		 * Resize, not optimal
18940cb5e5dSvi117747 		 */
19040cb5e5dSvi117747 		int	newlen = reass->sip_reass_msglen + *msglen;
19140cb5e5dSvi117747 		char	*newmsg;
19240cb5e5dSvi117747 
19340cb5e5dSvi117747 		assert(strlen(reass->sip_reass_msg) == reass->sip_reass_msglen);
19440cb5e5dSvi117747 		newmsg = malloc(newlen + 1);
19540cb5e5dSvi117747 		if (newmsg == NULL) {
19640cb5e5dSvi117747 			(void) pthread_mutex_unlock(
19740cb5e5dSvi117747 			    &pvt_data->sip_conn_obj_reass_lock);
19840cb5e5dSvi117747 			if (msgbuf != NULL)
19940cb5e5dSvi117747 				free(msgbuf);
20040cb5e5dSvi117747 			return (NULL);
20140cb5e5dSvi117747 		}
20240cb5e5dSvi117747 		(void) strncpy(newmsg, reass->sip_reass_msg,
20340cb5e5dSvi117747 		    reass->sip_reass_msglen);
20440cb5e5dSvi117747 		newmsg[reass->sip_reass_msglen] = '\0';
20540cb5e5dSvi117747 		(void) strncat(newmsg, msg, *msglen);
20640cb5e5dSvi117747 		newmsg[newlen] = '\0';
20740cb5e5dSvi117747 		assert(strlen(newmsg) == newlen);
20840cb5e5dSvi117747 		reass->sip_reass_msglen = newlen;
20940cb5e5dSvi117747 		free(msg);
21040cb5e5dSvi117747 		free(reass->sip_reass_msg);
21140cb5e5dSvi117747 		reass->sip_reass_msg = newmsg;
21240cb5e5dSvi117747 	}
21340cb5e5dSvi117747 	value = sip_get_msglen(reass->sip_reass_msg, reass->sip_reass_msglen);
21440cb5e5dSvi117747 	if (value == -1 || value >  reass->sip_reass_msglen) {
21540cb5e5dSvi117747 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
21640cb5e5dSvi117747 		return (NULL);
21740cb5e5dSvi117747 	}
21840cb5e5dSvi117747 tryone:
21940cb5e5dSvi117747 	if (value == reass->sip_reass_msglen) {
22040cb5e5dSvi117747 		msg = reass->sip_reass_msg;
22140cb5e5dSvi117747 		*msglen = reass->sip_reass_msglen;
22240cb5e5dSvi117747 		reass->sip_reass_msg = NULL;
22340cb5e5dSvi117747 		reass->sip_reass_msglen = 0;
22440cb5e5dSvi117747 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
22540cb5e5dSvi117747 		return (msg);
22640cb5e5dSvi117747 	}
22740cb5e5dSvi117747 	splitlen = reass->sip_reass_msglen - value;
22840cb5e5dSvi117747 	msg = (char *)malloc(value + 1);
22940cb5e5dSvi117747 	splitbuf = (char *)malloc(splitlen + 1);
23040cb5e5dSvi117747 	if (msg == NULL || splitbuf == NULL) {
23140cb5e5dSvi117747 		if (msg != NULL)
23240cb5e5dSvi117747 			free(msg);
23340cb5e5dSvi117747 		if (splitbuf != NULL)
23440cb5e5dSvi117747 			free(splitbuf);
23540cb5e5dSvi117747 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
23640cb5e5dSvi117747 		return (NULL);
23740cb5e5dSvi117747 	}
23840cb5e5dSvi117747 	(void) strncpy(msg, reass->sip_reass_msg, value);
23940cb5e5dSvi117747 	msg[value] = '\0';
24040cb5e5dSvi117747 	(void) strncpy(splitbuf, reass->sip_reass_msg + value, splitlen);
24140cb5e5dSvi117747 	splitbuf[splitlen] = '\0';
24240cb5e5dSvi117747 	free(reass->sip_reass_msg);
24340cb5e5dSvi117747 	reass->sip_reass_msg = splitbuf;
24440cb5e5dSvi117747 	reass->sip_reass_msglen = splitlen;
24540cb5e5dSvi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
24640cb5e5dSvi117747 	*msglen = value;
24740cb5e5dSvi117747 	return (msg);
24840cb5e5dSvi117747 }
249