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