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 * 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 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 * 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