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