12882Svi117747 /*
22882Svi117747 * CDDL HEADER START
32882Svi117747 *
42882Svi117747 * The contents of this file are subject to the terms of the
52882Svi117747 * Common Development and Distribution License (the "License").
62882Svi117747 * You may not use this file except in compliance with the License.
72882Svi117747 *
82882Svi117747 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92882Svi117747 * or http://www.opensolaris.org/os/licensing.
102882Svi117747 * See the License for the specific language governing permissions
112882Svi117747 * and limitations under the License.
122882Svi117747 *
132882Svi117747 * When distributing Covered Code, include this CDDL HEADER in each
142882Svi117747 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152882Svi117747 * If applicable, add the following below this CDDL HEADER, with the
162882Svi117747 * fields enclosed by brackets "[]" replaced with your own identifying
172882Svi117747 * information: Portions Copyright [yyyy] [name of copyright owner]
182882Svi117747 *
192882Svi117747 * CDDL HEADER END
202882Svi117747 */
212882Svi117747
222882Svi117747 /*
23*3439Svi117747 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
242882Svi117747 * Use is subject to license terms.
252882Svi117747 */
262882Svi117747
272882Svi117747 #pragma ident "%Z%%M% %I% %E% SMI"
282882Svi117747
29*3439Svi117747 #include <stdlib.h>
30*3439Svi117747 #include <assert.h>
31*3439Svi117747 #include <ctype.h>
32*3439Svi117747 #include <pthread.h>
33*3439Svi117747 #include <strings.h>
34*3439Svi117747 #include <sip.h>
35*3439Svi117747
362882Svi117747 #include "sip_miscdefs.h"
372882Svi117747
382882Svi117747 /*
392882Svi117747 * Local version of case insensitive strstr().
402882Svi117747 */
412882Svi117747 static char *
sip_reass_strstr(const char * as1,const char * as2)422882Svi117747 sip_reass_strstr(const char *as1, const char *as2)
432882Svi117747 {
442882Svi117747 const char *s1;
452882Svi117747 const char *s2;
462882Svi117747 const char *tptr;
472882Svi117747 char c;
482882Svi117747
492882Svi117747 s1 = as1;
502882Svi117747 s2 = as2;
512882Svi117747
522882Svi117747 if (s2 == NULL || *s2 == '\0')
532882Svi117747 return ((char *)s1);
542882Svi117747 c = *s2;
552882Svi117747
562882Svi117747 while (*s1)
572882Svi117747 if (tolower(*s1++) == c) {
582882Svi117747 tptr = s1;
592882Svi117747 while ((c = *++s2) == tolower(*s1++) && c)
602882Svi117747 ;
612882Svi117747 if (c == 0)
622882Svi117747 return ((char *)tptr - 1);
632882Svi117747 s1 = tptr;
642882Svi117747 s2 = as2;
652882Svi117747 c = *s2;
662882Svi117747 }
672882Svi117747
682882Svi117747 return (NULL);
692882Svi117747 }
702882Svi117747
712882Svi117747 /*
722882Svi117747 * Get the value in the content-length field and add it to the header length
732882Svi117747 * and return the total length. returns -1 if the length cannot be determined
742882Svi117747 * or if the message does not contain the entire message.
752882Svi117747 */
762882Svi117747 static int
sip_get_msglen(char * p,size_t msglen)772882Svi117747 sip_get_msglen(char *p, size_t msglen)
782882Svi117747 {
792882Svi117747 int value = 0;
802882Svi117747 int hlen;
812882Svi117747 char *c;
822882Svi117747 char *e;
832882Svi117747 int base = 10;
842882Svi117747 char *edge;
852882Svi117747 int digits = 0;
862882Svi117747
872882Svi117747 edge = p + msglen;
882882Svi117747 if ((c = sip_reass_strstr(p, "content-length")) == NULL)
892882Svi117747 return (-1);
902882Svi117747 hlen = c - p;
912882Svi117747 if ((hlen + strlen("content-length")) >= msglen)
922882Svi117747 return (-1);
932882Svi117747 c += strlen("content-length");
942882Svi117747 e = c + 1;
952882Svi117747 while (*e == ' ' || *e == ':') {
962882Svi117747 e++;
972882Svi117747 if (e == edge)
982882Svi117747 return (-1);
992882Svi117747 }
1002882Svi117747 while (*e != '\r' && *e != ' ') {
1012882Svi117747 if (e == edge)
1022882Svi117747 return (-1);
1032882Svi117747 if (*e >= '0' && *e <= '9')
1042882Svi117747 digits = *e - '0';
1052882Svi117747 else
1062882Svi117747 return (-1);
1072882Svi117747 value = (value * base) + digits;
1082882Svi117747 e++;
1092882Svi117747 }
1102882Svi117747 while (*e != '\r') {
1112882Svi117747 e++;
1122882Svi117747 if (e == edge)
1132882Svi117747 return (-1);
1142882Svi117747 }
1152882Svi117747 hlen = e - p + 4; /* 4 for 2 CRLFs ?? */
1162882Svi117747 value += hlen;
1172882Svi117747
1182882Svi117747 return (value);
1192882Svi117747 }
1202882Svi117747
1212882Svi117747 /*
1222882Svi117747 * We have determined that msg does not contain a *single* complete message.
1232882Svi117747 * Add it to the reassembly list and check if we have a complete message.
1242882Svi117747 * a NULL 'msg' means we are just checking if there are more complete
1252882Svi117747 * messages in the list that can be passed up.
1262882Svi117747 */
1272882Svi117747 char *
sip_get_tcp_msg(sip_conn_object_t obj,char * msg,size_t * msglen)1282882Svi117747 sip_get_tcp_msg(sip_conn_object_t obj, char *msg, size_t *msglen)
1292882Svi117747 {
1302882Svi117747 int value;
1312882Svi117747 sip_conn_obj_pvt_t *pvt_data;
1322882Svi117747 sip_reass_entry_t *reass;
1332882Svi117747 void **obj_val;
1342882Svi117747 char *msgbuf = NULL;
1352882Svi117747 int splitlen;
1362882Svi117747 char *splitbuf;
1372882Svi117747
1382882Svi117747 if (msg != NULL) {
1392882Svi117747 assert(*msglen > 0);
1402882Svi117747 msgbuf = (char *)malloc(*msglen + 1);
1412882Svi117747 if (msgbuf == NULL)
1422882Svi117747 return (NULL);
1432882Svi117747 (void) strncpy(msgbuf, msg, *msglen);
1442882Svi117747 msgbuf[*msglen] = '\0';
1452882Svi117747 msg = msgbuf;
1462882Svi117747 }
1472882Svi117747 obj_val = (void *)obj;
1482882Svi117747 pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1492882Svi117747 /*
1502882Svi117747 * connection object not initialized
1512882Svi117747 */
1522882Svi117747 if (pvt_data == NULL) {
1532882Svi117747 if (msg == NULL)
1542882Svi117747 return (NULL);
1552882Svi117747 value = sip_get_msglen(msg, *msglen);
1562882Svi117747 if (value == *msglen) {
1572882Svi117747 return (msg);
1582882Svi117747 } else {
1592882Svi117747 if (msgbuf != NULL)
1602882Svi117747 free(msgbuf);
1612882Svi117747 return (NULL);
1622882Svi117747 }
1632882Svi117747 }
1642882Svi117747 (void) pthread_mutex_lock(&pvt_data->sip_conn_obj_reass_lock);
1652882Svi117747 reass = pvt_data->sip_conn_obj_reass;
1662882Svi117747 assert(reass != NULL);
1672882Svi117747 if (reass->sip_reass_msg == NULL) {
1682882Svi117747 assert(reass->sip_reass_msglen == 0);
1692882Svi117747 if (msg == NULL) {
1702882Svi117747 (void) pthread_mutex_unlock(
1712882Svi117747 &pvt_data->sip_conn_obj_reass_lock);
1722882Svi117747 return (NULL);
1732882Svi117747 }
1742882Svi117747 value = sip_get_msglen(msg, *msglen);
1752882Svi117747 if (value == *msglen) {
1762882Svi117747 (void) pthread_mutex_unlock(
1772882Svi117747 &pvt_data->sip_conn_obj_reass_lock);
1782882Svi117747 return (msg);
1792882Svi117747 }
1802882Svi117747 reass->sip_reass_msg = msg;
1812882Svi117747 reass->sip_reass_msglen = *msglen;
1822882Svi117747 if (value != -1 && value < reass->sip_reass_msglen)
1832882Svi117747 goto tryone;
1842882Svi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
1852882Svi117747 return (NULL);
1862882Svi117747 } else if (msg != NULL) {
1872882Svi117747 /*
1882882Svi117747 * Resize, not optimal
1892882Svi117747 */
1902882Svi117747 int newlen = reass->sip_reass_msglen + *msglen;
1912882Svi117747 char *newmsg;
1922882Svi117747
1932882Svi117747 assert(strlen(reass->sip_reass_msg) == reass->sip_reass_msglen);
1942882Svi117747 newmsg = malloc(newlen + 1);
1952882Svi117747 if (newmsg == NULL) {
1962882Svi117747 (void) pthread_mutex_unlock(
1972882Svi117747 &pvt_data->sip_conn_obj_reass_lock);
1982882Svi117747 if (msgbuf != NULL)
1992882Svi117747 free(msgbuf);
2002882Svi117747 return (NULL);
2012882Svi117747 }
2022882Svi117747 (void) strncpy(newmsg, reass->sip_reass_msg,
2032882Svi117747 reass->sip_reass_msglen);
2042882Svi117747 newmsg[reass->sip_reass_msglen] = '\0';
2052882Svi117747 (void) strncat(newmsg, msg, *msglen);
2062882Svi117747 newmsg[newlen] = '\0';
2072882Svi117747 assert(strlen(newmsg) == newlen);
2082882Svi117747 reass->sip_reass_msglen = newlen;
2092882Svi117747 free(msg);
2102882Svi117747 free(reass->sip_reass_msg);
2112882Svi117747 reass->sip_reass_msg = newmsg;
2122882Svi117747 }
2132882Svi117747 value = sip_get_msglen(reass->sip_reass_msg, reass->sip_reass_msglen);
2142882Svi117747 if (value == -1 || value > reass->sip_reass_msglen) {
2152882Svi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
2162882Svi117747 return (NULL);
2172882Svi117747 }
2182882Svi117747 tryone:
2192882Svi117747 if (value == reass->sip_reass_msglen) {
2202882Svi117747 msg = reass->sip_reass_msg;
2212882Svi117747 *msglen = reass->sip_reass_msglen;
2222882Svi117747 reass->sip_reass_msg = NULL;
2232882Svi117747 reass->sip_reass_msglen = 0;
2242882Svi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
2252882Svi117747 return (msg);
2262882Svi117747 }
2272882Svi117747 splitlen = reass->sip_reass_msglen - value;
2282882Svi117747 msg = (char *)malloc(value + 1);
2292882Svi117747 splitbuf = (char *)malloc(splitlen + 1);
2302882Svi117747 if (msg == NULL || splitbuf == NULL) {
2312882Svi117747 if (msg != NULL)
2322882Svi117747 free(msg);
2332882Svi117747 if (splitbuf != NULL)
2342882Svi117747 free(splitbuf);
2352882Svi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
2362882Svi117747 return (NULL);
2372882Svi117747 }
2382882Svi117747 (void) strncpy(msg, reass->sip_reass_msg, value);
2392882Svi117747 msg[value] = '\0';
2402882Svi117747 (void) strncpy(splitbuf, reass->sip_reass_msg + value, splitlen);
2412882Svi117747 splitbuf[splitlen] = '\0';
2422882Svi117747 free(reass->sip_reass_msg);
2432882Svi117747 reass->sip_reass_msg = splitbuf;
2442882Svi117747 reass->sip_reass_msglen = splitlen;
2452882Svi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
2462882Svi117747 *msglen = value;
2472882Svi117747 return (msg);
2482882Svi117747 }
249