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 /* 233439Svi117747 * 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 293439Svi117747 #include <stdio.h> 303439Svi117747 #include <stdlib.h> 313439Svi117747 #include <assert.h> 323439Svi117747 #include <errno.h> 333439Svi117747 #include <pthread.h> 343439Svi117747 #include <strings.h> 353439Svi117747 #include <sip.h> 363439Svi117747 372882Svi117747 #include "sip_msg.h" 383439Svi117747 #include "sip_miscdefs.h" 392882Svi117747 #include "sip_hash.h" 402882Svi117747 #include "sip_dialog.h" 412882Svi117747 #include "sip_parse_generic.h" 422882Svi117747 432882Svi117747 #define SIP_DLG_XCHG_FROM 0 442882Svi117747 #define SIP_DLG_XCHG_TO 1 452882Svi117747 462882Svi117747 /* 472882Svi117747 * Dialog state change callback function 482882Svi117747 */ 492882Svi117747 void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL; 502882Svi117747 void (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL; 512882Svi117747 522882Svi117747 boolean_t sip_incomplete_dialog(sip_dialog_t); 532882Svi117747 542882Svi117747 /* 552882Svi117747 * Exchange From/To header 562882Svi117747 */ 572882Svi117747 _sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int); 582882Svi117747 592882Svi117747 /* 602882Svi117747 * Complete dialog hash table 612882Svi117747 */ 622882Svi117747 sip_hash_t sip_dialog_hash[SIP_HASH_SZ]; 632882Svi117747 642882Svi117747 /* 652882Svi117747 * Partial dialog hash table 662882Svi117747 */ 672882Svi117747 sip_hash_t sip_dialog_phash[SIP_HASH_SZ]; 682882Svi117747 692882Svi117747 /* 702882Svi117747 * Route set structure 712882Svi117747 */ 722882Svi117747 typedef struct sip_dlg_route_set_s { 732882Svi117747 char *sip_dlg_route; 742882Svi117747 sip_str_t sip_dlg_ruri; 752882Svi117747 boolean_t sip_dlg_route_lr; 762882Svi117747 struct sip_dlg_route_set_s *sip_dlg_route_next; 772882Svi117747 }sip_dlg_route_set_t; 782882Svi117747 792882Svi117747 sip_dialog_t sip_seed_dialog(sip_conn_object_t, _sip_msg_t *, 802882Svi117747 boolean_t, int); 812882Svi117747 sip_dialog_t sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *); 822882Svi117747 int sip_dialog_process(_sip_msg_t *, sip_dialog_t *); 832882Svi117747 void sip_dialog_delete(_sip_dialog_t *); 842882Svi117747 void sip_dialog_init(); 852882Svi117747 sip_dialog_t sip_dialog_find(_sip_msg_t *); 862882Svi117747 boolean_t sip_dialog_match(void *, void *); 872882Svi117747 boolean_t sip_dialog_free(void *, void *, int *); 882882Svi117747 sip_dialog_t sip_update_dialog(sip_dialog_t, _sip_msg_t *); 892882Svi117747 char *sip_dialog_req_uri(sip_dialog_t); 902882Svi117747 912882Svi117747 static void sip_release_dialog_res(_sip_dialog_t *); 922882Svi117747 void sip_dlg_self_destruct(void *); 932882Svi117747 static int sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *, 942882Svi117747 int); 952882Svi117747 static void sip_dialog_free_rset(sip_dlg_route_set_t *); 962882Svi117747 972882Svi117747 /* 982882Svi117747 * Timer object for partial dialogs 992882Svi117747 */ 1002882Svi117747 typedef struct sip_dialog_timer_obj_s { 1012882Svi117747 _sip_dialog_t *dialog; 1022882Svi117747 void (*func)(sip_dialog_t, sip_msg_t, void *); 1032882Svi117747 } sip_dialog_timer_obj_t; 1042882Svi117747 1052882Svi117747 /* 1062882Svi117747 * To avoid duplication all over the place 1072882Svi117747 */ 1082882Svi117747 static void 1092882Svi117747 sip_release_dialog_res(_sip_dialog_t *dialog) 1102882Svi117747 { 1112882Svi117747 1122882Svi117747 assert(dialog->sip_dlg_ref_cnt == 0); 1132882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 1142882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 1152882Svi117747 if (dialog->sip_dlg_call_id != NULL) 1162882Svi117747 sip_free_header(dialog->sip_dlg_call_id); 1172882Svi117747 if (dialog->sip_dlg_local_uri_tag != NULL) 1182882Svi117747 sip_free_header(dialog->sip_dlg_local_uri_tag); 1192882Svi117747 if (dialog->sip_dlg_remote_uri_tag != NULL) 1202882Svi117747 sip_free_header(dialog->sip_dlg_remote_uri_tag); 1212882Svi117747 if (dialog->sip_dlg_remote_target != NULL) 1222882Svi117747 sip_free_header(dialog->sip_dlg_remote_target); 123*4702Sgm209912 if (dialog->sip_dlg_local_contact != NULL) 124*4702Sgm209912 sip_free_header(dialog->sip_dlg_local_contact); 125*4702Sgm209912 if (dialog->sip_dlg_new_local_contact != NULL) 126*4702Sgm209912 sip_free_header(dialog->sip_dlg_new_local_contact); 1272882Svi117747 if (dialog->sip_dlg_route_set != NULL) 1282882Svi117747 sip_free_header(dialog->sip_dlg_route_set); 1292882Svi117747 if (dialog->sip_dlg_event != NULL) 1302882Svi117747 sip_free_header(dialog->sip_dlg_event); 1312882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 1322882Svi117747 free(dialog->sip_dlg_req_uri.sip_str_ptr); 1332882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 1342882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 1352882Svi117747 } 1362882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 1372882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 1382882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 1392882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 1402882Svi117747 } 1412882Svi117747 (void) pthread_mutex_destroy(&dialog->sip_dlg_mutex); 1422882Svi117747 free(dialog); 1432882Svi117747 } 1442882Svi117747 1452882Svi117747 /* 1462882Svi117747 * Get the route information from the 'value' and add it to the route 1472882Svi117747 * set. 1482882Svi117747 */ 1492882Svi117747 static sip_dlg_route_set_t * 1502882Svi117747 sip_add_route_to_set(sip_hdr_value_t *value) 1512882Svi117747 { 1522882Svi117747 int vlen = 0; 1532882Svi117747 sip_dlg_route_set_t *rset; 1542882Svi117747 char *crlf; 1552882Svi117747 const sip_param_t *uri_param; 1562882Svi117747 int error; 1572882Svi117747 1582882Svi117747 rset = calloc(1, sizeof (*rset)); 1592882Svi117747 if (rset == NULL) 1602882Svi117747 return (NULL); 1612882Svi117747 rset->sip_dlg_route_next = NULL; 1622882Svi117747 vlen = value->sip_value_end - value->sip_value_start; 1632882Svi117747 1642882Svi117747 /* 1652882Svi117747 * check for CRLF 1662882Svi117747 */ 1672882Svi117747 crlf = value->sip_value_end - strlen(SIP_CRLF); 1682882Svi117747 while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 1692882Svi117747 vlen -= strlen(SIP_CRLF); 1702882Svi117747 crlf -= strlen(SIP_CRLF); 1712882Svi117747 } 1722882Svi117747 rset->sip_dlg_route = calloc(1, vlen + 1); 1732882Svi117747 if (rset->sip_dlg_route == NULL) { 1742882Svi117747 free(rset); 1752882Svi117747 return (NULL); 1762882Svi117747 } 1772882Svi117747 /* 1782882Svi117747 * loose routing 1792882Svi117747 */ 1802882Svi117747 rset->sip_dlg_route_lr = B_FALSE; 1812882Svi117747 (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen); 1822882Svi117747 rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route + 1832882Svi117747 (value->cftr_uri.sip_str_ptr - value->sip_value_start); 1842882Svi117747 rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len; 1852882Svi117747 rset->sip_dlg_route[vlen] = '\0'; 1862882Svi117747 1872882Svi117747 assert(value->sip_value_parsed_uri != NULL); 1882882Svi117747 /* 1892882Svi117747 * Check if the 'lr' param is present for this route. 1902882Svi117747 */ 1912882Svi117747 uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error); 1922882Svi117747 if (error != 0) { 1932882Svi117747 free(rset->sip_dlg_route); 1942882Svi117747 free(rset); 1952882Svi117747 return (NULL); 1962882Svi117747 } 1972882Svi117747 if (uri_param != NULL) { 1982882Svi117747 rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr", 1992882Svi117747 strlen("lr")); 2002882Svi117747 } 2012882Svi117747 return (rset); 2022882Svi117747 } 2032882Svi117747 2042882Svi117747 /* 2052882Svi117747 * Depending on the route-set, determine the request URI. 2062882Svi117747 */ 2072882Svi117747 char * 2082882Svi117747 sip_dialog_req_uri(sip_dialog_t dialog) 2092882Svi117747 { 2102882Svi117747 const sip_str_t *req_uri; 2112882Svi117747 char *uri; 2122882Svi117747 _sip_dialog_t *_dialog; 2132882Svi117747 2142882Svi117747 _dialog = (_sip_dialog_t *)dialog; 2152882Svi117747 if (_dialog->sip_dlg_route_set == NULL || 2162882Svi117747 _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 2172882Svi117747 const struct sip_value *val; 2182882Svi117747 2192882Svi117747 val = sip_get_header_value(_dialog->sip_dlg_remote_target, 2202882Svi117747 NULL); 2212882Svi117747 if (val == NULL) 2222882Svi117747 return (NULL); 2232882Svi117747 req_uri = &((sip_hdr_value_t *)val)->cftr_uri; 2242882Svi117747 } else { 2252882Svi117747 req_uri = &_dialog->sip_dlg_req_uri; 2262882Svi117747 } 2272882Svi117747 uri = (char *)malloc(req_uri->sip_str_len + 1); 2282882Svi117747 if (uri == NULL) 2292882Svi117747 return (NULL); 2302882Svi117747 (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len); 2312882Svi117747 uri[req_uri->sip_str_len] = '\0'; 2322882Svi117747 2332882Svi117747 return (uri); 2342882Svi117747 } 2352882Svi117747 2362882Svi117747 /* 2372882Svi117747 * Free the route set. 2382882Svi117747 */ 2392882Svi117747 void 2402882Svi117747 sip_dialog_free_rset(sip_dlg_route_set_t *rset) 2412882Svi117747 { 2422882Svi117747 sip_dlg_route_set_t *next; 2432882Svi117747 2442882Svi117747 while (rset != NULL) { 2452882Svi117747 next = rset->sip_dlg_route_next; 2462882Svi117747 rset->sip_dlg_route_next = NULL; 2472882Svi117747 free(rset->sip_dlg_route); 2482882Svi117747 free(rset); 2492882Svi117747 rset = next; 2502882Svi117747 } 2512882Svi117747 } 2522882Svi117747 2532882Svi117747 /* 2542882Svi117747 * Recompute route-set 2552882Svi117747 */ 2562882Svi117747 static int 2572882Svi117747 sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 2582882Svi117747 { 2592882Svi117747 int ret; 2602882Svi117747 2612882Svi117747 if (dialog->sip_dlg_route_set != NULL) { 2622882Svi117747 sip_free_header(dialog->sip_dlg_route_set); 2632882Svi117747 dialog->sip_dlg_route_set = NULL; 2642882Svi117747 } 2652882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 2662882Svi117747 free(dialog->sip_dlg_req_uri.sip_str_ptr); 2672882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 2682882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 2692882Svi117747 } 2702882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 2712882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 2722882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 2732882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 2742882Svi117747 } 2752882Svi117747 ret = sip_dialog_get_route_set(dialog, sip_msg, what); 2762882Svi117747 return (ret); 2772882Svi117747 } 2782882Svi117747 2792882Svi117747 /* 2802882Svi117747 * If the route set is empty, the UAC MUST place the remote target URI 2812882Svi117747 * into the Request-URI. The UAC MUST NOT add a Route header field to 2822882Svi117747 * the request. 2832882Svi117747 * 2842882Svi117747 * If the route set is not empty, and the first URI in the route set 2852882Svi117747 * contains the lr parameter (see Section 19.1.1), the UAC MUST place 2862882Svi117747 * the remote target URI into the Request-URI and MUST include a Route 2872882Svi117747 * header field containing the route set values in order, including all 2882882Svi117747 * parameters. 2892882Svi117747 * 2902882Svi117747 * If the route set is not empty, and its first URI does not contain the 2912882Svi117747 * lr parameter, the UAC MUST place the first URI from the route set 2922882Svi117747 * into the Request-URI, stripping any parameters that are not allowed 2932882Svi117747 * in a Request-URI. The UAC MUST add a Route header field containing 2942882Svi117747 * the remainder of the route set values in order, including all 2952882Svi117747 * parameters. The UAC MUST then place the remote target URI into the 2962882Svi117747 * Route header field as the last value. 2972882Svi117747 */ 2982882Svi117747 int 2992882Svi117747 sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head, 3002882Svi117747 int rcnt, int rlen) 3012882Svi117747 { 3022882Svi117747 size_t rset_len; 3032882Svi117747 _sip_header_t *rhdr; 3042882Svi117747 char *rset; 3052882Svi117747 char *rp; 3062882Svi117747 char *rsp; 3072882Svi117747 int count; 3082882Svi117747 sip_dlg_route_set_t *route; 3092882Svi117747 boolean_t first = B_TRUE; 3102882Svi117747 const sip_str_t *to_uri; 3112882Svi117747 char *uri = NULL; 3122882Svi117747 int rspl; 3132882Svi117747 int rpl; 3142882Svi117747 3152882Svi117747 assert(rcnt > 0); 3162882Svi117747 3172882Svi117747 dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1; 3182882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt); 3192882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr == NULL) 3202882Svi117747 return (ENOMEM); 3212882Svi117747 rsp = dialog->sip_dlg_rset.sip_str_ptr; 3222882Svi117747 rspl = rlen + rcnt; 3232882Svi117747 route = rset_head; 3242882Svi117747 rset_len = rlen; 3252882Svi117747 if (!route->sip_dlg_route_lr) { 3262882Svi117747 const struct sip_value *val; 3272882Svi117747 3282882Svi117747 val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL); 3292882Svi117747 to_uri = &((sip_hdr_value_t *)val)->cftr_uri; 3302882Svi117747 uri = (char *)malloc(to_uri->sip_str_len + 1); 3312882Svi117747 if (uri == NULL) { 3322882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3332882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3342882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3352882Svi117747 return (ENOMEM); 3362882Svi117747 } 3372882Svi117747 (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len); 3382882Svi117747 uri[to_uri->sip_str_len] = '\0'; 3392882Svi117747 rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) + 3402882Svi117747 SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 3412882Svi117747 sizeof (char); 3422882Svi117747 count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); 3432882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = malloc( 3442882Svi117747 route->sip_dlg_ruri.sip_str_len + 1); 3452882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 3462882Svi117747 free(uri); 3472882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3482882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3492882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3502882Svi117747 return (ENOMEM); 3512882Svi117747 } 3522882Svi117747 (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp + 3532882Svi117747 (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route), 3542882Svi117747 route->sip_dlg_ruri.sip_str_len); 3552882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr[ 3562882Svi117747 route->sip_dlg_ruri.sip_str_len] = '\0'; 3572882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 3582882Svi117747 route->sip_dlg_ruri.sip_str_len; 3592882Svi117747 3602882Svi117747 rsp += count; 3612882Svi117747 rspl -= count; 3622882Svi117747 route = route->sip_dlg_route_next; 3632882Svi117747 } 3642882Svi117747 3652882Svi117747 /* 3662882Svi117747 * rcnt - 1 is for the number of COMMAs 3672882Svi117747 */ 3682882Svi117747 rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) + 3692882Svi117747 SIP_SPACE_LEN + rcnt - 1; 3702882Svi117747 rset = malloc(rset_len + 1); 3712882Svi117747 if (rset == NULL) { 3722882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3732882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3742882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3752882Svi117747 return (ENOMEM); 3762882Svi117747 } 3772882Svi117747 rhdr = sip_new_header(rset_len + strlen(SIP_CRLF)); 3782882Svi117747 if (rhdr == NULL) { 3792882Svi117747 free(rset); 3802882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3812882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3822882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3832882Svi117747 return (ENOMEM); 3842882Svi117747 } 3852882Svi117747 3862882Svi117747 rp = rset; 3872882Svi117747 rpl = rset_len + 1; 3882882Svi117747 count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON); 3892882Svi117747 rp += count; 3902882Svi117747 rpl -= count; 3912882Svi117747 3922882Svi117747 while (route != NULL) { 3932882Svi117747 if (first) { 3942882Svi117747 count = snprintf(rp, rpl, "%s", route->sip_dlg_route); 3952882Svi117747 rp += count; 3962882Svi117747 rpl -= count; 3972882Svi117747 first = B_FALSE; 3982882Svi117747 if (uri != NULL) { 3992882Svi117747 count = snprintf(rsp, rspl, "%c%s", 4002882Svi117747 SIP_COMMA, route->sip_dlg_route); 4012882Svi117747 } else { 4022882Svi117747 count = snprintf(rsp, rspl, "%s", 4032882Svi117747 route->sip_dlg_route); 4042882Svi117747 } 4052882Svi117747 rsp += count; 4062882Svi117747 rspl -= count; 4072882Svi117747 } else { 4082882Svi117747 count = snprintf(rp, rpl, "%c%s", SIP_COMMA, 4092882Svi117747 route->sip_dlg_route); 4102882Svi117747 rp += count; 4112882Svi117747 rpl -= count; 4122882Svi117747 count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, 4132882Svi117747 route->sip_dlg_route); 4142882Svi117747 rsp += count; 4152882Svi117747 rspl -= count; 4162882Svi117747 } 4172882Svi117747 route = route->sip_dlg_route_next; 4182882Svi117747 } 4192882Svi117747 assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr + 4202882Svi117747 dialog->sip_dlg_rset.sip_str_len); 4212882Svi117747 dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] = 4222882Svi117747 '\0'; 4232882Svi117747 if (uri != NULL) { 4242882Svi117747 if (first) { 4252882Svi117747 count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT, 4262882Svi117747 uri, SIP_RAQUOT); 4272882Svi117747 } else { 4282882Svi117747 count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA, 4292882Svi117747 SIP_LAQUOT, uri, SIP_RAQUOT); 4302882Svi117747 } 4312882Svi117747 rp += count; 4322882Svi117747 rpl -= count; 4332882Svi117747 free(uri); 4342882Svi117747 } 4352882Svi117747 assert(rp <= rset + rset_len); 4362882Svi117747 (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1, 4372882Svi117747 "%s%s", rset, SIP_CRLF); 4382882Svi117747 free(rset); 4392882Svi117747 dialog->sip_dlg_route_set = (sip_header_t)rhdr; 4402882Svi117747 sip_dialog_free_rset(rset_head); 4412882Svi117747 return (0); 4422882Svi117747 } 4432882Svi117747 4442882Svi117747 /* 4452882Svi117747 * UAC Behavior 4462882Svi117747 * The route set MUST be set to the list of URIs in the Record-Route 4472882Svi117747 * header field from the response, taken in reverse order and preserving 4482882Svi117747 * all URI parameters. 4492882Svi117747 * 4502882Svi117747 * UAS behavior 4512882Svi117747 * The route set MUST be set to the list of URIs in the Record-Route 4522882Svi117747 * header field from the request, taken in order and preserving all URI 4532882Svi117747 * parameters. 4542882Svi117747 */ 4552882Svi117747 static int 4562882Svi117747 sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 4572882Svi117747 { 4582882Svi117747 sip_header_t rrhdr; 4592882Svi117747 sip_hdr_value_t *value; 4602882Svi117747 int error; 4612882Svi117747 sip_dlg_route_set_t *rset_head = NULL; 4622882Svi117747 sip_dlg_route_set_t *rset_tail = NULL; 4632882Svi117747 sip_dlg_route_set_t *rset; 4642882Svi117747 int rset_cnt = 0; 4652882Svi117747 int rset_len = 0; 4662882Svi117747 4672882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 4682882Svi117747 rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL); 4692882Svi117747 while (rrhdr != NULL) { 4702882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 4712882Svi117747 value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error); 4722882Svi117747 while (value != NULL && error == 0) { 4732882Svi117747 char *crlf; 4742882Svi117747 4752882Svi117747 if (value->sip_value_state == SIP_VALUE_BAD) { 4762882Svi117747 value = (sip_hdr_value_t *)sip_get_next_value( 4772882Svi117747 (sip_header_value_t)value, &error); 4782882Svi117747 continue; 4792882Svi117747 } 4802882Svi117747 rset = sip_add_route_to_set(value); 4812882Svi117747 if (rset == NULL) 4822882Svi117747 goto r_error; 4832882Svi117747 /* 4842882Svi117747 * Add one for COMMA 4852882Svi117747 */ 4862882Svi117747 rset_cnt++; 4872882Svi117747 rset_len += (value->sip_value_end - 4882882Svi117747 value->sip_value_start); 4892882Svi117747 /* 4902882Svi117747 * Check for CRLF 4912882Svi117747 */ 4922882Svi117747 crlf = value->sip_value_end - strlen(SIP_CRLF); 4932882Svi117747 while (crlf != NULL && 4942882Svi117747 strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 4952882Svi117747 rset_len -= strlen(SIP_CRLF); 4962882Svi117747 crlf -= strlen(SIP_CRLF); 4972882Svi117747 } 4982882Svi117747 if (rset_head == NULL) { 4992882Svi117747 assert(rset_tail == NULL); 5002882Svi117747 rset_head = rset_tail = rset; 5012882Svi117747 } else if (what == SIP_UAS_DIALOG) { 5022882Svi117747 rset_tail->sip_dlg_route_next = rset; 5032882Svi117747 rset_tail = rset; 5042882Svi117747 } else if (what == SIP_UAC_DIALOG) { 5052882Svi117747 rset->sip_dlg_route_next = rset_head; 5062882Svi117747 rset_head = rset; 5072882Svi117747 } else { 5082882Svi117747 assert(0); 5092882Svi117747 } 5102882Svi117747 value = (sip_hdr_value_t *)sip_get_next_value( 5112882Svi117747 (sip_header_value_t)value, &error); 5122882Svi117747 } 5132882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 5142882Svi117747 rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr); 5152882Svi117747 } 5162882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 5172882Svi117747 if (rset_cnt == 0) 5182882Svi117747 return (0); 5192882Svi117747 if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt, 5202882Svi117747 rset_len) != 0) { 5212882Svi117747 goto r_error; 5222882Svi117747 } 5232882Svi117747 return (0); 5242882Svi117747 r_error: 5252882Svi117747 sip_dialog_free_rset(rset_head); 5262882Svi117747 return (ENOMEM); 5272882Svi117747 } 5282882Svi117747 5292882Svi117747 /* 5302882Svi117747 * UAS behavior: 5312882Svi117747 * The remote sequence number MUST be set to the value of the sequence 5322882Svi117747 * number in the CSeq header field of the request. The local sequence 5332882Svi117747 * number MUST be empty. The call identifier component of the dialog ID 5342882Svi117747 * MUST be set to the value of the Call-ID in the request. The local 5352882Svi117747 * tag component of the dialog ID MUST be set to the tag in the To field 5362882Svi117747 * in the response to the request (which always includes a tag), and the 5372882Svi117747 * remote tag component of the dialog ID MUST be set to the tag from the 5382882Svi117747 * From field in the request. A UAS MUST be prepared to receive a 5392882Svi117747 * request without a tag in the From field, in which case the tag is 5402882Svi117747 * considered to have a value of null. 5412882Svi117747 * The remote URI MUST be set to the URI in the From field, and the 5422882Svi117747 * local URI MUST be set to the URI in the To field. 5432882Svi117747 * The remote target MUST be set to the URI from the Contact header field 5442882Svi117747 * of the request. 5452882Svi117747 * 5462882Svi117747 * UAC behavior: 5472882Svi117747 * The local sequence number MUST be set to the value of the sequence 5482882Svi117747 * number in the CSeq header field of the request. The remote sequence 5492882Svi117747 * number MUST be empty (it is established when the remote UA sends a 5502882Svi117747 * request within the dialog). The call identifier component of the 5512882Svi117747 * dialog ID MUST be set to the value of the Call-ID in the request. 5522882Svi117747 * The local tag component of the dialog ID MUST be set to the tag in 5532882Svi117747 * the From field in the request, and the remote tag component of the 5542882Svi117747 * dialog ID MUST be set to the tag in the To field of the response. A 5552882Svi117747 * UAC MUST be prepared to receive a response without a tag in the To 5562882Svi117747 * field, in which case the tag is considered to have a value of null. 5572882Svi117747 * The remote URI MUST be set to the URI in the To field, and the local 5582882Svi117747 * URI MUST be set to the URI in the From field. 5592882Svi117747 * The remote target MUST be set to the URI from the Contact header field 5602882Svi117747 * of the response. 5612882Svi117747 */ 5622882Svi117747 5632882Svi117747 5642882Svi117747 /* 5652882Svi117747 * This is the routine that seeds a dialog. 5662882Svi117747 */ 5672882Svi117747 sip_dialog_t 5682882Svi117747 sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg, 5692882Svi117747 boolean_t dlg_on_fork, int dlg_type) 5702882Svi117747 { 5712882Svi117747 _sip_dialog_t *dialog; 5722882Svi117747 int cseq; 5732882Svi117747 sip_header_t fhdr = NULL; 5742882Svi117747 sip_header_t thdr = NULL; 5752882Svi117747 sip_header_t chdr; 5762882Svi117747 sip_header_t cihdr; 5772882Svi117747 sip_header_t evhdr = NULL; 5782882Svi117747 const struct sip_value *value; 5792882Svi117747 sip_dialog_timer_obj_t *tim_obj = NULL; 5802882Svi117747 const sip_str_t *callid; 5812882Svi117747 sip_method_t method; 5822882Svi117747 int timer1 = sip_timer_T1; 5832882Svi117747 int error; 5842882Svi117747 5852882Svi117747 if (!sip_msg_is_request((sip_msg_t)sip_msg, &error)) 5862882Svi117747 return (NULL); 5872882Svi117747 5882882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 5892882Svi117747 /* 5902882Svi117747 * Only INVITE and SUBSCRIBE supported 5912882Svi117747 */ 5922882Svi117747 if (error != 0 || (method != INVITE && method != SUBSCRIBE)) 5932882Svi117747 return (NULL); 5942882Svi117747 5952882Svi117747 /* 5962882Svi117747 * A request outside of a dialog MUST NOT contain a To tag 5972882Svi117747 */ 5982882Svi117747 if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL) 5992882Svi117747 return (NULL); 6002882Svi117747 6012882Svi117747 if (dlg_type == SIP_UAS_DIALOG) { 6022882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 6032882Svi117747 SIP_DLG_XCHG_FROM); 6042882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 6052882Svi117747 } else { 6062882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 6072882Svi117747 fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL); 6082882Svi117747 } 6092882Svi117747 cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL); 6102882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 6112882Svi117747 if (method == SUBSCRIBE) 6122882Svi117747 evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 6132882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 6142882Svi117747 if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL || 6152882Svi117747 (method == SUBSCRIBE && evhdr == NULL)) { 6162882Svi117747 if (thdr != NULL) 6172882Svi117747 sip_free_header(thdr); 6182882Svi117747 return (NULL); 6192882Svi117747 } 6202882Svi117747 6212882Svi117747 /* 6222882Svi117747 * Sanity check since we just store the headers in the dialog 6232882Svi117747 */ 6242882Svi117747 if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL || 6252882Svi117747 sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 6262882Svi117747 ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) || 6272882Svi117747 (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL || 6282882Svi117747 sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 6292882Svi117747 ((value = sip_get_header_value(chdr, NULL)) == NULL) || 6302882Svi117747 sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { 6312882Svi117747 if (thdr != NULL) 6322882Svi117747 sip_free_header(thdr); 6332882Svi117747 return (NULL); 6342882Svi117747 } 6352882Svi117747 6362882Svi117747 tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t)); 6372882Svi117747 if (tim_obj == NULL) { 6382882Svi117747 if (thdr != NULL) 6392882Svi117747 sip_free_header(thdr); 6402882Svi117747 return (NULL); 6412882Svi117747 } 6422882Svi117747 dialog = calloc(1, sizeof (_sip_dialog_t)); 6432882Svi117747 if (dialog == NULL) { 6442882Svi117747 if (thdr != NULL) 6452882Svi117747 sip_free_header(thdr); 6462882Svi117747 return (NULL); 6472882Svi117747 } 6482882Svi117747 /* 6492882Svi117747 * We will take the TO header with the tag when we complete this 6502882Svi117747 * dialog 6512882Svi117747 */ 6522882Svi117747 if (dlg_type == SIP_UAS_DIALOG) { 6532882Svi117747 dialog->sip_dlg_remote_uri_tag = thdr; 6542882Svi117747 /* 6552882Svi117747 * We take the remote target from the incoming request on the 6562882Svi117747 * UAS. For the UAC, we will take it from the response. 6572882Svi117747 */ 6582882Svi117747 if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == 6592882Svi117747 NULL) { 6602882Svi117747 goto dia_err; 6612882Svi117747 } 6622882Svi117747 } else { 6632882Svi117747 if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == 6642882Svi117747 NULL) { 6652882Svi117747 goto dia_err; 6662882Svi117747 } 667*4702Sgm209912 /* 668*4702Sgm209912 * We take the local contact from the originating request on 669*4702Sgm209912 * UAC. For the UAS, we will take it from the response. 670*4702Sgm209912 */ 671*4702Sgm209912 if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) == 672*4702Sgm209912 NULL) { 673*4702Sgm209912 goto dia_err; 674*4702Sgm209912 } else { 675*4702Sgm209912 dialog->sip_dlg_new_local_contact = NULL; 676*4702Sgm209912 } 6772882Svi117747 } 6782882Svi117747 if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) 6792882Svi117747 goto dia_err; 6802882Svi117747 if (method == SUBSCRIBE) { 6812882Svi117747 dialog->sip_dlg_event = sip_dup_header(evhdr); 6822882Svi117747 if (dialog->sip_dlg_event == NULL) { 6832882Svi117747 goto dia_err; 6842882Svi117747 } 6852882Svi117747 } 6862882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 6872882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 6882882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 6892882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 6902882Svi117747 /* 6912882Svi117747 * Get the route set from the request, if present 6922882Svi117747 */ 6932882Svi117747 if (dlg_type == SIP_UAS_DIALOG && 6942882Svi117747 sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) { 6952882Svi117747 goto dia_err; 6962882Svi117747 } 6972882Svi117747 if (dlg_type == SIP_UAC_DIALOG) 6982882Svi117747 dialog->sip_dlg_local_cseq = cseq; 6992882Svi117747 else 7002882Svi117747 dialog->sip_dlg_remote_cseq = cseq; 7012882Svi117747 dialog->sip_dlg_type = dlg_type; 7022882Svi117747 dialog->sip_dlg_on_fork = dlg_on_fork; 7032882Svi117747 dialog->sip_dlg_method = method; 7042882Svi117747 /* 7052882Svi117747 * Set the partial dialog timer with the INVITE timeout val 7062882Svi117747 */ 7072882Svi117747 if (sip_conn_timer1 != NULL) 7082882Svi117747 timer1 = sip_conn_timer1(obj); 7092882Svi117747 SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1); 7102882Svi117747 tim_obj->dialog = dialog; 7112882Svi117747 /* 7122882Svi117747 * Since at the client we never pass the partial dialog, we need not 7132882Svi117747 * invoke the callback when the partial dialog self-destructs. 7142882Svi117747 */ 7152882Svi117747 if (dlg_type == SIP_UAS_DIALOG) 7162882Svi117747 tim_obj->func = sip_ulp_dlg_del_cb; 7172882Svi117747 SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj, 7182882Svi117747 sip_dlg_self_destruct); 7192882Svi117747 if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 7202882Svi117747 goto dia_err; 7212882Svi117747 (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); 7222882Svi117747 7232882Svi117747 if (dlg_type == SIP_UAC_DIALOG) { 7242882Svi117747 const sip_str_t *local_tag; 7252882Svi117747 7262882Svi117747 local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 7272882Svi117747 assert(local_tag != NULL); 7282882Svi117747 sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len, 7292882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 7302882Svi117747 NULL, 0, NULL, 0, NULL, 0, NULL, 0, 7312882Svi117747 (uchar_t *)dialog->sip_dlg_id); 7322882Svi117747 7332882Svi117747 7342882Svi117747 /* 7352882Svi117747 * Add it to the partial hash table 7362882Svi117747 */ 7372882Svi117747 if (sip_hash_add(sip_dialog_phash, (void *)dialog, 7382882Svi117747 SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 7392882Svi117747 goto dia_err; 7402882Svi117747 } 7412882Svi117747 } 7422882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 7432882Svi117747 return ((sip_dialog_t)dialog); 7442882Svi117747 dia_err: 7452882Svi117747 sip_release_dialog_res(dialog); 7462882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 7472882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 7482882Svi117747 if (tim_obj != NULL) 7492882Svi117747 free(tim_obj); 7502882Svi117747 return (NULL); 7512882Svi117747 } 7522882Svi117747 7532882Svi117747 /* 7542882Svi117747 * When creating a dialog from a NOTIFY request, we need to get the FROM 7552882Svi117747 * header for the dialog from the TO header of the NOTIFY. 7562882Svi117747 */ 7572882Svi117747 _sip_header_t * 7582882Svi117747 sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what) 7592882Svi117747 { 7602882Svi117747 int len; 7612882Svi117747 _sip_header_t *newhdr; 7622882Svi117747 int cnt; 7632882Svi117747 const struct sip_header *hdr; 7642882Svi117747 int hdrsize; 7652882Svi117747 int error; 7662882Svi117747 7672882Svi117747 hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM : 7682882Svi117747 SIP_TO, NULL, &error); 7692882Svi117747 if (error != 0 || hdr == NULL) 7702882Svi117747 return (NULL); 7712882Svi117747 if (sip_parse_goto_values((_sip_header_t *)hdr) != 0) 7722882Svi117747 return (NULL); 7732882Svi117747 len = hdr->sip_hdr_end - hdr->sip_hdr_current; 7742882Svi117747 if (what == SIP_DLG_XCHG_FROM) { 7752882Svi117747 hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) + 7762882Svi117747 SIP_SPACE_LEN; 7772882Svi117747 } else { 7782882Svi117747 hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN + 7792882Svi117747 sizeof (char) + SIP_SPACE_LEN; 7802882Svi117747 } 7812882Svi117747 newhdr = sip_new_header(hdrsize); 7822882Svi117747 if (newhdr == NULL) 7832882Svi117747 return (NULL); 7842882Svi117747 if (what == SIP_DLG_XCHG_FROM) { 7852882Svi117747 cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 7862882Svi117747 "%s %c ", SIP_TO, SIP_HCOLON); 7872882Svi117747 } else { 7882882Svi117747 cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 7892882Svi117747 "%s %c ", SIP_FROM, SIP_HCOLON); 7902882Svi117747 } 7912882Svi117747 newhdr->sip_hdr_current += cnt; 7922882Svi117747 (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len); 7932882Svi117747 newhdr->sip_hdr_current += len; 7942882Svi117747 assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end); 7952882Svi117747 assert(hdr->sip_header_functions != NULL); 7962882Svi117747 7972882Svi117747 /* 7982882Svi117747 * FROM and TO have common parsing functions 7992882Svi117747 */ 8002882Svi117747 newhdr->sip_header_functions = hdr->sip_header_functions; 8012882Svi117747 newhdr->sip_hdr_current = newhdr->sip_hdr_start; 8022882Svi117747 8032882Svi117747 return (newhdr); 8042882Svi117747 } 8052882Svi117747 8062882Svi117747 /* 8072882Svi117747 * This is the response that completes the dialog that was created 8082882Svi117747 * in sip_seed_dialog(). 8092882Svi117747 */ 8102882Svi117747 sip_dialog_t 8112882Svi117747 sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog) 8122882Svi117747 { 8132882Svi117747 _sip_header_t *thdr; 8142882Svi117747 _sip_header_t *evhdr = NULL; 8152882Svi117747 _sip_header_t *substate = NULL; 8162882Svi117747 sip_header_t chdr = NULL; 8172882Svi117747 int resp_code; 8182882Svi117747 const sip_str_t *ttag; 8192882Svi117747 const sip_str_t *remtag; 8202882Svi117747 const sip_str_t *callid; 8212882Svi117747 const struct sip_value *val; 8222882Svi117747 sip_method_t method; 8232882Svi117747 int error = 0; 8242882Svi117747 int prev_state; 8252882Svi117747 boolean_t alloc_thdr = B_FALSE; 8262882Svi117747 8272882Svi117747 if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0) 8282882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 8292882Svi117747 else 8302882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 8312882Svi117747 if (error != 0 || dialog == NULL || 8322882Svi117747 (sip_msg_is_request((sip_msg_t)sip_msg, &error) && 8332882Svi117747 (dialog->sip_dlg_method == INVITE || method != NOTIFY))) { 8342882Svi117747 return (NULL); 8352882Svi117747 } 8362882Svi117747 if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY && 8372882Svi117747 sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 8382882Svi117747 dialog->sip_dlg_local_cseq) || 8392882Svi117747 (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY && 8402882Svi117747 sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 8412882Svi117747 dialog->sip_dlg_remote_cseq)) { 8422882Svi117747 return (NULL); 8432882Svi117747 } 8442882Svi117747 if (method == NOTIFY) { 8452882Svi117747 const sip_str_t *sstate; 8462882Svi117747 8472882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 8482882Svi117747 SIP_DLG_XCHG_FROM); 8492882Svi117747 if (thdr == NULL) 8502882Svi117747 return (NULL); 8512882Svi117747 alloc_thdr = B_TRUE; 8522882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 8532882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 8542882Svi117747 if (chdr == NULL) { 8552882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8562882Svi117747 sip_free_header(thdr); 8572882Svi117747 return (NULL); 8582882Svi117747 } 8592882Svi117747 evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 8602882Svi117747 if (evhdr == NULL) { 8612882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8622882Svi117747 sip_free_header(thdr); 8632882Svi117747 return (NULL); 8642882Svi117747 } 8652882Svi117747 substate = sip_search_for_header(sip_msg, 8662882Svi117747 SIP_SUBSCRIPTION_STATE, NULL); 8672882Svi117747 if (substate == NULL) { 8682882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8692882Svi117747 sip_free_header(thdr); 8702882Svi117747 return (NULL); 8712882Svi117747 } 8722882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 8732882Svi117747 sstate = sip_get_substate((sip_msg_t)sip_msg, &error); 8742882Svi117747 if (sstate == NULL || error != 0) { 8752882Svi117747 sip_free_header(thdr); 8762882Svi117747 return (NULL); 8772882Svi117747 } 8782882Svi117747 if ((sstate->sip_str_len != strlen("pending") && 8792882Svi117747 sstate->sip_str_len != strlen("active")) || 8802882Svi117747 ((sstate->sip_str_len == strlen("pending") && 8812882Svi117747 strncasecmp(sstate->sip_str_ptr, "pending", 8822882Svi117747 strlen("pending")) != 0) || 8832882Svi117747 (sstate->sip_str_len == strlen("active") && 8842882Svi117747 strncasecmp(sstate->sip_str_ptr, "active", 8852882Svi117747 strlen("active")) != 0))) { 8862882Svi117747 sip_free_header(thdr); 8872882Svi117747 return (NULL); 8882882Svi117747 } 8892882Svi117747 ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 8902882Svi117747 } else { 8912882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 8922882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 8932882Svi117747 SIP_DLG_XCHG_TO); 8942882Svi117747 alloc_thdr = B_TRUE; 8952882Svi117747 } else { 8962882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 8972882Svi117747 thdr = sip_search_for_header(sip_msg, SIP_TO, NULL); 8982882Svi117747 if (dialog->sip_dlg_remote_target == NULL) { 8992882Svi117747 chdr = sip_search_for_header(sip_msg, 9002882Svi117747 SIP_CONTACT, NULL); 9012882Svi117747 } 9022882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9032882Svi117747 } 9042882Svi117747 if (thdr == NULL) { 9052882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9062882Svi117747 return (NULL); 9072882Svi117747 } 9082882Svi117747 ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL); 9092882Svi117747 } 9102882Svi117747 if (ttag == NULL) { 9112882Svi117747 if (alloc_thdr) 9122882Svi117747 sip_free_header(thdr); 9132882Svi117747 return (NULL); 9142882Svi117747 } 9152882Svi117747 prev_state = dialog->sip_dlg_state; 9162882Svi117747 9172882Svi117747 if (method == NOTIFY) { 9182882Svi117747 int error; 9192882Svi117747 const sip_str_t *dlg_id_val = NULL; 9202882Svi117747 const sip_str_t *event; 9212882Svi117747 const sip_str_t *id_val = NULL; 9222882Svi117747 sip_header_value_t ev_val; 9232882Svi117747 sip_hdr_value_t *dlg_ev_val = NULL; 9242882Svi117747 9252882Svi117747 event = sip_get_event((sip_msg_t)sip_msg, &error); 9262882Svi117747 if (event == NULL || error != 0) { 9272882Svi117747 sip_free_header(thdr); 9282882Svi117747 return (NULL); 9292882Svi117747 } 9302882Svi117747 ev_val = (sip_header_value_t)sip_get_header_value(evhdr, 9312882Svi117747 &error); 9322882Svi117747 if (ev_val != NULL) 9332882Svi117747 id_val = sip_get_param_value(ev_val, "id", &error); 9342882Svi117747 if (error == 0) { 9352882Svi117747 dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value( 9362882Svi117747 dialog->sip_dlg_event, &error); 9372882Svi117747 } 9382882Svi117747 if (dlg_ev_val == NULL || error != 0) { 9392882Svi117747 sip_free_header(thdr); 9402882Svi117747 return (NULL); 9412882Svi117747 } 9422882Svi117747 dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val, 9432882Svi117747 "id", &error); 9442882Svi117747 if (error != 0 || 9452882Svi117747 dlg_ev_val->str_val_len != event->sip_str_len || 9462882Svi117747 strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr, 9472882Svi117747 event->sip_str_len != 0)) { 9482882Svi117747 sip_free_header(thdr); 9492882Svi117747 return (NULL); 9502882Svi117747 } 9512882Svi117747 if ((dlg_id_val == NULL && id_val != NULL) || 9522882Svi117747 (dlg_id_val != NULL && id_val == NULL)) { 9532882Svi117747 sip_free_header(thdr); 9542882Svi117747 return (NULL); 9552882Svi117747 } else if (dlg_id_val != NULL && id_val != NULL) { 9562882Svi117747 if (dlg_id_val->sip_str_len != id_val->sip_str_len || 9572882Svi117747 strncasecmp(dlg_id_val->sip_str_ptr, 9582882Svi117747 id_val->sip_str_ptr, dlg_id_val->sip_str_len) != 9592882Svi117747 0) { 9602882Svi117747 sip_free_header(thdr); 9612882Svi117747 return (NULL); 9622882Svi117747 } 9632882Svi117747 } 9642882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 9652882Svi117747 dialog->sip_dlg_remote_uri_tag = thdr; 9662882Svi117747 if ((dialog->sip_dlg_remote_target = 9672882Svi117747 sip_dup_header(chdr)) == NULL) { 9682882Svi117747 sip_free_header(thdr); 9692882Svi117747 return (NULL); 9702882Svi117747 } 9712882Svi117747 } else { 9722882Svi117747 dialog->sip_dlg_local_uri_tag = thdr; 9732882Svi117747 } 9742882Svi117747 dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 9752882Svi117747 } else { 9762882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 9772882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 9782882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_NEW); 9792882Svi117747 if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) { 9802882Svi117747 assert(dialog->sip_dlg_type == SIP_UAC_DIALOG); 9812882Svi117747 if ((dialog->sip_dlg_remote_target = 9822882Svi117747 sip_dup_header(chdr)) == NULL) { 9832882Svi117747 (void) pthread_mutex_unlock( 9842882Svi117747 &dialog->sip_dlg_mutex); 9852882Svi117747 if (alloc_thdr) 9862882Svi117747 sip_free_header(thdr); 9873439Svi117747 goto terminate_new_dlg; 9882882Svi117747 } 9892882Svi117747 if (sip_dialog_get_route_set(dialog, sip_msg, 9902882Svi117747 dialog->sip_dlg_type) != 0) { 9912882Svi117747 (void) pthread_mutex_unlock( 9922882Svi117747 &dialog->sip_dlg_mutex); 9932882Svi117747 if (alloc_thdr) 9942882Svi117747 sip_free_header(thdr); 9953439Svi117747 goto terminate_new_dlg; 9962882Svi117747 } 9972882Svi117747 } 9982882Svi117747 if (SIP_PROVISIONAL_RESP(resp_code)) { 9992882Svi117747 dialog->sip_dlg_state = SIP_DLG_EARLY; 10002882Svi117747 } else if (SIP_OK_RESP(resp_code)) { 10012882Svi117747 /* 10022882Svi117747 * Per 12.1 the UAS must include the contact header 10032882Svi117747 * for a dialog establishing response, so if we 10042882Svi117747 * don't find one, we terminate it. 10052882Svi117747 */ 10062882Svi117747 if (dialog->sip_dlg_remote_target == NULL) { 10072882Svi117747 (void) pthread_mutex_unlock( 10082882Svi117747 &dialog->sip_dlg_mutex); 10092882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 10102882Svi117747 sip_ulp_dlg_del_cb(dialog, 10112882Svi117747 (sip_msg_t)sip_msg, NULL); 10122882Svi117747 } 10132882Svi117747 if (alloc_thdr) 10142882Svi117747 sip_free_header(thdr); 10153439Svi117747 goto terminate_new_dlg; 10162882Svi117747 } 10172882Svi117747 dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 10182882Svi117747 } else { 10192882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 10202882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 10212882Svi117747 sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg, 10222882Svi117747 NULL); 10232882Svi117747 } 10242882Svi117747 if (alloc_thdr) 10252882Svi117747 sip_free_header(thdr); 10263439Svi117747 goto terminate_new_dlg; 10272882Svi117747 } 10282882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 10292882Svi117747 dialog->sip_dlg_local_uri_tag = thdr; 10302882Svi117747 } else { 10312882Svi117747 if ((dialog->sip_dlg_remote_uri_tag = 10322882Svi117747 sip_dup_header(thdr)) == NULL) { 10332882Svi117747 (void) pthread_mutex_unlock( 10342882Svi117747 &dialog->sip_dlg_mutex); 10353439Svi117747 goto terminate_new_dlg; 10362882Svi117747 } 10372882Svi117747 } 10382882Svi117747 } 10392882Svi117747 10402882Svi117747 /* 1041*4702Sgm209912 * We take the local contact for UAS Dialog from the response (either 1042*4702Sgm209912 * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE 1043*4702Sgm209912 * request) 1044*4702Sgm209912 */ 1045*4702Sgm209912 if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state 1046*4702Sgm209912 == SIP_DLG_CONFIRMED)) { 1047*4702Sgm209912 if (chdr == NULL) { 1048*4702Sgm209912 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 1049*4702Sgm209912 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 1050*4702Sgm209912 NULL); 1051*4702Sgm209912 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 1052*4702Sgm209912 } 1053*4702Sgm209912 if ((chdr == NULL) || ((dialog->sip_dlg_local_contact = 1054*4702Sgm209912 sip_dup_header(chdr)) == NULL)) { 1055*4702Sgm209912 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1056*4702Sgm209912 if (alloc_thdr) 1057*4702Sgm209912 sip_free_header(thdr); 1058*4702Sgm209912 goto terminate_new_dlg; 1059*4702Sgm209912 } 1060*4702Sgm209912 } 1061*4702Sgm209912 1062*4702Sgm209912 /* 10632882Svi117747 * Cancel the partial dialog timer 10642882Svi117747 */ 10652882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 10662882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 10672882Svi117747 10682882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 10692882Svi117747 val = sip_get_header_value(dialog->sip_dlg_local_uri_tag, 10702882Svi117747 &error); 10712882Svi117747 } else { 10722882Svi117747 val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag, 10732882Svi117747 &error); 10742882Svi117747 } 10752882Svi117747 assert(val != NULL && error == 0); 10762882Svi117747 remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error); 10772882Svi117747 10782882Svi117747 val = sip_get_header_value(dialog->sip_dlg_call_id, &error); 10792882Svi117747 callid = &((sip_hdr_value_t *)val)->str_val; 10802882Svi117747 10812882Svi117747 /* 10822882Svi117747 * Get an ID for this dialog 10832882Svi117747 */ 10842882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 10852882Svi117747 sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len, 10862882Svi117747 ttag->sip_str_ptr, ttag->sip_str_len, 10872882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 10882882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 10892882Svi117747 } else { 10902882Svi117747 sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len, 10912882Svi117747 remtag->sip_str_ptr, remtag->sip_str_len, 10922882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 10932882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 10942882Svi117747 } 10952882Svi117747 10962882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 10972882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 10982882Svi117747 10992882Svi117747 /* 11002882Svi117747 * Add it to the hash table 11012882Svi117747 */ 11022882Svi117747 if (sip_hash_add(sip_dialog_hash, (void *)dialog, 11032882Svi117747 SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 11043439Svi117747 terminate_new_dlg: 11052882Svi117747 /* 11062882Svi117747 * So that sip_dialog_delete() does not try to remove 11072882Svi117747 * this from the hash table. 11082882Svi117747 */ 11092882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11102882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 11113439Svi117747 if (dialog->sip_dlg_local_uri_tag != NULL) { 11123439Svi117747 sip_free_header(dialog->sip_dlg_local_uri_tag); 11133439Svi117747 dialog->sip_dlg_local_uri_tag = NULL; 11143439Svi117747 } 11152882Svi117747 } else { 11163439Svi117747 if (dialog->sip_dlg_remote_uri_tag != NULL) { 11173439Svi117747 sip_free_header(dialog->sip_dlg_remote_uri_tag); 11183439Svi117747 dialog->sip_dlg_remote_uri_tag = NULL; 11193439Svi117747 } 11202882Svi117747 } 11212882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11222882Svi117747 sip_dialog_terminate(dialog, (sip_msg_t)sip_msg); 11232882Svi117747 return (NULL); 11242882Svi117747 } 11252882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 11262882Svi117747 sip_dlg_ulp_state_cb((sip_dialog_t)dialog, 11272882Svi117747 (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state); 11282882Svi117747 } 11292882Svi117747 return ((sip_dialog_t)dialog); 11302882Svi117747 } 11312882Svi117747 11322882Svi117747 /* 11332882Svi117747 * Check if this dialog is a match. 11342882Svi117747 */ 11352882Svi117747 boolean_t 11362882Svi117747 sip_dialog_match(void *obj, void *hindex) 11372882Svi117747 { 11382882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11392882Svi117747 11402882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11412882Svi117747 if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 11422882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11432882Svi117747 return (B_FALSE); 11442882Svi117747 } 11452882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, 11462882Svi117747 sizeof (dialog->sip_dlg_id)) == 0) { 11472882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 11482882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11492882Svi117747 return (B_TRUE); 11502882Svi117747 } 11512882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11522882Svi117747 return (B_FALSE); 11532882Svi117747 } 11542882Svi117747 11552882Svi117747 /* 11562882Svi117747 * Don't delete, just take it out of the hash 11572882Svi117747 */ 11582882Svi117747 boolean_t 11592882Svi117747 sip_dialog_dontfree(void *obj, void *hindex, int *found) 11602882Svi117747 { 11612882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11622882Svi117747 11632882Svi117747 *found = 0; 11642882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11652882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 11662882Svi117747 == 0) { 11672882Svi117747 *found = 1; 11682882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11692882Svi117747 return (B_TRUE); 11702882Svi117747 } 11712882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11722882Svi117747 return (B_FALSE); 11732882Svi117747 } 11742882Svi117747 11752882Svi117747 /* 11762882Svi117747 * Free resources associated with the dialog, the object will be removed 11772882Svi117747 * from the hash list by sip_hash_delete. 11782882Svi117747 */ 11792882Svi117747 boolean_t 11802882Svi117747 sip_dialog_free(void *obj, void *hindex, int *found) 11812882Svi117747 { 11822882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11832882Svi117747 11842882Svi117747 *found = 0; 11852882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11862882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 11872882Svi117747 == 0) { 11882882Svi117747 *found = 1; 11892882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED); 11902882Svi117747 if (dialog->sip_dlg_ref_cnt != 0) { 11912882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11922882Svi117747 return (B_FALSE); 11932882Svi117747 } 11942882Svi117747 sip_release_dialog_res(dialog); 11952882Svi117747 return (B_TRUE); 11962882Svi117747 } 11972882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11982882Svi117747 return (B_FALSE); 11992882Svi117747 } 12002882Svi117747 12012882Svi117747 /* 12022882Svi117747 * The UAS will receive the request from the transaction layer. If the 12032882Svi117747 * request has a tag in the To header field, the UAS core computes the 12042882Svi117747 * dialog identifier corresponding to the request and compares it with 12052882Svi117747 * existing dialogs. If there is a match, this is a mid-dialog request. 12062882Svi117747 */ 12072882Svi117747 sip_dialog_t 12082882Svi117747 sip_dialog_find(_sip_msg_t *sip_msg) 12092882Svi117747 { 12102882Svi117747 const sip_str_t *localtag; 12112882Svi117747 const sip_str_t *remtag; 12122882Svi117747 const sip_str_t *callid; 12132882Svi117747 uint16_t digest[8]; 12142882Svi117747 _sip_dialog_t *dialog; 12152882Svi117747 boolean_t is_request; 12162882Svi117747 int error; 12172882Svi117747 12182882Svi117747 is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 12192882Svi117747 if (error != 0) 12202882Svi117747 return (NULL); 12212882Svi117747 if (is_request) { 12222882Svi117747 localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 12232882Svi117747 if (error == 0) 12242882Svi117747 remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 12252882Svi117747 } else { 12262882Svi117747 remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 12272882Svi117747 if (error == 0) 12282882Svi117747 localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 12292882Svi117747 } 12302882Svi117747 if (error != 0) 12312882Svi117747 return (NULL); 12322882Svi117747 callid = sip_get_callid((sip_msg_t)sip_msg, &error); 12332882Svi117747 if (error != 0 || remtag == NULL || localtag == NULL || 12342882Svi117747 callid == NULL) { 12352882Svi117747 return (NULL); 12362882Svi117747 } 12372882Svi117747 sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 12382882Svi117747 remtag->sip_str_ptr, remtag->sip_str_len, 12392882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 12402882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 12412882Svi117747 12422882Svi117747 dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash, 12432882Svi117747 (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match); 12442882Svi117747 if (dialog == NULL) { 12452882Svi117747 sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 12462882Svi117747 NULL, 0, callid->sip_str_ptr, callid->sip_str_len, 12472882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 12482882Svi117747 dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash, 12492882Svi117747 (void *)digest, SIP_DIGEST_TO_HASH(digest), 12502882Svi117747 sip_dialog_match); 12512882Svi117747 } 12522882Svi117747 return ((sip_dialog_t)dialog); 12532882Svi117747 } 12542882Svi117747 12552882Svi117747 /* 12562882Svi117747 * We keep this partial dialog for the duration of the INVITE 12572882Svi117747 * transaction timeout duration, i.e. Timer B. 12582882Svi117747 */ 12592882Svi117747 void 12602882Svi117747 sip_dlg_self_destruct(void *args) 12612882Svi117747 { 12622882Svi117747 sip_dialog_timer_obj_t *tim_obj = (sip_dialog_timer_obj_t *)args; 12632882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)tim_obj->dialog; 12642882Svi117747 int index; 12652882Svi117747 12662882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12672882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_NEW); 12682882Svi117747 dialog->sip_dlg_state = SIP_DLG_DESTROYED; 12692882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 12702882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 12712882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12722882Svi117747 sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id, 12732882Svi117747 index, sip_dialog_dontfree); 12742882Svi117747 } else { 12752882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12762882Svi117747 } 12772882Svi117747 if (tim_obj->func != NULL) 12782882Svi117747 tim_obj->func(dialog, NULL, NULL); 12792882Svi117747 free(tim_obj); 12802882Svi117747 SIP_DLG_REFCNT_DECR(dialog); 12812882Svi117747 } 12822882Svi117747 12832882Svi117747 /* 12842882Svi117747 * Terminate a dialog 12852882Svi117747 */ 12862882Svi117747 void 12872882Svi117747 sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg) 12882882Svi117747 { 12892882Svi117747 int prev_state; 12902882Svi117747 12912882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12922882Svi117747 prev_state = dialog->sip_dlg_state; 12932882Svi117747 dialog->sip_dlg_state = SIP_DLG_DESTROYED; 12942882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12952882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 12962882Svi117747 sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state, 12972882Svi117747 dialog->sip_dlg_state); 12982882Svi117747 } 12992882Svi117747 SIP_DLG_REFCNT_DECR(dialog); 13002882Svi117747 } 13012882Svi117747 13022882Svi117747 /* 13032882Svi117747 * Delete a dialog 13042882Svi117747 */ 13052882Svi117747 void 13062882Svi117747 sip_dialog_delete(_sip_dialog_t *dialog) 13072882Svi117747 { 13082882Svi117747 int index; 13092882Svi117747 13102882Svi117747 /* 13112882Svi117747 * partial dialog, not in the hash table 13122882Svi117747 */ 13132882Svi117747 if (dialog->sip_dlg_local_uri_tag == NULL || 13142882Svi117747 dialog->sip_dlg_remote_uri_tag == NULL) { 13152882Svi117747 /* 13162882Svi117747 * Cancel the partial dialog timer 13172882Svi117747 */ 13182882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 13192882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 13202882Svi117747 sip_release_dialog_res(dialog); 13212882Svi117747 return; 13222882Svi117747 } 13232882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 13242882Svi117747 sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index, 13252882Svi117747 sip_dialog_free); 13262882Svi117747 } 13272882Svi117747 13282882Svi117747 /* 13292882Svi117747 * Get the remote target from the CONTACT header from the 200 OK response 13302882Svi117747 */ 13312882Svi117747 static boolean_t 13322882Svi117747 sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg) 13332882Svi117747 { 13342882Svi117747 sip_header_t chdr; 13352882Svi117747 13362882Svi117747 if (dialog->sip_dlg_remote_target != NULL) 13372882Svi117747 return (B_TRUE); 13382882Svi117747 13392882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 13402882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 13412882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 13422882Svi117747 if (chdr == NULL) 13432882Svi117747 return (B_FALSE); 13442882Svi117747 if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL) 13452882Svi117747 return (B_FALSE); 13462882Svi117747 13472882Svi117747 return (B_TRUE); 13482882Svi117747 } 13492882Svi117747 13502882Svi117747 /* 13512882Svi117747 * Process an incoming request/response 13522882Svi117747 */ 13532882Svi117747 /* ARGSUSED */ 13542882Svi117747 int 13552882Svi117747 sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog) 13562882Svi117747 { 13572882Svi117747 boolean_t request; 13582882Svi117747 _sip_dialog_t *_dialog; 13592882Svi117747 int error; 13602882Svi117747 13612882Svi117747 request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 13622882Svi117747 if (error != 0) 13632882Svi117747 return (EINVAL); 13642882Svi117747 _dialog = (_sip_dialog_t *)*sip_dialog; 13652882Svi117747 if (request) { 13662882Svi117747 uint32_t cseq; 13672882Svi117747 sip_method_t method; 13682882Svi117747 13692882Svi117747 cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error); 13702882Svi117747 if (error != 0) 13712882Svi117747 return (EINVAL); 13722882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 13732882Svi117747 if (error != 0) 13742882Svi117747 return (EINVAL); 13752882Svi117747 if (sip_get_request_method((sip_msg_t)sip_msg, &error) != 13762882Svi117747 method) { 13772882Svi117747 return (EINVAL); 13782882Svi117747 } 13792882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 13802882Svi117747 /* 13812882Svi117747 * Requests that do not change in any way the state 13822882Svi117747 * of a dialog may be received within a dialog. 13832882Svi117747 * They are processed as if they had been received 13842882Svi117747 * outside the dialog. 13852882Svi117747 * For dialogs that have been established with an 13862882Svi117747 * INVITE, the only target refresh request defined is 13872882Svi117747 * re-INVITE. 13882882Svi117747 */ 13892882Svi117747 if (_dialog->sip_dlg_method == INVITE && 13902882Svi117747 method == INVITE && _dialog->sip_dlg_remote_cseq != 0 && 13912882Svi117747 SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) { 13922882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 13932882Svi117747 return (EPROTO); 13942882Svi117747 } 13952882Svi117747 /* 13962882Svi117747 * Target-Refresh request 13972882Svi117747 */ 13982882Svi117747 if (_dialog->sip_dlg_method == INVITE && method == INVITE) { 13992882Svi117747 sip_header_t chdr; 14002882Svi117747 sip_header_t nchdr; 14012882Svi117747 14022882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 14032882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 14042882Svi117747 NULL); 14052882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 14062882Svi117747 if (chdr != NULL && 14072882Svi117747 (nchdr = sip_dup_header(chdr)) != NULL) { 14082882Svi117747 if (_dialog->sip_dlg_remote_target != NULL) { 14092882Svi117747 sip_free_header( 14102882Svi117747 _dialog->sip_dlg_remote_target); 14112882Svi117747 } 14122882Svi117747 _dialog->sip_dlg_remote_target = nchdr; 14132882Svi117747 } 14142882Svi117747 } 14152882Svi117747 _dialog->sip_dlg_remote_cseq = cseq; 14162882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14172882Svi117747 } else { 14182882Svi117747 int resp_code; 14192882Svi117747 sip_method_t method; 14202882Svi117747 int error; 14212882Svi117747 14222882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 14232882Svi117747 if (error == 0) { 14242882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, 14252882Svi117747 &error); 14262882Svi117747 } 14272882Svi117747 if (error != 0) 14282882Svi117747 return (error); 14292882Svi117747 14302882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 14314641Sgm209912 if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 14324641Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14334641Sgm209912 return (0); 14344641Sgm209912 } 14352882Svi117747 assert(_dialog->sip_dlg_state == SIP_DLG_EARLY || 14362882Svi117747 _dialog->sip_dlg_state == SIP_DLG_CONFIRMED); 14372882Svi117747 /* 14382882Svi117747 * Let the user delete the dialog if it is not a 1XX/2XX resp 14392882Svi117747 * for an early INVITE dialog. 14402882Svi117747 */ 14412882Svi117747 if (SIP_OK_RESP(resp_code)) { 14422882Svi117747 if (method == INVITE) { 14432882Svi117747 if (!sip_get_rtarg(_dialog, sip_msg)) { 14442882Svi117747 (void) pthread_mutex_unlock( 14452882Svi117747 &_dialog->sip_dlg_mutex); 14462882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 14472882Svi117747 sip_ulp_dlg_del_cb( 14482882Svi117747 (sip_dialog_t)_dialog, 14492882Svi117747 (sip_msg_t)sip_msg, NULL); 14502882Svi117747 } 14512882Svi117747 sip_dialog_terminate(_dialog, 14522882Svi117747 (sip_msg_t)sip_msg); 14532882Svi117747 return (0); 14542882Svi117747 } 14552882Svi117747 if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 14562882Svi117747 _dialog->sip_dlg_state = 14572882Svi117747 SIP_DLG_CONFIRMED; 14582882Svi117747 (void) pthread_mutex_unlock( 14592882Svi117747 &_dialog->sip_dlg_mutex); 14602882Svi117747 (void) sip_dlg_recompute_rset(_dialog, 14612882Svi117747 sip_msg, SIP_UAC_DIALOG); 14622882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 14632882Svi117747 sip_dlg_ulp_state_cb( 14642882Svi117747 (sip_dialog_t)_dialog, 14652882Svi117747 sip_msg, SIP_DLG_EARLY, 14662882Svi117747 _dialog->sip_dlg_state); 14672882Svi117747 } 14682882Svi117747 return (0); 1469*4702Sgm209912 } else if (_dialog->sip_dlg_new_local_contact 1470*4702Sgm209912 != NULL) { 1471*4702Sgm209912 assert(_dialog->sip_dlg_local_contact 1472*4702Sgm209912 != NULL); 1473*4702Sgm209912 sip_free_header(_dialog-> 1474*4702Sgm209912 sip_dlg_local_contact); 1475*4702Sgm209912 _dialog->sip_dlg_local_contact = 1476*4702Sgm209912 _dialog->sip_dlg_new_local_contact; 1477*4702Sgm209912 _dialog->sip_dlg_new_local_contact = 1478*4702Sgm209912 NULL; 14792882Svi117747 } 14802882Svi117747 } 14812882Svi117747 } 14822882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14832882Svi117747 } 14842882Svi117747 return (0); 14852882Svi117747 } 14862882Svi117747 14872882Svi117747 /* 14882882Svi117747 * Copy partial dialog to create a complete dialog 14892882Svi117747 */ 14902882Svi117747 _sip_dialog_t * 14912882Svi117747 sip_copy_partial_dialog(_sip_dialog_t *dialog) 14922882Svi117747 { 14932882Svi117747 _sip_dialog_t *new_dlg; 14942882Svi117747 14952882Svi117747 new_dlg = calloc(1, sizeof (_sip_dialog_t)); 14962882Svi117747 if (new_dlg == NULL) 14972882Svi117747 return (NULL); 14982882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 14992882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_ptr = 15002882Svi117747 malloc(dialog->sip_dlg_req_uri.sip_str_len + 1); 15012882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) { 15022882Svi117747 free(new_dlg); 15032882Svi117747 return (NULL); 15042882Svi117747 } 15052882Svi117747 (void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr, 15062882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr, 15072882Svi117747 dialog->sip_dlg_req_uri.sip_str_len); 15082882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_ptr[ 15092882Svi117747 dialog->sip_dlg_req_uri.sip_str_len] = '\0'; 15102882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_len = 15112882Svi117747 dialog->sip_dlg_req_uri.sip_str_len; 15122882Svi117747 } 15132882Svi117747 if (dialog->sip_dlg_route_set != NULL) { 15142882Svi117747 assert(dialog->sip_dlg_rset.sip_str_ptr != NULL); 15152882Svi117747 new_dlg->sip_dlg_rset.sip_str_ptr = 15162882Svi117747 malloc(dialog->sip_dlg_rset.sip_str_len + 1); 15172882Svi117747 if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) { 15182882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 15192882Svi117747 free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 15202882Svi117747 free(new_dlg); 15212882Svi117747 return (NULL); 15222882Svi117747 } 15232882Svi117747 (void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr, 15242882Svi117747 dialog->sip_dlg_rset.sip_str_ptr, 15252882Svi117747 dialog->sip_dlg_rset.sip_str_len); 15262882Svi117747 new_dlg->sip_dlg_rset.sip_str_ptr[ 15272882Svi117747 dialog->sip_dlg_rset.sip_str_len] = '\0'; 15282882Svi117747 new_dlg->sip_dlg_rset.sip_str_len = 15292882Svi117747 dialog->sip_dlg_rset.sip_str_len; 15302882Svi117747 15312882Svi117747 new_dlg->sip_dlg_route_set = 15322882Svi117747 sip_dup_header(dialog->sip_dlg_route_set); 15332882Svi117747 if (new_dlg->sip_dlg_route_set == NULL) { 15342882Svi117747 free(new_dlg->sip_dlg_rset.sip_str_ptr); 15352882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 15362882Svi117747 free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 15372882Svi117747 free(new_dlg); 15382882Svi117747 return (NULL); 15392882Svi117747 } 15402882Svi117747 } 15412882Svi117747 if ((new_dlg->sip_dlg_local_uri_tag = 15422882Svi117747 sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL || 15432882Svi117747 (new_dlg->sip_dlg_remote_target = 15442882Svi117747 sip_dup_header(dialog->sip_dlg_remote_target)) == NULL || 1545*4702Sgm209912 (new_dlg->sip_dlg_local_contact = 1546*4702Sgm209912 sip_dup_header(dialog->sip_dlg_local_contact)) == NULL || 15472882Svi117747 (new_dlg->sip_dlg_call_id = 15482882Svi117747 sip_dup_header(dialog->sip_dlg_call_id)) == NULL) { 15492882Svi117747 sip_release_dialog_res(new_dlg); 15502882Svi117747 return (NULL); 15512882Svi117747 } 15522882Svi117747 if (dialog->sip_dlg_event != NULL) { 15532882Svi117747 new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event); 15542882Svi117747 if (new_dlg->sip_dlg_event == NULL) { 15552882Svi117747 sip_release_dialog_res(new_dlg); 15562882Svi117747 return (NULL); 15572882Svi117747 } 15582882Svi117747 } 15592882Svi117747 new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq; 15602882Svi117747 new_dlg->sip_dlg_type = dialog->sip_dlg_type; 15612882Svi117747 new_dlg->sip_dlg_on_fork = B_FALSE; 15622882Svi117747 (void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL); 15632882Svi117747 15642882Svi117747 return (new_dlg); 15652882Svi117747 } 15662882Svi117747 15672882Svi117747 /* 15682882Svi117747 * Update the dialog using the response 15692882Svi117747 */ 15702882Svi117747 sip_dialog_t 15712882Svi117747 sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg) 15722882Svi117747 { 15732882Svi117747 _sip_dialog_t *_dialog; 15742882Svi117747 boolean_t isreq; 15752882Svi117747 sip_method_t method; 15762882Svi117747 int resp_code = 0; 15772882Svi117747 int prev_state; 15782882Svi117747 boolean_t decr_ref = B_FALSE; 15792882Svi117747 int error; 15802882Svi117747 15812882Svi117747 isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error); 15822882Svi117747 if (error != 0) 15832882Svi117747 return (dialog); 15842882Svi117747 _dialog = (_sip_dialog_t *)dialog; 15852882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 15862882Svi117747 if (isreq) { 15872882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 15882882Svi117747 if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE || 15892882Svi117747 method != NOTIFY) { 15902882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15912882Svi117747 return (dialog); 15922882Svi117747 } 15932882Svi117747 } else { 15942882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 15952882Svi117747 if (error != 0) { 15962882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15972882Svi117747 return (dialog); 15982882Svi117747 } 1599*4702Sgm209912 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 1600*4702Sgm209912 if (error != 0) { 1601*4702Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1602*4702Sgm209912 return (dialog); 1603*4702Sgm209912 } 16042882Svi117747 } 16052882Svi117747 prev_state = _dialog->sip_dlg_state; 16062882Svi117747 if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) { 16072882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16082882Svi117747 } else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 16092882Svi117747 /* 16102882Svi117747 * Let the user delete the dialog if it is not a 1XX/2XX resp 16112882Svi117747 * for an early dialog. 16122882Svi117747 */ 16132882Svi117747 assert(!isreq); 16142882Svi117747 if (SIP_OK_RESP(resp_code)) { 16152882Svi117747 _dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 1616*4702Sgm209912 /* 1617*4702Sgm209912 * If we recieved provisional response before we would 1618*4702Sgm209912 * not have captured local contact. So store it now. 1619*4702Sgm209912 */ 1620*4702Sgm209912 if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog-> 1621*4702Sgm209912 sip_dlg_method == INVITE && method == INVITE) { 1622*4702Sgm209912 sip_header_t chdr; 1623*4702Sgm209912 (void) pthread_mutex_lock(&sip_msg-> 1624*4702Sgm209912 sip_msg_mutex); 1625*4702Sgm209912 chdr = sip_search_for_header(sip_msg, 1626*4702Sgm209912 SIP_CONTACT, NULL); 1627*4702Sgm209912 (void) pthread_mutex_unlock(&sip_msg-> 1628*4702Sgm209912 sip_msg_mutex); 1629*4702Sgm209912 if (chdr != NULL) { 1630*4702Sgm209912 _dialog->sip_dlg_local_contact 1631*4702Sgm209912 = sip_dup_header(chdr); 1632*4702Sgm209912 _dialog->sip_dlg_new_local_contact = 1633*4702Sgm209912 NULL; 1634*4702Sgm209912 } 1635*4702Sgm209912 } 16362882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16372882Svi117747 (void) sip_dlg_recompute_rset(_dialog, sip_msg, 16382882Svi117747 SIP_UAS_DIALOG); 16392882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 16402882Svi117747 sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg, 16412882Svi117747 prev_state, dialog->sip_dlg_state); 16422882Svi117747 } 16432882Svi117747 } else { 16442882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16452882Svi117747 } 16462882Svi117747 } else if (_dialog->sip_dlg_state == SIP_DLG_NEW) { 16472882Svi117747 if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE && 16482882Svi117747 SIP_PROVISIONAL_RESP(resp_code)) { 16492882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16502882Svi117747 return (dialog); 16512882Svi117747 } 16522882Svi117747 if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) { 16532882Svi117747 _sip_dialog_t *new_dlg; 16542882Svi117747 16552882Svi117747 if (_dialog->sip_dlg_on_fork) { 16562882Svi117747 new_dlg = sip_copy_partial_dialog(_dialog); 16572882Svi117747 if (new_dlg == NULL) { 16582882Svi117747 (void) pthread_mutex_unlock( 16592882Svi117747 &_dialog->sip_dlg_mutex); 16602882Svi117747 return (dialog); 16612882Svi117747 } 16622882Svi117747 /* 16632882Svi117747 * This decr/incr dance is because the caller 16642882Svi117747 * has incremented the ref on the partial 16652882Svi117747 * dialog, we release it here and incr the 16662882Svi117747 * ref on the new dialog which will be 16672882Svi117747 * released by the caller. 16682882Svi117747 */ 16692882Svi117747 (void) pthread_mutex_unlock( 16702882Svi117747 &_dialog->sip_dlg_mutex); 16712882Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 16722882Svi117747 _dialog = new_dlg; 16732882Svi117747 (void) pthread_mutex_lock( 16742882Svi117747 &_dialog->sip_dlg_mutex); 16752882Svi117747 SIP_DLG_REFCNT_INCR(_dialog); 16762882Svi117747 } else { 16772882Svi117747 int index; 16782882Svi117747 16792882Svi117747 /* 16802882Svi117747 * take it out of the list so that further 16812882Svi117747 * responses will not result in a dialog. 16822882Svi117747 * We will have an extra refcount when we 16832882Svi117747 * come back from sip_complete_dialog(), i.e. 16842882Svi117747 * one when the partial dialog was created - 16852882Svi117747 * in sip_seed_dialog(), one held by the caller 16862882Svi117747 * and one that will be added by 16872882Svi117747 * sip_complete_dialog(). We need to release 16882882Svi117747 * the one added by the sip_seed_dialog(), 16892882Svi117747 * since the one in sip_complete_dialog() 16902882Svi117747 * is for the same purpose. 16912882Svi117747 */ 16922882Svi117747 if (SIP_IS_TIMER_RUNNING( 16932882Svi117747 _dialog->sip_dlg_timer)) { 16942882Svi117747 SIP_CANCEL_TIMER( 16952882Svi117747 _dialog->sip_dlg_timer); 16962882Svi117747 } 16972882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 16982882Svi117747 (void) pthread_mutex_unlock( 16992882Svi117747 &_dialog->sip_dlg_mutex); 17002882Svi117747 sip_hash_delete(sip_dialog_phash, 17012882Svi117747 (void *)_dialog->sip_dlg_id, 17022882Svi117747 index, sip_dialog_dontfree); 17032882Svi117747 (void) pthread_mutex_lock( 17042882Svi117747 &_dialog->sip_dlg_mutex); 17052882Svi117747 decr_ref = B_TRUE; 17062882Svi117747 } 17072882Svi117747 } else { 17082882Svi117747 decr_ref = B_TRUE; 17092882Svi117747 } 17102882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17112882Svi117747 if ((dialog = sip_complete_dialog(sip_msg, _dialog)) == 17122882Svi117747 NULL) { 17133439Svi117747 if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref) 17143439Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 17152882Svi117747 return (NULL); 17162882Svi117747 } 17172882Svi117747 if (decr_ref) 17182882Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 17192882Svi117747 } else { 17202882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17212882Svi117747 } 17222882Svi117747 return (dialog); 17232882Svi117747 } 17242882Svi117747 17252882Svi117747 /* 17262882Svi117747 * Initialize the hash table 17272882Svi117747 */ 17282882Svi117747 void 17292882Svi117747 sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *), 17302882Svi117747 void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int)) 17312882Svi117747 { 17322882Svi117747 int cnt; 17332882Svi117747 17342882Svi117747 for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 17352882Svi117747 sip_dialog_hash[cnt].hash_count = 0; 17362882Svi117747 sip_dialog_hash[cnt].hash_head = NULL; 17372882Svi117747 sip_dialog_hash[cnt].hash_tail = NULL; 17382882Svi117747 (void) pthread_mutex_init( 17392882Svi117747 &sip_dialog_hash[cnt].sip_hash_mutex, NULL); 17402882Svi117747 sip_dialog_phash[cnt].hash_count = 0; 17412882Svi117747 sip_dialog_phash[cnt].hash_head = NULL; 17422882Svi117747 sip_dialog_phash[cnt].hash_tail = NULL; 17432882Svi117747 (void) pthread_mutex_init( 17442882Svi117747 &sip_dialog_phash[cnt].sip_hash_mutex, NULL); 17452882Svi117747 } 17462882Svi117747 if (ulp_dlg_del != NULL) 17472882Svi117747 sip_ulp_dlg_del_cb = ulp_dlg_del; 17482882Svi117747 17492882Svi117747 if (ulp_state_cb != NULL) 17502882Svi117747 sip_dlg_ulp_state_cb = ulp_state_cb; 17512882Svi117747 } 1752*4702Sgm209912 1753*4702Sgm209912 /* 1754*4702Sgm209912 * Copy the new contact header of re-INVITE 1755*4702Sgm209912 */ 1756*4702Sgm209912 void 1757*4702Sgm209912 sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg) 1758*4702Sgm209912 { 1759*4702Sgm209912 sip_header_t chdr = NULL; 1760*4702Sgm209912 sip_header_t nhdr = NULL; 1761*4702Sgm209912 1762*4702Sgm209912 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 1763*4702Sgm209912 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 1764*4702Sgm209912 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 1765*4702Sgm209912 1766*4702Sgm209912 if (chdr == NULL) 1767*4702Sgm209912 return; 1768*4702Sgm209912 1769*4702Sgm209912 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1770*4702Sgm209912 if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state 1771*4702Sgm209912 != SIP_DLG_CONFIRMED) { 1772*4702Sgm209912 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1773*4702Sgm209912 return; 1774*4702Sgm209912 } 1775*4702Sgm209912 1776*4702Sgm209912 if (((nhdr = sip_dup_header(chdr)) != NULL)) { 1777*4702Sgm209912 if (dialog->sip_dlg_new_local_contact != NULL) 1778*4702Sgm209912 sip_free_header(dialog->sip_dlg_new_local_contact); 1779*4702Sgm209912 dialog->sip_dlg_new_local_contact = nhdr; 1780*4702Sgm209912 } 1781*4702Sgm209912 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 1782*4702Sgm209912 } 1783