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