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 2007 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 <stdlib.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <pthread.h>
33 #include <strings.h>
34 #include <sip.h>
35
36 #include "sip_miscdefs.h"
37
38 /*
39 * Local version of case insensitive strstr().
40 */
41 static char *
sip_reass_strstr(const char * as1,const char * as2)42 sip_reass_strstr(const char *as1, const char *as2)
43 {
44 const char *s1;
45 const char *s2;
46 const char *tptr;
47 char c;
48
49 s1 = as1;
50 s2 = as2;
51
52 if (s2 == NULL || *s2 == '\0')
53 return ((char *)s1);
54 c = *s2;
55
56 while (*s1)
57 if (tolower(*s1++) == c) {
58 tptr = s1;
59 while ((c = *++s2) == tolower(*s1++) && c)
60 ;
61 if (c == 0)
62 return ((char *)tptr - 1);
63 s1 = tptr;
64 s2 = as2;
65 c = *s2;
66 }
67
68 return (NULL);
69 }
70
71 /*
72 * Get the value in the content-length field and add it to the header length
73 * and return the total length. returns -1 if the length cannot be determined
74 * or if the message does not contain the entire message.
75 */
76 static int
sip_get_msglen(char * p,size_t msglen)77 sip_get_msglen(char *p, size_t msglen)
78 {
79 int value = 0;
80 int hlen;
81 char *c;
82 char *e;
83 int base = 10;
84 char *edge;
85 int digits = 0;
86
87 edge = p + msglen;
88 if ((c = sip_reass_strstr(p, "content-length")) == NULL)
89 return (-1);
90 hlen = c - p;
91 if ((hlen + strlen("content-length")) >= msglen)
92 return (-1);
93 c += strlen("content-length");
94 e = c + 1;
95 while (*e == ' ' || *e == ':') {
96 e++;
97 if (e == edge)
98 return (-1);
99 }
100 while (*e != '\r' && *e != ' ') {
101 if (e == edge)
102 return (-1);
103 if (*e >= '0' && *e <= '9')
104 digits = *e - '0';
105 else
106 return (-1);
107 value = (value * base) + digits;
108 e++;
109 }
110 while (*e != '\r') {
111 e++;
112 if (e == edge)
113 return (-1);
114 }
115 hlen = e - p + 4; /* 4 for 2 CRLFs ?? */
116 value += hlen;
117
118 return (value);
119 }
120
121 /*
122 * We have determined that msg does not contain a *single* complete message.
123 * Add it to the reassembly list and check if we have a complete message.
124 * a NULL 'msg' means we are just checking if there are more complete
125 * messages in the list that can be passed up.
126 */
127 char *
sip_get_tcp_msg(sip_conn_object_t obj,char * msg,size_t * msglen)128 sip_get_tcp_msg(sip_conn_object_t obj, char *msg, size_t *msglen)
129 {
130 int value;
131 sip_conn_obj_pvt_t *pvt_data;
132 sip_reass_entry_t *reass;
133 void **obj_val;
134 char *msgbuf = NULL;
135 int splitlen;
136 char *splitbuf;
137
138 if (msg != NULL) {
139 assert(*msglen > 0);
140 msgbuf = (char *)malloc(*msglen + 1);
141 if (msgbuf == NULL)
142 return (NULL);
143 (void) strncpy(msgbuf, msg, *msglen);
144 msgbuf[*msglen] = '\0';
145 msg = msgbuf;
146 }
147 obj_val = (void *)obj;
148 pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
149 /*
150 * connection object not initialized
151 */
152 if (pvt_data == NULL) {
153 if (msg == NULL)
154 return (NULL);
155 value = sip_get_msglen(msg, *msglen);
156 if (value == *msglen) {
157 return (msg);
158 } else {
159 if (msgbuf != NULL)
160 free(msgbuf);
161 return (NULL);
162 }
163 }
164 (void) pthread_mutex_lock(&pvt_data->sip_conn_obj_reass_lock);
165 reass = pvt_data->sip_conn_obj_reass;
166 assert(reass != NULL);
167 if (reass->sip_reass_msg == NULL) {
168 assert(reass->sip_reass_msglen == 0);
169 if (msg == NULL) {
170 (void) pthread_mutex_unlock(
171 &pvt_data->sip_conn_obj_reass_lock);
172 return (NULL);
173 }
174 value = sip_get_msglen(msg, *msglen);
175 if (value == *msglen) {
176 (void) pthread_mutex_unlock(
177 &pvt_data->sip_conn_obj_reass_lock);
178 return (msg);
179 }
180 reass->sip_reass_msg = msg;
181 reass->sip_reass_msglen = *msglen;
182 if (value != -1 && value < reass->sip_reass_msglen)
183 goto tryone;
184 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
185 return (NULL);
186 } else if (msg != NULL) {
187 /*
188 * Resize, not optimal
189 */
190 int newlen = reass->sip_reass_msglen + *msglen;
191 char *newmsg;
192
193 assert(strlen(reass->sip_reass_msg) == reass->sip_reass_msglen);
194 newmsg = malloc(newlen + 1);
195 if (newmsg == NULL) {
196 (void) pthread_mutex_unlock(
197 &pvt_data->sip_conn_obj_reass_lock);
198 if (msgbuf != NULL)
199 free(msgbuf);
200 return (NULL);
201 }
202 (void) strncpy(newmsg, reass->sip_reass_msg,
203 reass->sip_reass_msglen);
204 newmsg[reass->sip_reass_msglen] = '\0';
205 (void) strncat(newmsg, msg, *msglen);
206 newmsg[newlen] = '\0';
207 assert(strlen(newmsg) == newlen);
208 reass->sip_reass_msglen = newlen;
209 free(msg);
210 free(reass->sip_reass_msg);
211 reass->sip_reass_msg = newmsg;
212 }
213 value = sip_get_msglen(reass->sip_reass_msg, reass->sip_reass_msglen);
214 if (value == -1 || value > reass->sip_reass_msglen) {
215 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
216 return (NULL);
217 }
218 tryone:
219 if (value == reass->sip_reass_msglen) {
220 msg = reass->sip_reass_msg;
221 *msglen = reass->sip_reass_msglen;
222 reass->sip_reass_msg = NULL;
223 reass->sip_reass_msglen = 0;
224 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
225 return (msg);
226 }
227 splitlen = reass->sip_reass_msglen - value;
228 msg = (char *)malloc(value + 1);
229 splitbuf = (char *)malloc(splitlen + 1);
230 if (msg == NULL || splitbuf == NULL) {
231 if (msg != NULL)
232 free(msg);
233 if (splitbuf != NULL)
234 free(splitbuf);
235 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
236 return (NULL);
237 }
238 (void) strncpy(msg, reass->sip_reass_msg, value);
239 msg[value] = '\0';
240 (void) strncpy(splitbuf, reass->sip_reass_msg + value, splitlen);
241 splitbuf[splitlen] = '\0';
242 free(reass->sip_reass_msg);
243 reass->sip_reass_msg = splitbuf;
244 reass->sip_reass_msglen = splitlen;
245 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
246 *msglen = value;
247 return (msg);
248 }
249