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