1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include "sip_miscdefs.h"
32 
33 /*
34  * Local version of case insensitive strstr().
35  */
36 static char *
37 sip_reass_strstr(const char *as1, const char *as2)
38 {
39 	const char	*s1;
40 	const char	*s2;
41 	const char	*tptr;
42 	char	c;
43 
44 	s1 = as1;
45 	s2 = as2;
46 
47 	if (s2 == NULL || *s2 == '\0')
48 		return ((char *)s1);
49 	c = *s2;
50 
51 	while (*s1)
52 		if (tolower(*s1++) == c) {
53 			tptr = s1;
54 			while ((c = *++s2) == tolower(*s1++) && c)
55 				;
56 			if (c == 0)
57 				return ((char *)tptr - 1);
58 			s1 = tptr;
59 			s2 = as2;
60 			c = *s2;
61 		}
62 
63 	return (NULL);
64 }
65 
66 /*
67  * Get the value in the content-length field and add it to the header length
68  * and return the total length. returns -1 if the length cannot be determined
69  * or if the message does not contain the entire message.
70  */
71 static int
72 sip_get_msglen(char *p, size_t msglen)
73 {
74 	int	value = 0;
75 	int 	hlen;
76 	char	*c;
77 	char	*e;
78 	int	base = 10;
79 	char	*edge;
80 	int	digits = 0;
81 
82 	edge = p + msglen;
83 	if ((c = sip_reass_strstr(p, "content-length")) == NULL)
84 		return (-1);
85 	hlen = c - p;
86 	if ((hlen +  strlen("content-length")) >= msglen)
87 		return (-1);
88 	c += strlen("content-length");
89 	e = c + 1;
90 	while (*e == ' ' || *e == ':') {
91 		e++;
92 		if (e == edge)
93 			return (-1);
94 	}
95 	while (*e  != '\r' && *e != ' ') {
96 		if (e == edge)
97 			return (-1);
98 		if (*e >= '0' && *e <= '9')
99 			digits = *e - '0';
100 		else
101 			return (-1);
102 		value = (value * base) + digits;
103 		e++;
104 	}
105 	while (*e != '\r') {
106 		e++;
107 		if (e == edge)
108 			return (-1);
109 	}
110 	hlen = e - p + 4;	/* 4 for 2 CRLFs ?? */
111 	value += hlen;
112 
113 	return (value);
114 }
115 
116 /*
117  * We have determined that msg does not contain a *single* complete message.
118  * Add it to the reassembly list and check if we have a complete message.
119  * a NULL 'msg' means we are just checking if there are more complete
120  * messages in the list that can be passed up.
121  */
122 char *
123 sip_get_tcp_msg(sip_conn_object_t obj, char *msg, size_t *msglen)
124 {
125 	int			value;
126 	sip_conn_obj_pvt_t	*pvt_data;
127 	sip_reass_entry_t	*reass;
128 	void			**obj_val;
129 	char			*msgbuf = NULL;
130 	int			splitlen;
131 	char			*splitbuf;
132 
133 	if (msg != NULL) {
134 		assert(*msglen > 0);
135 		msgbuf = (char *)malloc(*msglen + 1);
136 		if (msgbuf == NULL)
137 			return (NULL);
138 		(void) strncpy(msgbuf, msg, *msglen);
139 		msgbuf[*msglen] = '\0';
140 		msg = msgbuf;
141 	}
142 	obj_val = (void *)obj;
143 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
144 	/*
145 	 * connection object not initialized
146 	 */
147 	if (pvt_data == NULL) {
148 		if (msg == NULL)
149 			return (NULL);
150 		value = sip_get_msglen(msg, *msglen);
151 		if (value == *msglen) {
152 			return (msg);
153 		} else {
154 			if (msgbuf != NULL)
155 				free(msgbuf);
156 			return (NULL);
157 		}
158 	}
159 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_reass_lock);
160 	reass = pvt_data->sip_conn_obj_reass;
161 	assert(reass != NULL);
162 	if (reass->sip_reass_msg == NULL) {
163 		assert(reass->sip_reass_msglen == 0);
164 		if (msg == NULL) {
165 			(void) pthread_mutex_unlock(
166 			    &pvt_data->sip_conn_obj_reass_lock);
167 			return (NULL);
168 		}
169 		value = sip_get_msglen(msg, *msglen);
170 		if (value == *msglen) {
171 			(void) pthread_mutex_unlock(
172 			    &pvt_data->sip_conn_obj_reass_lock);
173 			return (msg);
174 		}
175 		reass->sip_reass_msg = msg;
176 		reass->sip_reass_msglen = *msglen;
177 		if (value != -1 && value < reass->sip_reass_msglen)
178 			goto tryone;
179 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
180 		return (NULL);
181 	} else if (msg != NULL) {
182 		/*
183 		 * Resize, not optimal
184 		 */
185 		int	newlen = reass->sip_reass_msglen + *msglen;
186 		char	*newmsg;
187 
188 		assert(strlen(reass->sip_reass_msg) == reass->sip_reass_msglen);
189 		newmsg = malloc(newlen + 1);
190 		if (newmsg == NULL) {
191 			(void) pthread_mutex_unlock(
192 			    &pvt_data->sip_conn_obj_reass_lock);
193 			if (msgbuf != NULL)
194 				free(msgbuf);
195 			return (NULL);
196 		}
197 		(void) strncpy(newmsg, reass->sip_reass_msg,
198 		    reass->sip_reass_msglen);
199 		newmsg[reass->sip_reass_msglen] = '\0';
200 		(void) strncat(newmsg, msg, *msglen);
201 		newmsg[newlen] = '\0';
202 		assert(strlen(newmsg) == newlen);
203 		reass->sip_reass_msglen = newlen;
204 		free(msg);
205 		free(reass->sip_reass_msg);
206 		reass->sip_reass_msg = newmsg;
207 	}
208 	value = sip_get_msglen(reass->sip_reass_msg, reass->sip_reass_msglen);
209 	if (value == -1 || value >  reass->sip_reass_msglen) {
210 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
211 		return (NULL);
212 	}
213 tryone:
214 	if (value == reass->sip_reass_msglen) {
215 		msg = reass->sip_reass_msg;
216 		*msglen = reass->sip_reass_msglen;
217 		reass->sip_reass_msg = NULL;
218 		reass->sip_reass_msglen = 0;
219 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
220 		return (msg);
221 	}
222 	splitlen = reass->sip_reass_msglen - value;
223 	msg = (char *)malloc(value + 1);
224 	splitbuf = (char *)malloc(splitlen + 1);
225 	if (msg == NULL || splitbuf == NULL) {
226 		if (msg != NULL)
227 			free(msg);
228 		if (splitbuf != NULL)
229 			free(splitbuf);
230 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
231 		return (NULL);
232 	}
233 	(void) strncpy(msg, reass->sip_reass_msg, value);
234 	msg[value] = '\0';
235 	(void) strncpy(splitbuf, reass->sip_reass_msg + value, splitlen);
236 	splitbuf[splitlen] = '\0';
237 	free(reass->sip_reass_msg);
238 	reass->sip_reass_msg = splitbuf;
239 	reass->sip_reass_msglen = splitlen;
240 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
241 	*msglen = value;
242 	return (msg);
243 }
244