12882Svi117747 /* 22882Svi117747 * CDDL HEADER START 32882Svi117747 * 42882Svi117747 * The contents of this file are subject to the terms of the 52882Svi117747 * Common Development and Distribution License (the "License"). 62882Svi117747 * You may not use this file except in compliance with the License. 72882Svi117747 * 82882Svi117747 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92882Svi117747 * or http://www.opensolaris.org/os/licensing. 102882Svi117747 * See the License for the specific language governing permissions 112882Svi117747 * and limitations under the License. 122882Svi117747 * 132882Svi117747 * When distributing Covered Code, include this CDDL HEADER in each 142882Svi117747 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152882Svi117747 * If applicable, add the following below this CDDL HEADER, with the 162882Svi117747 * fields enclosed by brackets "[]" replaced with your own identifying 172882Svi117747 * information: Portions Copyright [yyyy] [name of copyright owner] 182882Svi117747 * 192882Svi117747 * CDDL HEADER END 202882Svi117747 */ 212882Svi117747 222882Svi117747 /* 23*5842Sgm209912 * Copyright 2008 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 { 111*5842Sgm209912 int count = 0; 112*5842Sgm209912 sip_msg_chain_t *msg_chain; 113*5842Sgm209912 sip_msg_chain_t *nmsg_chain; 1142882Svi117747 115*5842Sgm209912 if (dialog->sip_dlg_ref_cnt != 0) { 116*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 117*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 118*5842Sgm209912 } 1192882Svi117747 assert(dialog->sip_dlg_ref_cnt == 0); 1202882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 1212882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 1222882Svi117747 if (dialog->sip_dlg_call_id != NULL) 1232882Svi117747 sip_free_header(dialog->sip_dlg_call_id); 1242882Svi117747 if (dialog->sip_dlg_local_uri_tag != NULL) 1252882Svi117747 sip_free_header(dialog->sip_dlg_local_uri_tag); 1262882Svi117747 if (dialog->sip_dlg_remote_uri_tag != NULL) 1272882Svi117747 sip_free_header(dialog->sip_dlg_remote_uri_tag); 1282882Svi117747 if (dialog->sip_dlg_remote_target != NULL) 1292882Svi117747 sip_free_header(dialog->sip_dlg_remote_target); 1304702Sgm209912 if (dialog->sip_dlg_local_contact != NULL) 1314702Sgm209912 sip_free_header(dialog->sip_dlg_local_contact); 1324702Sgm209912 if (dialog->sip_dlg_new_local_contact != NULL) 1334702Sgm209912 sip_free_header(dialog->sip_dlg_new_local_contact); 1342882Svi117747 if (dialog->sip_dlg_route_set != NULL) 1352882Svi117747 sip_free_header(dialog->sip_dlg_route_set); 1362882Svi117747 if (dialog->sip_dlg_event != NULL) 1372882Svi117747 sip_free_header(dialog->sip_dlg_event); 1382882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 1392882Svi117747 free(dialog->sip_dlg_req_uri.sip_str_ptr); 1402882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 1412882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 1422882Svi117747 } 1432882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 1442882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 1452882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 1462882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 1472882Svi117747 } 148*5842Sgm209912 for (count = 0; count <= SIP_DLG_DESTROYED; count++) { 149*5842Sgm209912 msg_chain = dialog->sip_dlg_log[count].sip_msgs; 150*5842Sgm209912 while (msg_chain != NULL) { 151*5842Sgm209912 nmsg_chain = msg_chain->next; 152*5842Sgm209912 if (msg_chain->sip_msg != NULL) 153*5842Sgm209912 free(msg_chain->sip_msg); 154*5842Sgm209912 free(msg_chain); 155*5842Sgm209912 msg_chain = nmsg_chain; 156*5842Sgm209912 } 157*5842Sgm209912 } 1582882Svi117747 (void) pthread_mutex_destroy(&dialog->sip_dlg_mutex); 1592882Svi117747 free(dialog); 1602882Svi117747 } 1612882Svi117747 1622882Svi117747 /* 1632882Svi117747 * Get the route information from the 'value' and add it to the route 1642882Svi117747 * set. 1652882Svi117747 */ 1662882Svi117747 static sip_dlg_route_set_t * 1672882Svi117747 sip_add_route_to_set(sip_hdr_value_t *value) 1682882Svi117747 { 1692882Svi117747 int vlen = 0; 1702882Svi117747 sip_dlg_route_set_t *rset; 1712882Svi117747 char *crlf; 1722882Svi117747 const sip_param_t *uri_param; 1732882Svi117747 int error; 1742882Svi117747 1752882Svi117747 rset = calloc(1, sizeof (*rset)); 1762882Svi117747 if (rset == NULL) 1772882Svi117747 return (NULL); 1782882Svi117747 rset->sip_dlg_route_next = NULL; 1792882Svi117747 vlen = value->sip_value_end - value->sip_value_start; 1802882Svi117747 1812882Svi117747 /* 1822882Svi117747 * check for CRLF 1832882Svi117747 */ 1842882Svi117747 crlf = value->sip_value_end - strlen(SIP_CRLF); 1852882Svi117747 while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 1862882Svi117747 vlen -= strlen(SIP_CRLF); 1872882Svi117747 crlf -= strlen(SIP_CRLF); 1882882Svi117747 } 1892882Svi117747 rset->sip_dlg_route = calloc(1, vlen + 1); 1902882Svi117747 if (rset->sip_dlg_route == NULL) { 1912882Svi117747 free(rset); 1922882Svi117747 return (NULL); 1932882Svi117747 } 1942882Svi117747 /* 1952882Svi117747 * loose routing 1962882Svi117747 */ 1972882Svi117747 rset->sip_dlg_route_lr = B_FALSE; 1982882Svi117747 (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen); 1992882Svi117747 rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route + 2002882Svi117747 (value->cftr_uri.sip_str_ptr - value->sip_value_start); 2012882Svi117747 rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len; 2022882Svi117747 rset->sip_dlg_route[vlen] = '\0'; 2032882Svi117747 2042882Svi117747 assert(value->sip_value_parsed_uri != NULL); 2052882Svi117747 /* 2062882Svi117747 * Check if the 'lr' param is present for this route. 2072882Svi117747 */ 2082882Svi117747 uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error); 2092882Svi117747 if (error != 0) { 2102882Svi117747 free(rset->sip_dlg_route); 2112882Svi117747 free(rset); 2122882Svi117747 return (NULL); 2132882Svi117747 } 2142882Svi117747 if (uri_param != NULL) { 2152882Svi117747 rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr", 2162882Svi117747 strlen("lr")); 2172882Svi117747 } 2182882Svi117747 return (rset); 2192882Svi117747 } 2202882Svi117747 2212882Svi117747 /* 2222882Svi117747 * Depending on the route-set, determine the request URI. 2232882Svi117747 */ 2242882Svi117747 char * 2252882Svi117747 sip_dialog_req_uri(sip_dialog_t dialog) 2262882Svi117747 { 2272882Svi117747 const sip_str_t *req_uri; 2282882Svi117747 char *uri; 2292882Svi117747 _sip_dialog_t *_dialog; 2302882Svi117747 2312882Svi117747 _dialog = (_sip_dialog_t *)dialog; 2322882Svi117747 if (_dialog->sip_dlg_route_set == NULL || 2332882Svi117747 _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 2342882Svi117747 const struct sip_value *val; 2352882Svi117747 2362882Svi117747 val = sip_get_header_value(_dialog->sip_dlg_remote_target, 2372882Svi117747 NULL); 2382882Svi117747 if (val == NULL) 2392882Svi117747 return (NULL); 2402882Svi117747 req_uri = &((sip_hdr_value_t *)val)->cftr_uri; 2412882Svi117747 } else { 2422882Svi117747 req_uri = &_dialog->sip_dlg_req_uri; 2432882Svi117747 } 2442882Svi117747 uri = (char *)malloc(req_uri->sip_str_len + 1); 2452882Svi117747 if (uri == NULL) 2462882Svi117747 return (NULL); 2472882Svi117747 (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len); 2482882Svi117747 uri[req_uri->sip_str_len] = '\0'; 2492882Svi117747 2502882Svi117747 return (uri); 2512882Svi117747 } 2522882Svi117747 2532882Svi117747 /* 2542882Svi117747 * Free the route set. 2552882Svi117747 */ 2562882Svi117747 void 2572882Svi117747 sip_dialog_free_rset(sip_dlg_route_set_t *rset) 2582882Svi117747 { 2592882Svi117747 sip_dlg_route_set_t *next; 2602882Svi117747 2612882Svi117747 while (rset != NULL) { 2622882Svi117747 next = rset->sip_dlg_route_next; 2632882Svi117747 rset->sip_dlg_route_next = NULL; 2642882Svi117747 free(rset->sip_dlg_route); 2652882Svi117747 free(rset); 2662882Svi117747 rset = next; 2672882Svi117747 } 2682882Svi117747 } 2692882Svi117747 2702882Svi117747 /* 2712882Svi117747 * Recompute route-set 2722882Svi117747 */ 2732882Svi117747 static int 2742882Svi117747 sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 2752882Svi117747 { 2762882Svi117747 int ret; 2772882Svi117747 2782882Svi117747 if (dialog->sip_dlg_route_set != NULL) { 2792882Svi117747 sip_free_header(dialog->sip_dlg_route_set); 2802882Svi117747 dialog->sip_dlg_route_set = NULL; 2812882Svi117747 } 2822882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 2832882Svi117747 free(dialog->sip_dlg_req_uri.sip_str_ptr); 2842882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 2852882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 2862882Svi117747 } 2872882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { 2882882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 2892882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 2902882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 2912882Svi117747 } 2922882Svi117747 ret = sip_dialog_get_route_set(dialog, sip_msg, what); 2932882Svi117747 return (ret); 2942882Svi117747 } 2952882Svi117747 2962882Svi117747 /* 2972882Svi117747 * If the route set is empty, the UAC MUST place the remote target URI 2982882Svi117747 * into the Request-URI. The UAC MUST NOT add a Route header field to 2992882Svi117747 * the request. 3002882Svi117747 * 3012882Svi117747 * If the route set is not empty, and the first URI in the route set 3022882Svi117747 * contains the lr parameter (see Section 19.1.1), the UAC MUST place 3032882Svi117747 * the remote target URI into the Request-URI and MUST include a Route 3042882Svi117747 * header field containing the route set values in order, including all 3052882Svi117747 * parameters. 3062882Svi117747 * 3072882Svi117747 * If the route set is not empty, and its first URI does not contain the 3082882Svi117747 * lr parameter, the UAC MUST place the first URI from the route set 3092882Svi117747 * into the Request-URI, stripping any parameters that are not allowed 3102882Svi117747 * in a Request-URI. The UAC MUST add a Route header field containing 3112882Svi117747 * the remainder of the route set values in order, including all 3122882Svi117747 * parameters. The UAC MUST then place the remote target URI into the 3132882Svi117747 * Route header field as the last value. 3142882Svi117747 */ 3152882Svi117747 int 3162882Svi117747 sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head, 3172882Svi117747 int rcnt, int rlen) 3182882Svi117747 { 3192882Svi117747 size_t rset_len; 3202882Svi117747 _sip_header_t *rhdr; 3212882Svi117747 char *rset; 3222882Svi117747 char *rp; 3232882Svi117747 char *rsp; 3242882Svi117747 int count; 3252882Svi117747 sip_dlg_route_set_t *route; 3262882Svi117747 boolean_t first = B_TRUE; 3272882Svi117747 const sip_str_t *to_uri; 3282882Svi117747 char *uri = NULL; 3292882Svi117747 int rspl; 3302882Svi117747 int rpl; 3312882Svi117747 332*5842Sgm209912 if (rcnt <= 0) { 333*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 334*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 335*5842Sgm209912 } 3362882Svi117747 assert(rcnt > 0); 3372882Svi117747 3382882Svi117747 dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1; 3392882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt); 3402882Svi117747 if (dialog->sip_dlg_rset.sip_str_ptr == NULL) 3412882Svi117747 return (ENOMEM); 3422882Svi117747 rsp = dialog->sip_dlg_rset.sip_str_ptr; 3432882Svi117747 rspl = rlen + rcnt; 3442882Svi117747 route = rset_head; 3452882Svi117747 rset_len = rlen; 3462882Svi117747 if (!route->sip_dlg_route_lr) { 3472882Svi117747 const struct sip_value *val; 3482882Svi117747 3492882Svi117747 val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL); 3502882Svi117747 to_uri = &((sip_hdr_value_t *)val)->cftr_uri; 3512882Svi117747 uri = (char *)malloc(to_uri->sip_str_len + 1); 3522882Svi117747 if (uri == NULL) { 3532882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3542882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3552882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3562882Svi117747 return (ENOMEM); 3572882Svi117747 } 3582882Svi117747 (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len); 3592882Svi117747 uri[to_uri->sip_str_len] = '\0'; 3602882Svi117747 rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) + 3612882Svi117747 SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 3622882Svi117747 sizeof (char); 3632882Svi117747 count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); 3642882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = malloc( 3652882Svi117747 route->sip_dlg_ruri.sip_str_len + 1); 3662882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { 3672882Svi117747 free(uri); 3682882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3692882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3702882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3712882Svi117747 return (ENOMEM); 3722882Svi117747 } 3732882Svi117747 (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp + 3742882Svi117747 (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route), 3752882Svi117747 route->sip_dlg_ruri.sip_str_len); 3762882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr[ 3772882Svi117747 route->sip_dlg_ruri.sip_str_len] = '\0'; 3782882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 3792882Svi117747 route->sip_dlg_ruri.sip_str_len; 3802882Svi117747 3812882Svi117747 rsp += count; 3822882Svi117747 rspl -= count; 3832882Svi117747 route = route->sip_dlg_route_next; 3842882Svi117747 } 3852882Svi117747 3862882Svi117747 /* 3872882Svi117747 * rcnt - 1 is for the number of COMMAs 3882882Svi117747 */ 3892882Svi117747 rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) + 3902882Svi117747 SIP_SPACE_LEN + rcnt - 1; 3912882Svi117747 rset = malloc(rset_len + 1); 3922882Svi117747 if (rset == NULL) { 3932882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 3942882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 3952882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 3962882Svi117747 return (ENOMEM); 3972882Svi117747 } 3982882Svi117747 rhdr = sip_new_header(rset_len + strlen(SIP_CRLF)); 3992882Svi117747 if (rhdr == NULL) { 4002882Svi117747 free(rset); 4012882Svi117747 free(dialog->sip_dlg_rset.sip_str_ptr); 4022882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 4032882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 4042882Svi117747 return (ENOMEM); 4052882Svi117747 } 4062882Svi117747 4072882Svi117747 rp = rset; 4082882Svi117747 rpl = rset_len + 1; 4092882Svi117747 count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON); 4102882Svi117747 rp += count; 4112882Svi117747 rpl -= count; 4122882Svi117747 4132882Svi117747 while (route != NULL) { 4142882Svi117747 if (first) { 4152882Svi117747 count = snprintf(rp, rpl, "%s", route->sip_dlg_route); 4162882Svi117747 rp += count; 4172882Svi117747 rpl -= count; 4182882Svi117747 first = B_FALSE; 4192882Svi117747 if (uri != NULL) { 4202882Svi117747 count = snprintf(rsp, rspl, "%c%s", 4212882Svi117747 SIP_COMMA, route->sip_dlg_route); 4222882Svi117747 } else { 4232882Svi117747 count = snprintf(rsp, rspl, "%s", 4242882Svi117747 route->sip_dlg_route); 4252882Svi117747 } 4262882Svi117747 rsp += count; 4272882Svi117747 rspl -= count; 4282882Svi117747 } else { 4292882Svi117747 count = snprintf(rp, rpl, "%c%s", SIP_COMMA, 4302882Svi117747 route->sip_dlg_route); 4312882Svi117747 rp += count; 4322882Svi117747 rpl -= count; 4332882Svi117747 count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, 4342882Svi117747 route->sip_dlg_route); 4352882Svi117747 rsp += count; 4362882Svi117747 rspl -= count; 4372882Svi117747 } 4382882Svi117747 route = route->sip_dlg_route_next; 4392882Svi117747 } 440*5842Sgm209912 if (rsp > dialog->sip_dlg_rset.sip_str_ptr + 441*5842Sgm209912 dialog->sip_dlg_rset.sip_str_len) { 442*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 443*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 444*5842Sgm209912 } 4452882Svi117747 assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr + 4462882Svi117747 dialog->sip_dlg_rset.sip_str_len); 4472882Svi117747 dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] = 4482882Svi117747 '\0'; 4492882Svi117747 if (uri != NULL) { 4502882Svi117747 if (first) { 4512882Svi117747 count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT, 4522882Svi117747 uri, SIP_RAQUOT); 4532882Svi117747 } else { 4542882Svi117747 count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA, 4552882Svi117747 SIP_LAQUOT, uri, SIP_RAQUOT); 4562882Svi117747 } 4572882Svi117747 rp += count; 4582882Svi117747 rpl -= count; 4592882Svi117747 free(uri); 4602882Svi117747 } 461*5842Sgm209912 if (rp > rset + rset_len) { 462*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 463*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 464*5842Sgm209912 } 4652882Svi117747 assert(rp <= rset + rset_len); 4662882Svi117747 (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1, 4672882Svi117747 "%s%s", rset, SIP_CRLF); 4682882Svi117747 free(rset); 4692882Svi117747 dialog->sip_dlg_route_set = (sip_header_t)rhdr; 4702882Svi117747 sip_dialog_free_rset(rset_head); 4712882Svi117747 return (0); 4722882Svi117747 } 4732882Svi117747 4742882Svi117747 /* 4752882Svi117747 * UAC Behavior 4762882Svi117747 * The route set MUST be set to the list of URIs in the Record-Route 4772882Svi117747 * header field from the response, taken in reverse order and preserving 4782882Svi117747 * all URI parameters. 4792882Svi117747 * 4802882Svi117747 * UAS behavior 4812882Svi117747 * The route set MUST be set to the list of URIs in the Record-Route 4822882Svi117747 * header field from the request, taken in order and preserving all URI 4832882Svi117747 * parameters. 4842882Svi117747 */ 4852882Svi117747 static int 4862882Svi117747 sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what) 4872882Svi117747 { 4882882Svi117747 sip_header_t rrhdr; 4892882Svi117747 sip_hdr_value_t *value; 4902882Svi117747 int error; 4912882Svi117747 sip_dlg_route_set_t *rset_head = NULL; 4922882Svi117747 sip_dlg_route_set_t *rset_tail = NULL; 4932882Svi117747 sip_dlg_route_set_t *rset; 4942882Svi117747 int rset_cnt = 0; 4952882Svi117747 int rset_len = 0; 4962882Svi117747 4972882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 4982882Svi117747 rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL); 4992882Svi117747 while (rrhdr != NULL) { 5002882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 5012882Svi117747 value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error); 5022882Svi117747 while (value != NULL && error == 0) { 5032882Svi117747 char *crlf; 5042882Svi117747 5052882Svi117747 if (value->sip_value_state == SIP_VALUE_BAD) { 5062882Svi117747 value = (sip_hdr_value_t *)sip_get_next_value( 5072882Svi117747 (sip_header_value_t)value, &error); 5082882Svi117747 continue; 5092882Svi117747 } 5102882Svi117747 rset = sip_add_route_to_set(value); 5112882Svi117747 if (rset == NULL) 5122882Svi117747 goto r_error; 5132882Svi117747 /* 5142882Svi117747 * Add one for COMMA 5152882Svi117747 */ 5162882Svi117747 rset_cnt++; 5172882Svi117747 rset_len += (value->sip_value_end - 5182882Svi117747 value->sip_value_start); 5192882Svi117747 /* 5202882Svi117747 * Check for CRLF 5212882Svi117747 */ 5222882Svi117747 crlf = value->sip_value_end - strlen(SIP_CRLF); 5232882Svi117747 while (crlf != NULL && 5242882Svi117747 strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { 5252882Svi117747 rset_len -= strlen(SIP_CRLF); 5262882Svi117747 crlf -= strlen(SIP_CRLF); 5272882Svi117747 } 5282882Svi117747 if (rset_head == NULL) { 529*5842Sgm209912 if (rset_tail != NULL) { 530*5842Sgm209912 sip_write_to_log((void *)dialog, 531*5842Sgm209912 SIP_DIALOG_LOG | SIP_ASSERT_ERROR, 532*5842Sgm209912 __FILE__, __LINE__); 533*5842Sgm209912 } 5342882Svi117747 assert(rset_tail == NULL); 5352882Svi117747 rset_head = rset_tail = rset; 5362882Svi117747 } else if (what == SIP_UAS_DIALOG) { 5372882Svi117747 rset_tail->sip_dlg_route_next = rset; 5382882Svi117747 rset_tail = rset; 5392882Svi117747 } else if (what == SIP_UAC_DIALOG) { 5402882Svi117747 rset->sip_dlg_route_next = rset_head; 5412882Svi117747 rset_head = rset; 5422882Svi117747 } else { 543*5842Sgm209912 sip_write_to_log((void *)dialog, 544*5842Sgm209912 SIP_DIALOG_LOG | SIP_ASSERT_ERROR, 545*5842Sgm209912 __FILE__, __LINE__); 5462882Svi117747 assert(0); 5472882Svi117747 } 5482882Svi117747 value = (sip_hdr_value_t *)sip_get_next_value( 5492882Svi117747 (sip_header_value_t)value, &error); 5502882Svi117747 } 5512882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 5522882Svi117747 rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr); 5532882Svi117747 } 5542882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 5552882Svi117747 if (rset_cnt == 0) 5562882Svi117747 return (0); 5572882Svi117747 if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt, 5582882Svi117747 rset_len) != 0) { 5592882Svi117747 goto r_error; 5602882Svi117747 } 5612882Svi117747 return (0); 5622882Svi117747 r_error: 5632882Svi117747 sip_dialog_free_rset(rset_head); 5642882Svi117747 return (ENOMEM); 5652882Svi117747 } 5662882Svi117747 5672882Svi117747 /* 5682882Svi117747 * UAS behavior: 5692882Svi117747 * The remote sequence number MUST be set to the value of the sequence 5702882Svi117747 * number in the CSeq header field of the request. The local sequence 5712882Svi117747 * number MUST be empty. The call identifier component of the dialog ID 5722882Svi117747 * MUST be set to the value of the Call-ID in the request. The local 5732882Svi117747 * tag component of the dialog ID MUST be set to the tag in the To field 5742882Svi117747 * in the response to the request (which always includes a tag), and the 5752882Svi117747 * remote tag component of the dialog ID MUST be set to the tag from the 5762882Svi117747 * From field in the request. A UAS MUST be prepared to receive a 5772882Svi117747 * request without a tag in the From field, in which case the tag is 5782882Svi117747 * considered to have a value of null. 5792882Svi117747 * The remote URI MUST be set to the URI in the From field, and the 5802882Svi117747 * local URI MUST be set to the URI in the To field. 5812882Svi117747 * The remote target MUST be set to the URI from the Contact header field 5822882Svi117747 * of the request. 5832882Svi117747 * 5842882Svi117747 * UAC behavior: 5852882Svi117747 * The local sequence number MUST be set to the value of the sequence 5862882Svi117747 * number in the CSeq header field of the request. The remote sequence 5872882Svi117747 * number MUST be empty (it is established when the remote UA sends a 5882882Svi117747 * request within the dialog). The call identifier component of the 5892882Svi117747 * dialog ID MUST be set to the value of the Call-ID in the request. 5902882Svi117747 * The local tag component of the dialog ID MUST be set to the tag in 5912882Svi117747 * the From field in the request, and the remote tag component of the 5922882Svi117747 * dialog ID MUST be set to the tag in the To field of the response. A 5932882Svi117747 * UAC MUST be prepared to receive a response without a tag in the To 5942882Svi117747 * field, in which case the tag is considered to have a value of null. 5952882Svi117747 * The remote URI MUST be set to the URI in the To field, and the local 5962882Svi117747 * URI MUST be set to the URI in the From field. 5972882Svi117747 * The remote target MUST be set to the URI from the Contact header field 5982882Svi117747 * of the response. 5992882Svi117747 */ 6002882Svi117747 6012882Svi117747 6022882Svi117747 /* 6032882Svi117747 * This is the routine that seeds a dialog. 6042882Svi117747 */ 6052882Svi117747 sip_dialog_t 6062882Svi117747 sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg, 6072882Svi117747 boolean_t dlg_on_fork, int dlg_type) 6082882Svi117747 { 6092882Svi117747 _sip_dialog_t *dialog; 6102882Svi117747 int cseq; 6112882Svi117747 sip_header_t fhdr = NULL; 6122882Svi117747 sip_header_t thdr = NULL; 6132882Svi117747 sip_header_t chdr; 6142882Svi117747 sip_header_t cihdr; 6152882Svi117747 sip_header_t evhdr = NULL; 6162882Svi117747 const struct sip_value *value; 6172882Svi117747 sip_dialog_timer_obj_t *tim_obj = NULL; 6182882Svi117747 const sip_str_t *callid; 6192882Svi117747 sip_method_t method; 6202882Svi117747 int timer1 = sip_timer_T1; 6212882Svi117747 int error; 6222882Svi117747 6232882Svi117747 if (!sip_msg_is_request((sip_msg_t)sip_msg, &error)) 6242882Svi117747 return (NULL); 6252882Svi117747 6262882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 6272882Svi117747 /* 6282882Svi117747 * Only INVITE and SUBSCRIBE supported 6292882Svi117747 */ 6302882Svi117747 if (error != 0 || (method != INVITE && method != SUBSCRIBE)) 6312882Svi117747 return (NULL); 6322882Svi117747 6332882Svi117747 /* 6342882Svi117747 * A request outside of a dialog MUST NOT contain a To tag 6352882Svi117747 */ 6362882Svi117747 if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL) 6372882Svi117747 return (NULL); 6382882Svi117747 6392882Svi117747 if (dlg_type == SIP_UAS_DIALOG) { 6402882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 6412882Svi117747 SIP_DLG_XCHG_FROM); 6422882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 6432882Svi117747 } else { 6442882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 6452882Svi117747 fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL); 6462882Svi117747 } 6472882Svi117747 cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL); 6482882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 6492882Svi117747 if (method == SUBSCRIBE) 6502882Svi117747 evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 6512882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 6522882Svi117747 if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL || 6532882Svi117747 (method == SUBSCRIBE && evhdr == NULL)) { 6542882Svi117747 if (thdr != NULL) 6552882Svi117747 sip_free_header(thdr); 6562882Svi117747 return (NULL); 6572882Svi117747 } 6582882Svi117747 6592882Svi117747 /* 6602882Svi117747 * Sanity check since we just store the headers in the dialog 6612882Svi117747 */ 6622882Svi117747 if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL || 6632882Svi117747 sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 6642882Svi117747 ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) || 6652882Svi117747 (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL || 6662882Svi117747 sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL || 6672882Svi117747 ((value = sip_get_header_value(chdr, NULL)) == NULL) || 6682882Svi117747 sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { 6692882Svi117747 if (thdr != NULL) 6702882Svi117747 sip_free_header(thdr); 6712882Svi117747 return (NULL); 6722882Svi117747 } 6732882Svi117747 6742882Svi117747 tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t)); 6752882Svi117747 if (tim_obj == NULL) { 6762882Svi117747 if (thdr != NULL) 6772882Svi117747 sip_free_header(thdr); 6782882Svi117747 return (NULL); 6792882Svi117747 } 6802882Svi117747 dialog = calloc(1, sizeof (_sip_dialog_t)); 6812882Svi117747 if (dialog == NULL) { 6822882Svi117747 if (thdr != NULL) 6832882Svi117747 sip_free_header(thdr); 6842882Svi117747 return (NULL); 6852882Svi117747 } 6862882Svi117747 /* 6872882Svi117747 * We will take the TO header with the tag when we complete this 6882882Svi117747 * dialog 6892882Svi117747 */ 6902882Svi117747 if (dlg_type == SIP_UAS_DIALOG) { 6912882Svi117747 dialog->sip_dlg_remote_uri_tag = thdr; 6922882Svi117747 /* 6932882Svi117747 * We take the remote target from the incoming request on the 6942882Svi117747 * UAS. For the UAC, we will take it from the response. 6952882Svi117747 */ 6962882Svi117747 if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == 6972882Svi117747 NULL) { 6982882Svi117747 goto dia_err; 6992882Svi117747 } 7002882Svi117747 } else { 7012882Svi117747 if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == 7022882Svi117747 NULL) { 7032882Svi117747 goto dia_err; 7042882Svi117747 } 7054702Sgm209912 /* 7064702Sgm209912 * We take the local contact from the originating request on 7074702Sgm209912 * UAC. For the UAS, we will take it from the response. 7084702Sgm209912 */ 7094702Sgm209912 if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) == 7104702Sgm209912 NULL) { 7114702Sgm209912 goto dia_err; 7124702Sgm209912 } else { 7134702Sgm209912 dialog->sip_dlg_new_local_contact = NULL; 7144702Sgm209912 } 7152882Svi117747 } 7162882Svi117747 if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) 7172882Svi117747 goto dia_err; 7182882Svi117747 if (method == SUBSCRIBE) { 7192882Svi117747 dialog->sip_dlg_event = sip_dup_header(evhdr); 7202882Svi117747 if (dialog->sip_dlg_event == NULL) { 7212882Svi117747 goto dia_err; 7222882Svi117747 } 7232882Svi117747 } 7242882Svi117747 dialog->sip_dlg_rset.sip_str_ptr = NULL; 7252882Svi117747 dialog->sip_dlg_rset.sip_str_len = 0; 7262882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr = NULL; 7272882Svi117747 dialog->sip_dlg_req_uri.sip_str_len = 0; 7282882Svi117747 /* 7292882Svi117747 * Get the route set from the request, if present 7302882Svi117747 */ 7312882Svi117747 if (dlg_type == SIP_UAS_DIALOG && 7322882Svi117747 sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) { 7332882Svi117747 goto dia_err; 7342882Svi117747 } 7352882Svi117747 if (dlg_type == SIP_UAC_DIALOG) 7362882Svi117747 dialog->sip_dlg_local_cseq = cseq; 7372882Svi117747 else 7382882Svi117747 dialog->sip_dlg_remote_cseq = cseq; 7392882Svi117747 dialog->sip_dlg_type = dlg_type; 7402882Svi117747 dialog->sip_dlg_on_fork = dlg_on_fork; 7412882Svi117747 dialog->sip_dlg_method = method; 7422882Svi117747 /* 7432882Svi117747 * Set the partial dialog timer with the INVITE timeout val 7442882Svi117747 */ 7452882Svi117747 if (sip_conn_timer1 != NULL) 7462882Svi117747 timer1 = sip_conn_timer1(obj); 7472882Svi117747 SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1); 7482882Svi117747 tim_obj->dialog = dialog; 7492882Svi117747 /* 7502882Svi117747 * Since at the client we never pass the partial dialog, we need not 7512882Svi117747 * invoke the callback when the partial dialog self-destructs. 7522882Svi117747 */ 7532882Svi117747 if (dlg_type == SIP_UAS_DIALOG) 7542882Svi117747 tim_obj->func = sip_ulp_dlg_del_cb; 7552882Svi117747 SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj, 7562882Svi117747 sip_dlg_self_destruct); 7572882Svi117747 if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 7582882Svi117747 goto dia_err; 7592882Svi117747 (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); 7602882Svi117747 7612882Svi117747 if (dlg_type == SIP_UAC_DIALOG) { 7622882Svi117747 const sip_str_t *local_tag; 7632882Svi117747 7642882Svi117747 local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 765*5842Sgm209912 if (local_tag == NULL) { 766*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 767*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 768*5842Sgm209912 } 7692882Svi117747 assert(local_tag != NULL); 7702882Svi117747 sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len, 7712882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 7722882Svi117747 NULL, 0, NULL, 0, NULL, 0, NULL, 0, 7732882Svi117747 (uchar_t *)dialog->sip_dlg_id); 7742882Svi117747 7752882Svi117747 7762882Svi117747 /* 7772882Svi117747 * Add it to the partial hash table 7782882Svi117747 */ 7792882Svi117747 if (sip_hash_add(sip_dialog_phash, (void *)dialog, 7802882Svi117747 SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 7812882Svi117747 goto dia_err; 7822882Svi117747 } 7832882Svi117747 } 784*5842Sgm209912 785*5842Sgm209912 dialog->sip_dlg_msgcnt = 1; 786*5842Sgm209912 sip_add_log(&dialog->sip_dlg_log[dialog->sip_dlg_state], 787*5842Sgm209912 (sip_msg_t)sip_msg, dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG); 788*5842Sgm209912 7892882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 7902882Svi117747 return ((sip_dialog_t)dialog); 7912882Svi117747 dia_err: 7922882Svi117747 sip_release_dialog_res(dialog); 7932882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 7942882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 7952882Svi117747 if (tim_obj != NULL) 7962882Svi117747 free(tim_obj); 7972882Svi117747 return (NULL); 7982882Svi117747 } 7992882Svi117747 8002882Svi117747 /* 8012882Svi117747 * When creating a dialog from a NOTIFY request, we need to get the FROM 8022882Svi117747 * header for the dialog from the TO header of the NOTIFY. 8032882Svi117747 */ 8042882Svi117747 _sip_header_t * 8052882Svi117747 sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what) 8062882Svi117747 { 8072882Svi117747 int len; 8082882Svi117747 _sip_header_t *newhdr; 8092882Svi117747 int cnt; 8102882Svi117747 const struct sip_header *hdr; 8112882Svi117747 int hdrsize; 8122882Svi117747 int error; 8132882Svi117747 8142882Svi117747 hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM : 8152882Svi117747 SIP_TO, NULL, &error); 8162882Svi117747 if (error != 0 || hdr == NULL) 8172882Svi117747 return (NULL); 8182882Svi117747 if (sip_parse_goto_values((_sip_header_t *)hdr) != 0) 8192882Svi117747 return (NULL); 8202882Svi117747 len = hdr->sip_hdr_end - hdr->sip_hdr_current; 8212882Svi117747 if (what == SIP_DLG_XCHG_FROM) { 8222882Svi117747 hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) + 8232882Svi117747 SIP_SPACE_LEN; 8242882Svi117747 } else { 8252882Svi117747 hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN + 8262882Svi117747 sizeof (char) + SIP_SPACE_LEN; 8272882Svi117747 } 8282882Svi117747 newhdr = sip_new_header(hdrsize); 8292882Svi117747 if (newhdr == NULL) 8302882Svi117747 return (NULL); 8312882Svi117747 if (what == SIP_DLG_XCHG_FROM) { 8322882Svi117747 cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 8332882Svi117747 "%s %c ", SIP_TO, SIP_HCOLON); 8342882Svi117747 } else { 8352882Svi117747 cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, 8362882Svi117747 "%s %c ", SIP_FROM, SIP_HCOLON); 8372882Svi117747 } 8382882Svi117747 newhdr->sip_hdr_current += cnt; 8392882Svi117747 (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len); 8402882Svi117747 newhdr->sip_hdr_current += len; 8412882Svi117747 assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end); 8422882Svi117747 assert(hdr->sip_header_functions != NULL); 8432882Svi117747 8442882Svi117747 /* 8452882Svi117747 * FROM and TO have common parsing functions 8462882Svi117747 */ 8472882Svi117747 newhdr->sip_header_functions = hdr->sip_header_functions; 8482882Svi117747 newhdr->sip_hdr_current = newhdr->sip_hdr_start; 8492882Svi117747 8502882Svi117747 return (newhdr); 8512882Svi117747 } 8522882Svi117747 8532882Svi117747 /* 8542882Svi117747 * This is the response that completes the dialog that was created 8552882Svi117747 * in sip_seed_dialog(). 8562882Svi117747 */ 8572882Svi117747 sip_dialog_t 8582882Svi117747 sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog) 8592882Svi117747 { 8602882Svi117747 _sip_header_t *thdr; 8612882Svi117747 _sip_header_t *evhdr = NULL; 8622882Svi117747 _sip_header_t *substate = NULL; 8632882Svi117747 sip_header_t chdr = NULL; 8642882Svi117747 int resp_code; 8652882Svi117747 const sip_str_t *ttag; 8662882Svi117747 const sip_str_t *remtag; 8672882Svi117747 const sip_str_t *callid; 8682882Svi117747 const struct sip_value *val; 8692882Svi117747 sip_method_t method; 8702882Svi117747 int error = 0; 8712882Svi117747 int prev_state; 8722882Svi117747 boolean_t alloc_thdr = B_FALSE; 8732882Svi117747 8742882Svi117747 if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0) 8752882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 8762882Svi117747 else 8772882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 8782882Svi117747 if (error != 0 || dialog == NULL || 8792882Svi117747 (sip_msg_is_request((sip_msg_t)sip_msg, &error) && 8802882Svi117747 (dialog->sip_dlg_method == INVITE || method != NOTIFY))) { 8812882Svi117747 return (NULL); 8822882Svi117747 } 8832882Svi117747 if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY && 8842882Svi117747 sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 8852882Svi117747 dialog->sip_dlg_local_cseq) || 8862882Svi117747 (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY && 8872882Svi117747 sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != 8882882Svi117747 dialog->sip_dlg_remote_cseq)) { 8892882Svi117747 return (NULL); 8902882Svi117747 } 8912882Svi117747 if (method == NOTIFY) { 8922882Svi117747 const sip_str_t *sstate; 8932882Svi117747 8942882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 8952882Svi117747 SIP_DLG_XCHG_FROM); 8962882Svi117747 if (thdr == NULL) 8972882Svi117747 return (NULL); 8982882Svi117747 alloc_thdr = B_TRUE; 8992882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 9002882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 9012882Svi117747 if (chdr == NULL) { 9022882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9032882Svi117747 sip_free_header(thdr); 9042882Svi117747 return (NULL); 9052882Svi117747 } 9062882Svi117747 evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); 9072882Svi117747 if (evhdr == NULL) { 9082882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9092882Svi117747 sip_free_header(thdr); 9102882Svi117747 return (NULL); 9112882Svi117747 } 9122882Svi117747 substate = sip_search_for_header(sip_msg, 9132882Svi117747 SIP_SUBSCRIPTION_STATE, NULL); 9142882Svi117747 if (substate == NULL) { 9152882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9162882Svi117747 sip_free_header(thdr); 9172882Svi117747 return (NULL); 9182882Svi117747 } 9192882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9202882Svi117747 sstate = sip_get_substate((sip_msg_t)sip_msg, &error); 9212882Svi117747 if (sstate == NULL || error != 0) { 9222882Svi117747 sip_free_header(thdr); 9232882Svi117747 return (NULL); 9242882Svi117747 } 9252882Svi117747 if ((sstate->sip_str_len != strlen("pending") && 9262882Svi117747 sstate->sip_str_len != strlen("active")) || 9272882Svi117747 ((sstate->sip_str_len == strlen("pending") && 9282882Svi117747 strncasecmp(sstate->sip_str_ptr, "pending", 9292882Svi117747 strlen("pending")) != 0) || 9302882Svi117747 (sstate->sip_str_len == strlen("active") && 9312882Svi117747 strncasecmp(sstate->sip_str_ptr, "active", 9322882Svi117747 strlen("active")) != 0))) { 9332882Svi117747 sip_free_header(thdr); 9342882Svi117747 return (NULL); 9352882Svi117747 } 9362882Svi117747 ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); 9372882Svi117747 } else { 9382882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 9392882Svi117747 thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, 9402882Svi117747 SIP_DLG_XCHG_TO); 9412882Svi117747 alloc_thdr = B_TRUE; 9422882Svi117747 } else { 9432882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 9442882Svi117747 thdr = sip_search_for_header(sip_msg, SIP_TO, NULL); 9452882Svi117747 if (dialog->sip_dlg_remote_target == NULL) { 9462882Svi117747 chdr = sip_search_for_header(sip_msg, 9472882Svi117747 SIP_CONTACT, NULL); 9482882Svi117747 } 9492882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9502882Svi117747 } 9512882Svi117747 if (thdr == NULL) { 9522882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 9532882Svi117747 return (NULL); 9542882Svi117747 } 9552882Svi117747 ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL); 9562882Svi117747 } 9572882Svi117747 if (ttag == NULL) { 9582882Svi117747 if (alloc_thdr) 9592882Svi117747 sip_free_header(thdr); 9602882Svi117747 return (NULL); 9612882Svi117747 } 9622882Svi117747 prev_state = dialog->sip_dlg_state; 9632882Svi117747 9642882Svi117747 if (method == NOTIFY) { 9652882Svi117747 int error; 9662882Svi117747 const sip_str_t *dlg_id_val = NULL; 9672882Svi117747 const sip_str_t *event; 9682882Svi117747 const sip_str_t *id_val = NULL; 9692882Svi117747 sip_header_value_t ev_val; 9702882Svi117747 sip_hdr_value_t *dlg_ev_val = NULL; 9712882Svi117747 9722882Svi117747 event = sip_get_event((sip_msg_t)sip_msg, &error); 9732882Svi117747 if (event == NULL || error != 0) { 9742882Svi117747 sip_free_header(thdr); 9752882Svi117747 return (NULL); 9762882Svi117747 } 9772882Svi117747 ev_val = (sip_header_value_t)sip_get_header_value(evhdr, 9782882Svi117747 &error); 9792882Svi117747 if (ev_val != NULL) 9802882Svi117747 id_val = sip_get_param_value(ev_val, "id", &error); 9812882Svi117747 if (error == 0) { 9822882Svi117747 dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value( 9832882Svi117747 dialog->sip_dlg_event, &error); 9842882Svi117747 } 9852882Svi117747 if (dlg_ev_val == NULL || error != 0) { 9862882Svi117747 sip_free_header(thdr); 9872882Svi117747 return (NULL); 9882882Svi117747 } 9892882Svi117747 dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val, 9902882Svi117747 "id", &error); 9912882Svi117747 if (error != 0 || 9922882Svi117747 dlg_ev_val->str_val_len != event->sip_str_len || 9932882Svi117747 strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr, 9942882Svi117747 event->sip_str_len != 0)) { 9952882Svi117747 sip_free_header(thdr); 9962882Svi117747 return (NULL); 9972882Svi117747 } 9982882Svi117747 if ((dlg_id_val == NULL && id_val != NULL) || 9992882Svi117747 (dlg_id_val != NULL && id_val == NULL)) { 10002882Svi117747 sip_free_header(thdr); 10012882Svi117747 return (NULL); 10022882Svi117747 } else if (dlg_id_val != NULL && id_val != NULL) { 10032882Svi117747 if (dlg_id_val->sip_str_len != id_val->sip_str_len || 10042882Svi117747 strncasecmp(dlg_id_val->sip_str_ptr, 10052882Svi117747 id_val->sip_str_ptr, dlg_id_val->sip_str_len) != 10062882Svi117747 0) { 10072882Svi117747 sip_free_header(thdr); 10082882Svi117747 return (NULL); 10092882Svi117747 } 10102882Svi117747 } 10112882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 10122882Svi117747 dialog->sip_dlg_remote_uri_tag = thdr; 10132882Svi117747 if ((dialog->sip_dlg_remote_target = 10142882Svi117747 sip_dup_header(chdr)) == NULL) { 10152882Svi117747 sip_free_header(thdr); 10162882Svi117747 return (NULL); 10172882Svi117747 } 10182882Svi117747 } else { 10192882Svi117747 dialog->sip_dlg_local_uri_tag = thdr; 10202882Svi117747 } 10212882Svi117747 dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 10222882Svi117747 } else { 10232882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 10242882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1025*5842Sgm209912 if (dialog->sip_dlg_state != SIP_DLG_NEW) { 1026*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1027*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1028*5842Sgm209912 } 10292882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_NEW); 10302882Svi117747 if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) { 1031*5842Sgm209912 if (dialog->sip_dlg_type != SIP_UAC_DIALOG) { 1032*5842Sgm209912 sip_write_to_log((void *)dialog, 1033*5842Sgm209912 SIP_DIALOG_LOG | SIP_ASSERT_ERROR, 1034*5842Sgm209912 __FILE__, __LINE__); 1035*5842Sgm209912 } 10362882Svi117747 assert(dialog->sip_dlg_type == SIP_UAC_DIALOG); 10372882Svi117747 if ((dialog->sip_dlg_remote_target = 10382882Svi117747 sip_dup_header(chdr)) == NULL) { 10392882Svi117747 (void) pthread_mutex_unlock( 10402882Svi117747 &dialog->sip_dlg_mutex); 10412882Svi117747 if (alloc_thdr) 10422882Svi117747 sip_free_header(thdr); 10433439Svi117747 goto terminate_new_dlg; 10442882Svi117747 } 10452882Svi117747 if (sip_dialog_get_route_set(dialog, sip_msg, 10462882Svi117747 dialog->sip_dlg_type) != 0) { 10472882Svi117747 (void) pthread_mutex_unlock( 10482882Svi117747 &dialog->sip_dlg_mutex); 10492882Svi117747 if (alloc_thdr) 10502882Svi117747 sip_free_header(thdr); 10513439Svi117747 goto terminate_new_dlg; 10522882Svi117747 } 10532882Svi117747 } 10542882Svi117747 if (SIP_PROVISIONAL_RESP(resp_code)) { 10552882Svi117747 dialog->sip_dlg_state = SIP_DLG_EARLY; 10562882Svi117747 } else if (SIP_OK_RESP(resp_code)) { 10572882Svi117747 /* 10582882Svi117747 * Per 12.1 the UAS must include the contact header 10592882Svi117747 * for a dialog establishing response, so if we 10602882Svi117747 * don't find one, we terminate it. 10612882Svi117747 */ 10622882Svi117747 if (dialog->sip_dlg_remote_target == NULL) { 10632882Svi117747 (void) pthread_mutex_unlock( 10642882Svi117747 &dialog->sip_dlg_mutex); 10652882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 10662882Svi117747 sip_ulp_dlg_del_cb(dialog, 10672882Svi117747 (sip_msg_t)sip_msg, NULL); 10682882Svi117747 } 10692882Svi117747 if (alloc_thdr) 10702882Svi117747 sip_free_header(thdr); 10713439Svi117747 goto terminate_new_dlg; 10722882Svi117747 } 10732882Svi117747 dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 10742882Svi117747 } else { 10752882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 10762882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 10772882Svi117747 sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg, 10782882Svi117747 NULL); 10792882Svi117747 } 10802882Svi117747 if (alloc_thdr) 10812882Svi117747 sip_free_header(thdr); 10823439Svi117747 goto terminate_new_dlg; 10832882Svi117747 } 10842882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 10852882Svi117747 dialog->sip_dlg_local_uri_tag = thdr; 10862882Svi117747 } else { 10872882Svi117747 if ((dialog->sip_dlg_remote_uri_tag = 10882882Svi117747 sip_dup_header(thdr)) == NULL) { 10892882Svi117747 (void) pthread_mutex_unlock( 10902882Svi117747 &dialog->sip_dlg_mutex); 10913439Svi117747 goto terminate_new_dlg; 10922882Svi117747 } 10932882Svi117747 } 10942882Svi117747 } 10952882Svi117747 10962882Svi117747 /* 10974702Sgm209912 * We take the local contact for UAS Dialog from the response (either 10984702Sgm209912 * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE 10994702Sgm209912 * request) 11004702Sgm209912 */ 11014702Sgm209912 if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state 11024702Sgm209912 == SIP_DLG_CONFIRMED)) { 11034702Sgm209912 if (chdr == NULL) { 11044702Sgm209912 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 11054702Sgm209912 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 11064702Sgm209912 NULL); 11074702Sgm209912 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 11084702Sgm209912 } 11094702Sgm209912 if ((chdr == NULL) || ((dialog->sip_dlg_local_contact = 11104702Sgm209912 sip_dup_header(chdr)) == NULL)) { 11114702Sgm209912 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11124702Sgm209912 if (alloc_thdr) 11134702Sgm209912 sip_free_header(thdr); 11144702Sgm209912 goto terminate_new_dlg; 11154702Sgm209912 } 11164702Sgm209912 } 11174702Sgm209912 11184702Sgm209912 /* 11192882Svi117747 * Cancel the partial dialog timer 11202882Svi117747 */ 11212882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 11222882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 11232882Svi117747 11242882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 11252882Svi117747 val = sip_get_header_value(dialog->sip_dlg_local_uri_tag, 11262882Svi117747 &error); 11272882Svi117747 } else { 11282882Svi117747 val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag, 11292882Svi117747 &error); 11302882Svi117747 } 1131*5842Sgm209912 if (val == NULL || error != 0) { 1132*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1133*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1134*5842Sgm209912 } 11352882Svi117747 assert(val != NULL && error == 0); 11362882Svi117747 remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error); 11372882Svi117747 11382882Svi117747 val = sip_get_header_value(dialog->sip_dlg_call_id, &error); 11392882Svi117747 callid = &((sip_hdr_value_t *)val)->str_val; 11402882Svi117747 11412882Svi117747 /* 11422882Svi117747 * Get an ID for this dialog 11432882Svi117747 */ 11442882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 11452882Svi117747 sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len, 11462882Svi117747 ttag->sip_str_ptr, ttag->sip_str_len, 11472882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 11482882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 11492882Svi117747 } else { 11502882Svi117747 sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len, 11512882Svi117747 remtag->sip_str_ptr, remtag->sip_str_len, 11522882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 11532882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); 11542882Svi117747 } 11552882Svi117747 11562882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 11572882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11582882Svi117747 11592882Svi117747 /* 11602882Svi117747 * Add it to the hash table 11612882Svi117747 */ 11622882Svi117747 if (sip_hash_add(sip_dialog_hash, (void *)dialog, 11632882Svi117747 SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { 11643439Svi117747 terminate_new_dlg: 11652882Svi117747 /* 11662882Svi117747 * So that sip_dialog_delete() does not try to remove 11672882Svi117747 * this from the hash table. 11682882Svi117747 */ 11692882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 11702882Svi117747 if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { 11713439Svi117747 if (dialog->sip_dlg_local_uri_tag != NULL) { 11723439Svi117747 sip_free_header(dialog->sip_dlg_local_uri_tag); 11733439Svi117747 dialog->sip_dlg_local_uri_tag = NULL; 11743439Svi117747 } 11752882Svi117747 } else { 11763439Svi117747 if (dialog->sip_dlg_remote_uri_tag != NULL) { 11773439Svi117747 sip_free_header(dialog->sip_dlg_remote_uri_tag); 11783439Svi117747 dialog->sip_dlg_remote_uri_tag = NULL; 11793439Svi117747 } 11802882Svi117747 } 11812882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 11822882Svi117747 sip_dialog_terminate(dialog, (sip_msg_t)sip_msg); 11832882Svi117747 return (NULL); 11842882Svi117747 } 11852882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 11862882Svi117747 sip_dlg_ulp_state_cb((sip_dialog_t)dialog, 11872882Svi117747 (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state); 11882882Svi117747 } 11892882Svi117747 return ((sip_dialog_t)dialog); 11902882Svi117747 } 11912882Svi117747 11922882Svi117747 /* 11932882Svi117747 * Check if this dialog is a match. 11942882Svi117747 */ 11952882Svi117747 boolean_t 11962882Svi117747 sip_dialog_match(void *obj, void *hindex) 11972882Svi117747 { 11982882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 11992882Svi117747 12002882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12012882Svi117747 if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 12022882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12032882Svi117747 return (B_FALSE); 12042882Svi117747 } 12052882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, 12062882Svi117747 sizeof (dialog->sip_dlg_id)) == 0) { 12072882Svi117747 SIP_DLG_REFCNT_INCR(dialog); 12082882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12092882Svi117747 return (B_TRUE); 12102882Svi117747 } 12112882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12122882Svi117747 return (B_FALSE); 12132882Svi117747 } 12142882Svi117747 12152882Svi117747 /* 12162882Svi117747 * Don't delete, just take it out of the hash 12172882Svi117747 */ 12182882Svi117747 boolean_t 12192882Svi117747 sip_dialog_dontfree(void *obj, void *hindex, int *found) 12202882Svi117747 { 12212882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 12222882Svi117747 12232882Svi117747 *found = 0; 12242882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12252882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 12262882Svi117747 == 0) { 12272882Svi117747 *found = 1; 12282882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12292882Svi117747 return (B_TRUE); 12302882Svi117747 } 12312882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12322882Svi117747 return (B_FALSE); 12332882Svi117747 } 12342882Svi117747 12352882Svi117747 /* 12362882Svi117747 * Free resources associated with the dialog, the object will be removed 12372882Svi117747 * from the hash list by sip_hash_delete. 12382882Svi117747 */ 12392882Svi117747 boolean_t 12402882Svi117747 sip_dialog_free(void *obj, void *hindex, int *found) 12412882Svi117747 { 12422882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)obj; 12432882Svi117747 12442882Svi117747 *found = 0; 12452882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 12462882Svi117747 if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) 12472882Svi117747 == 0) { 12482882Svi117747 *found = 1; 1249*5842Sgm209912 if (dialog->sip_dlg_state != SIP_DLG_DESTROYED) { 1250*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1251*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1252*5842Sgm209912 } 12532882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED); 12542882Svi117747 if (dialog->sip_dlg_ref_cnt != 0) { 12552882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12562882Svi117747 return (B_FALSE); 12572882Svi117747 } 1258*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0); 12592882Svi117747 sip_release_dialog_res(dialog); 12602882Svi117747 return (B_TRUE); 12612882Svi117747 } 12622882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 12632882Svi117747 return (B_FALSE); 12642882Svi117747 } 12652882Svi117747 12662882Svi117747 /* 12672882Svi117747 * The UAS will receive the request from the transaction layer. If the 12682882Svi117747 * request has a tag in the To header field, the UAS core computes the 12692882Svi117747 * dialog identifier corresponding to the request and compares it with 12702882Svi117747 * existing dialogs. If there is a match, this is a mid-dialog request. 12712882Svi117747 */ 12722882Svi117747 sip_dialog_t 12732882Svi117747 sip_dialog_find(_sip_msg_t *sip_msg) 12742882Svi117747 { 12752882Svi117747 const sip_str_t *localtag; 12762882Svi117747 const sip_str_t *remtag; 12772882Svi117747 const sip_str_t *callid; 12782882Svi117747 uint16_t digest[8]; 12792882Svi117747 _sip_dialog_t *dialog; 12802882Svi117747 boolean_t is_request; 12812882Svi117747 int error; 12822882Svi117747 12832882Svi117747 is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 12842882Svi117747 if (error != 0) 12852882Svi117747 return (NULL); 12862882Svi117747 if (is_request) { 12872882Svi117747 localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 12882882Svi117747 if (error == 0) 12892882Svi117747 remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 12902882Svi117747 } else { 12912882Svi117747 remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); 12922882Svi117747 if (error == 0) 12932882Svi117747 localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); 12942882Svi117747 } 12952882Svi117747 if (error != 0) 12962882Svi117747 return (NULL); 12972882Svi117747 callid = sip_get_callid((sip_msg_t)sip_msg, &error); 12982882Svi117747 if (error != 0 || remtag == NULL || localtag == NULL || 12992882Svi117747 callid == NULL) { 13002882Svi117747 return (NULL); 13012882Svi117747 } 13022882Svi117747 sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 13032882Svi117747 remtag->sip_str_ptr, remtag->sip_str_len, 13042882Svi117747 callid->sip_str_ptr, callid->sip_str_len, 13052882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 13062882Svi117747 13072882Svi117747 dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash, 13082882Svi117747 (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match); 13092882Svi117747 if (dialog == NULL) { 13102882Svi117747 sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len, 13112882Svi117747 NULL, 0, callid->sip_str_ptr, callid->sip_str_len, 13122882Svi117747 NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest); 13132882Svi117747 dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash, 13142882Svi117747 (void *)digest, SIP_DIGEST_TO_HASH(digest), 13152882Svi117747 sip_dialog_match); 13162882Svi117747 } 13172882Svi117747 return ((sip_dialog_t)dialog); 13182882Svi117747 } 13192882Svi117747 13202882Svi117747 /* 13212882Svi117747 * We keep this partial dialog for the duration of the INVITE 13222882Svi117747 * transaction timeout duration, i.e. Timer B. 13232882Svi117747 */ 13242882Svi117747 void 13252882Svi117747 sip_dlg_self_destruct(void *args) 13262882Svi117747 { 13272882Svi117747 sip_dialog_timer_obj_t *tim_obj = (sip_dialog_timer_obj_t *)args; 13282882Svi117747 _sip_dialog_t *dialog = (_sip_dialog_t *)tim_obj->dialog; 13292882Svi117747 int index; 13302882Svi117747 13312882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 1332*5842Sgm209912 if (dialog->sip_dlg_state != SIP_DLG_NEW) { 1333*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1334*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1335*5842Sgm209912 } 13362882Svi117747 assert(dialog->sip_dlg_state == SIP_DLG_NEW); 13372882Svi117747 dialog->sip_dlg_state = SIP_DLG_DESTROYED; 13382882Svi117747 if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { 13392882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 13402882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 13412882Svi117747 sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id, 13422882Svi117747 index, sip_dialog_dontfree); 13432882Svi117747 } else { 13442882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 13452882Svi117747 } 13462882Svi117747 if (tim_obj->func != NULL) 13472882Svi117747 tim_obj->func(dialog, NULL, NULL); 13482882Svi117747 free(tim_obj); 13492882Svi117747 SIP_DLG_REFCNT_DECR(dialog); 13502882Svi117747 } 13512882Svi117747 13522882Svi117747 /* 13532882Svi117747 * Terminate a dialog 13542882Svi117747 */ 13552882Svi117747 void 13562882Svi117747 sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg) 13572882Svi117747 { 13582882Svi117747 int prev_state; 13592882Svi117747 13602882Svi117747 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 13612882Svi117747 prev_state = dialog->sip_dlg_state; 13622882Svi117747 dialog->sip_dlg_state = SIP_DLG_DESTROYED; 13632882Svi117747 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 13642882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 13652882Svi117747 sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state, 13662882Svi117747 dialog->sip_dlg_state); 13672882Svi117747 } 13682882Svi117747 SIP_DLG_REFCNT_DECR(dialog); 13692882Svi117747 } 13702882Svi117747 13712882Svi117747 /* 13722882Svi117747 * Delete a dialog 13732882Svi117747 */ 13742882Svi117747 void 13752882Svi117747 sip_dialog_delete(_sip_dialog_t *dialog) 13762882Svi117747 { 13772882Svi117747 int index; 13782882Svi117747 13792882Svi117747 /* 13802882Svi117747 * partial dialog, not in the hash table 13812882Svi117747 */ 13822882Svi117747 if (dialog->sip_dlg_local_uri_tag == NULL || 13832882Svi117747 dialog->sip_dlg_remote_uri_tag == NULL) { 13842882Svi117747 /* 13852882Svi117747 * Cancel the partial dialog timer 13862882Svi117747 */ 13872882Svi117747 if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) 13882882Svi117747 SIP_CANCEL_TIMER(dialog->sip_dlg_timer); 1389*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0); 13902882Svi117747 sip_release_dialog_res(dialog); 13912882Svi117747 return; 13922882Svi117747 } 13932882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 13942882Svi117747 sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index, 13952882Svi117747 sip_dialog_free); 13962882Svi117747 } 13972882Svi117747 13982882Svi117747 /* 13992882Svi117747 * Get the remote target from the CONTACT header from the 200 OK response 14002882Svi117747 */ 14012882Svi117747 static boolean_t 14022882Svi117747 sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg) 14032882Svi117747 { 14042882Svi117747 sip_header_t chdr; 14052882Svi117747 14062882Svi117747 if (dialog->sip_dlg_remote_target != NULL) 14072882Svi117747 return (B_TRUE); 14082882Svi117747 14092882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 14102882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 14112882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 14122882Svi117747 if (chdr == NULL) 14132882Svi117747 return (B_FALSE); 14142882Svi117747 if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL) 14152882Svi117747 return (B_FALSE); 14162882Svi117747 14172882Svi117747 return (B_TRUE); 14182882Svi117747 } 14192882Svi117747 14202882Svi117747 /* 14212882Svi117747 * Process an incoming request/response 14222882Svi117747 */ 14232882Svi117747 /* ARGSUSED */ 14242882Svi117747 int 14252882Svi117747 sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog) 14262882Svi117747 { 14272882Svi117747 boolean_t request; 14282882Svi117747 _sip_dialog_t *_dialog; 14292882Svi117747 int error; 14302882Svi117747 1431*5842Sgm209912 _dialog = (_sip_dialog_t *)*sip_dialog; 1432*5842Sgm209912 1433*5842Sgm209912 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 1434*5842Sgm209912 _dialog->sip_dlg_msgcnt++; 1435*5842Sgm209912 sip_add_log(&_dialog->sip_dlg_log[_dialog->sip_dlg_state], 1436*5842Sgm209912 (sip_msg_t)sip_msg, _dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG); 1437*5842Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1438*5842Sgm209912 14392882Svi117747 request = sip_msg_is_request((sip_msg_t)sip_msg, &error); 14402882Svi117747 if (error != 0) 14412882Svi117747 return (EINVAL); 14422882Svi117747 if (request) { 14432882Svi117747 uint32_t cseq; 14442882Svi117747 sip_method_t method; 14452882Svi117747 14462882Svi117747 cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error); 14472882Svi117747 if (error != 0) 14482882Svi117747 return (EINVAL); 14492882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 14502882Svi117747 if (error != 0) 14512882Svi117747 return (EINVAL); 14522882Svi117747 if (sip_get_request_method((sip_msg_t)sip_msg, &error) != 14532882Svi117747 method) { 14542882Svi117747 return (EINVAL); 14552882Svi117747 } 14562882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 14572882Svi117747 /* 14582882Svi117747 * Requests that do not change in any way the state 14592882Svi117747 * of a dialog may be received within a dialog. 14602882Svi117747 * They are processed as if they had been received 14612882Svi117747 * outside the dialog. 14622882Svi117747 * For dialogs that have been established with an 14632882Svi117747 * INVITE, the only target refresh request defined is 14642882Svi117747 * re-INVITE. 14652882Svi117747 */ 14662882Svi117747 if (_dialog->sip_dlg_method == INVITE && 14672882Svi117747 method == INVITE && _dialog->sip_dlg_remote_cseq != 0 && 14682882Svi117747 SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) { 14692882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14702882Svi117747 return (EPROTO); 14712882Svi117747 } 14722882Svi117747 /* 14732882Svi117747 * Target-Refresh request 14742882Svi117747 */ 14752882Svi117747 if (_dialog->sip_dlg_method == INVITE && method == INVITE) { 14762882Svi117747 sip_header_t chdr; 14772882Svi117747 sip_header_t nchdr; 14782882Svi117747 14792882Svi117747 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 14802882Svi117747 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, 14812882Svi117747 NULL); 14822882Svi117747 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 14832882Svi117747 if (chdr != NULL && 14842882Svi117747 (nchdr = sip_dup_header(chdr)) != NULL) { 14852882Svi117747 if (_dialog->sip_dlg_remote_target != NULL) { 14862882Svi117747 sip_free_header( 14872882Svi117747 _dialog->sip_dlg_remote_target); 14882882Svi117747 } 14892882Svi117747 _dialog->sip_dlg_remote_target = nchdr; 14902882Svi117747 } 14912882Svi117747 } 14922882Svi117747 _dialog->sip_dlg_remote_cseq = cseq; 14932882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 14942882Svi117747 } else { 14952882Svi117747 int resp_code; 14962882Svi117747 sip_method_t method; 14972882Svi117747 int error; 14982882Svi117747 14992882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 15002882Svi117747 if (error == 0) { 15012882Svi117747 method = sip_get_callseq_method((sip_msg_t)sip_msg, 15022882Svi117747 &error); 15032882Svi117747 } 15042882Svi117747 if (error != 0) 15052882Svi117747 return (error); 15062882Svi117747 15072882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 15084641Sgm209912 if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) { 15094641Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15104641Sgm209912 return (0); 15114641Sgm209912 } 1512*5842Sgm209912 if (_dialog->sip_dlg_state != SIP_DLG_EARLY && 1513*5842Sgm209912 _dialog->sip_dlg_state != SIP_DLG_CONFIRMED) { 1514*5842Sgm209912 sip_write_to_log((void *)_dialog, SIP_DIALOG_LOG | 1515*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1516*5842Sgm209912 } 15172882Svi117747 assert(_dialog->sip_dlg_state == SIP_DLG_EARLY || 15182882Svi117747 _dialog->sip_dlg_state == SIP_DLG_CONFIRMED); 15192882Svi117747 /* 15202882Svi117747 * Let the user delete the dialog if it is not a 1XX/2XX resp 15212882Svi117747 * for an early INVITE dialog. 15222882Svi117747 */ 15232882Svi117747 if (SIP_OK_RESP(resp_code)) { 15242882Svi117747 if (method == INVITE) { 15252882Svi117747 if (!sip_get_rtarg(_dialog, sip_msg)) { 15262882Svi117747 (void) pthread_mutex_unlock( 15272882Svi117747 &_dialog->sip_dlg_mutex); 15282882Svi117747 if (sip_ulp_dlg_del_cb != NULL) { 15292882Svi117747 sip_ulp_dlg_del_cb( 15302882Svi117747 (sip_dialog_t)_dialog, 15312882Svi117747 (sip_msg_t)sip_msg, NULL); 15322882Svi117747 } 15332882Svi117747 sip_dialog_terminate(_dialog, 15342882Svi117747 (sip_msg_t)sip_msg); 15352882Svi117747 return (0); 15362882Svi117747 } 15372882Svi117747 if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 15382882Svi117747 _dialog->sip_dlg_state = 15392882Svi117747 SIP_DLG_CONFIRMED; 1540*5842Sgm209912 (void) sip_dlg_recompute_rset(_dialog, 1541*5842Sgm209912 sip_msg, SIP_UAC_DIALOG); 15422882Svi117747 (void) pthread_mutex_unlock( 15432882Svi117747 &_dialog->sip_dlg_mutex); 15442882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 15452882Svi117747 sip_dlg_ulp_state_cb( 15462882Svi117747 (sip_dialog_t)_dialog, 15472882Svi117747 sip_msg, SIP_DLG_EARLY, 15482882Svi117747 _dialog->sip_dlg_state); 15492882Svi117747 } 15502882Svi117747 return (0); 15514702Sgm209912 } else if (_dialog->sip_dlg_new_local_contact 15524702Sgm209912 != NULL) { 1553*5842Sgm209912 if (_dialog->sip_dlg_local_contact == 1554*5842Sgm209912 NULL) { 1555*5842Sgm209912 (void) sip_write_to_log((void *) 1556*5842Sgm209912 _dialog, SIP_DIALOG_LOG | 1557*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, 1558*5842Sgm209912 __LINE__); 1559*5842Sgm209912 } 15604702Sgm209912 assert(_dialog->sip_dlg_local_contact 15614702Sgm209912 != NULL); 15624702Sgm209912 sip_free_header(_dialog-> 15634719Sgm209912 sip_dlg_local_contact); 15644702Sgm209912 _dialog->sip_dlg_local_contact = 15654702Sgm209912 _dialog->sip_dlg_new_local_contact; 15664702Sgm209912 _dialog->sip_dlg_new_local_contact = 15674702Sgm209912 NULL; 15682882Svi117747 } 15692882Svi117747 } 15702882Svi117747 } 15712882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 15722882Svi117747 } 15732882Svi117747 return (0); 15742882Svi117747 } 15752882Svi117747 15762882Svi117747 /* 15772882Svi117747 * Copy partial dialog to create a complete dialog 15782882Svi117747 */ 15792882Svi117747 _sip_dialog_t * 15802882Svi117747 sip_copy_partial_dialog(_sip_dialog_t *dialog) 15812882Svi117747 { 15822882Svi117747 _sip_dialog_t *new_dlg; 15832882Svi117747 15842882Svi117747 new_dlg = calloc(1, sizeof (_sip_dialog_t)); 15852882Svi117747 if (new_dlg == NULL) 15862882Svi117747 return (NULL); 15872882Svi117747 if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { 15882882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_ptr = 15892882Svi117747 malloc(dialog->sip_dlg_req_uri.sip_str_len + 1); 15902882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) { 15912882Svi117747 free(new_dlg); 15922882Svi117747 return (NULL); 15932882Svi117747 } 15942882Svi117747 (void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr, 15952882Svi117747 dialog->sip_dlg_req_uri.sip_str_ptr, 15962882Svi117747 dialog->sip_dlg_req_uri.sip_str_len); 15972882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_ptr[ 15982882Svi117747 dialog->sip_dlg_req_uri.sip_str_len] = '\0'; 15992882Svi117747 new_dlg->sip_dlg_req_uri.sip_str_len = 16002882Svi117747 dialog->sip_dlg_req_uri.sip_str_len; 16012882Svi117747 } 16022882Svi117747 if (dialog->sip_dlg_route_set != NULL) { 1603*5842Sgm209912 if (dialog->sip_dlg_rset.sip_str_ptr == NULL) { 1604*5842Sgm209912 sip_write_to_log((void *)dialog, SIP_DIALOG_LOG | 1605*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1606*5842Sgm209912 } 16072882Svi117747 assert(dialog->sip_dlg_rset.sip_str_ptr != NULL); 16082882Svi117747 new_dlg->sip_dlg_rset.sip_str_ptr = 16092882Svi117747 malloc(dialog->sip_dlg_rset.sip_str_len + 1); 16102882Svi117747 if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) { 16112882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 16122882Svi117747 free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 16132882Svi117747 free(new_dlg); 16142882Svi117747 return (NULL); 16152882Svi117747 } 16162882Svi117747 (void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr, 16172882Svi117747 dialog->sip_dlg_rset.sip_str_ptr, 16182882Svi117747 dialog->sip_dlg_rset.sip_str_len); 16192882Svi117747 new_dlg->sip_dlg_rset.sip_str_ptr[ 16202882Svi117747 dialog->sip_dlg_rset.sip_str_len] = '\0'; 16212882Svi117747 new_dlg->sip_dlg_rset.sip_str_len = 16222882Svi117747 dialog->sip_dlg_rset.sip_str_len; 16232882Svi117747 16242882Svi117747 new_dlg->sip_dlg_route_set = 16252882Svi117747 sip_dup_header(dialog->sip_dlg_route_set); 16262882Svi117747 if (new_dlg->sip_dlg_route_set == NULL) { 16272882Svi117747 free(new_dlg->sip_dlg_rset.sip_str_ptr); 16282882Svi117747 if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL) 16292882Svi117747 free(new_dlg->sip_dlg_req_uri.sip_str_ptr); 16302882Svi117747 free(new_dlg); 16312882Svi117747 return (NULL); 16322882Svi117747 } 16332882Svi117747 } 16342882Svi117747 if ((new_dlg->sip_dlg_local_uri_tag = 16352882Svi117747 sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL || 16362882Svi117747 (new_dlg->sip_dlg_remote_target = 16372882Svi117747 sip_dup_header(dialog->sip_dlg_remote_target)) == NULL || 16384702Sgm209912 (new_dlg->sip_dlg_local_contact = 16394702Sgm209912 sip_dup_header(dialog->sip_dlg_local_contact)) == NULL || 16402882Svi117747 (new_dlg->sip_dlg_call_id = 16412882Svi117747 sip_dup_header(dialog->sip_dlg_call_id)) == NULL) { 16422882Svi117747 sip_release_dialog_res(new_dlg); 16432882Svi117747 return (NULL); 16442882Svi117747 } 16452882Svi117747 if (dialog->sip_dlg_event != NULL) { 16462882Svi117747 new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event); 16472882Svi117747 if (new_dlg->sip_dlg_event == NULL) { 16482882Svi117747 sip_release_dialog_res(new_dlg); 16492882Svi117747 return (NULL); 16502882Svi117747 } 16512882Svi117747 } 16522882Svi117747 new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq; 16532882Svi117747 new_dlg->sip_dlg_type = dialog->sip_dlg_type; 16542882Svi117747 new_dlg->sip_dlg_on_fork = B_FALSE; 16552882Svi117747 (void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL); 16562882Svi117747 16572882Svi117747 return (new_dlg); 16582882Svi117747 } 16592882Svi117747 16602882Svi117747 /* 16612882Svi117747 * Update the dialog using the response 16622882Svi117747 */ 16632882Svi117747 sip_dialog_t 16642882Svi117747 sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg) 16652882Svi117747 { 16662882Svi117747 _sip_dialog_t *_dialog; 16672882Svi117747 boolean_t isreq; 16682882Svi117747 sip_method_t method; 16692882Svi117747 int resp_code = 0; 16702882Svi117747 int prev_state; 16712882Svi117747 boolean_t decr_ref = B_FALSE; 16722882Svi117747 int error; 16732882Svi117747 1674*5842Sgm209912 _dialog = (_sip_dialog_t *)dialog; 1675*5842Sgm209912 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 1676*5842Sgm209912 _dialog->sip_dlg_msgcnt++; 1677*5842Sgm209912 sip_add_log(&_dialog->sip_dlg_log[_dialog->sip_dlg_state], 1678*5842Sgm209912 (sip_msg_t)sip_msg, _dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG); 1679*5842Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 1680*5842Sgm209912 16812882Svi117747 isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error); 16822882Svi117747 if (error != 0) 16832882Svi117747 return (dialog); 16842882Svi117747 (void) pthread_mutex_lock(&_dialog->sip_dlg_mutex); 16852882Svi117747 if (isreq) { 16862882Svi117747 method = sip_get_request_method((sip_msg_t)sip_msg, &error); 16872882Svi117747 if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE || 16882882Svi117747 method != NOTIFY) { 16892882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16902882Svi117747 return (dialog); 16912882Svi117747 } 16922882Svi117747 } else { 16932882Svi117747 resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); 16942882Svi117747 if (error != 0) { 16952882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 16962882Svi117747 return (dialog); 16972882Svi117747 } 16984702Sgm209912 method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); 16994702Sgm209912 if (error != 0) { 17004702Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17014702Sgm209912 return (dialog); 17024702Sgm209912 } 17032882Svi117747 } 17042882Svi117747 prev_state = _dialog->sip_dlg_state; 17052882Svi117747 if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) { 17062882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17072882Svi117747 } else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) { 17082882Svi117747 /* 17092882Svi117747 * Let the user delete the dialog if it is not a 1XX/2XX resp 17102882Svi117747 * for an early dialog. 17112882Svi117747 */ 1712*5842Sgm209912 if (isreq) { 1713*5842Sgm209912 sip_write_to_log((void *)_dialog, SIP_DIALOG_LOG | 1714*5842Sgm209912 SIP_ASSERT_ERROR, __FILE__, __LINE__); 1715*5842Sgm209912 } 17162882Svi117747 assert(!isreq); 17172882Svi117747 if (SIP_OK_RESP(resp_code)) { 17182882Svi117747 _dialog->sip_dlg_state = SIP_DLG_CONFIRMED; 17194702Sgm209912 /* 17204702Sgm209912 * If we recieved provisional response before we would 17214702Sgm209912 * not have captured local contact. So store it now. 17224702Sgm209912 */ 17234702Sgm209912 if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog-> 17244702Sgm209912 sip_dlg_method == INVITE && method == INVITE) { 17254702Sgm209912 sip_header_t chdr; 17264702Sgm209912 (void) pthread_mutex_lock(&sip_msg-> 17274702Sgm209912 sip_msg_mutex); 17284702Sgm209912 chdr = sip_search_for_header(sip_msg, 17294702Sgm209912 SIP_CONTACT, NULL); 17304702Sgm209912 (void) pthread_mutex_unlock(&sip_msg-> 17314702Sgm209912 sip_msg_mutex); 17324702Sgm209912 if (chdr != NULL) { 17334702Sgm209912 _dialog->sip_dlg_local_contact 17344702Sgm209912 = sip_dup_header(chdr); 17354702Sgm209912 _dialog->sip_dlg_new_local_contact = 17364702Sgm209912 NULL; 17374702Sgm209912 } 17384702Sgm209912 } 17392882Svi117747 (void) sip_dlg_recompute_rset(_dialog, sip_msg, 17402882Svi117747 SIP_UAS_DIALOG); 1741*5842Sgm209912 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17422882Svi117747 if (sip_dlg_ulp_state_cb != NULL) { 17432882Svi117747 sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg, 17442882Svi117747 prev_state, dialog->sip_dlg_state); 17452882Svi117747 } 17462882Svi117747 } else { 17472882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17482882Svi117747 } 17492882Svi117747 } else if (_dialog->sip_dlg_state == SIP_DLG_NEW) { 17502882Svi117747 if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE && 17512882Svi117747 SIP_PROVISIONAL_RESP(resp_code)) { 17522882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 17532882Svi117747 return (dialog); 17542882Svi117747 } 17552882Svi117747 if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) { 17562882Svi117747 _sip_dialog_t *new_dlg; 17572882Svi117747 17582882Svi117747 if (_dialog->sip_dlg_on_fork) { 17592882Svi117747 new_dlg = sip_copy_partial_dialog(_dialog); 17602882Svi117747 if (new_dlg == NULL) { 17612882Svi117747 (void) pthread_mutex_unlock( 17622882Svi117747 &_dialog->sip_dlg_mutex); 17632882Svi117747 return (dialog); 17642882Svi117747 } 17652882Svi117747 /* 17662882Svi117747 * This decr/incr dance is because the caller 17672882Svi117747 * has incremented the ref on the partial 17682882Svi117747 * dialog, we release it here and incr the 17692882Svi117747 * ref on the new dialog which will be 17702882Svi117747 * released by the caller. 17712882Svi117747 */ 17722882Svi117747 (void) pthread_mutex_unlock( 17732882Svi117747 &_dialog->sip_dlg_mutex); 17742882Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 17752882Svi117747 _dialog = new_dlg; 17762882Svi117747 (void) pthread_mutex_lock( 17772882Svi117747 &_dialog->sip_dlg_mutex); 17782882Svi117747 SIP_DLG_REFCNT_INCR(_dialog); 17792882Svi117747 } else { 17802882Svi117747 int index; 17812882Svi117747 17822882Svi117747 /* 17832882Svi117747 * take it out of the list so that further 17842882Svi117747 * responses will not result in a dialog. 17852882Svi117747 * We will have an extra refcount when we 17862882Svi117747 * come back from sip_complete_dialog(), i.e. 17872882Svi117747 * one when the partial dialog was created - 17882882Svi117747 * in sip_seed_dialog(), one held by the caller 17892882Svi117747 * and one that will be added by 17902882Svi117747 * sip_complete_dialog(). We need to release 17912882Svi117747 * the one added by the sip_seed_dialog(), 17922882Svi117747 * since the one in sip_complete_dialog() 17932882Svi117747 * is for the same purpose. 17942882Svi117747 */ 17952882Svi117747 if (SIP_IS_TIMER_RUNNING( 17962882Svi117747 _dialog->sip_dlg_timer)) { 17972882Svi117747 SIP_CANCEL_TIMER( 17982882Svi117747 _dialog->sip_dlg_timer); 17992882Svi117747 } 18002882Svi117747 index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id); 18012882Svi117747 (void) pthread_mutex_unlock( 18022882Svi117747 &_dialog->sip_dlg_mutex); 18032882Svi117747 sip_hash_delete(sip_dialog_phash, 18042882Svi117747 (void *)_dialog->sip_dlg_id, 18052882Svi117747 index, sip_dialog_dontfree); 18062882Svi117747 (void) pthread_mutex_lock( 18072882Svi117747 &_dialog->sip_dlg_mutex); 18082882Svi117747 decr_ref = B_TRUE; 18092882Svi117747 } 18102882Svi117747 } else { 18112882Svi117747 decr_ref = B_TRUE; 18122882Svi117747 } 18132882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 18142882Svi117747 if ((dialog = sip_complete_dialog(sip_msg, _dialog)) == 18152882Svi117747 NULL) { 18163439Svi117747 if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref) 18173439Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 18182882Svi117747 return (NULL); 18192882Svi117747 } 18202882Svi117747 if (decr_ref) 18212882Svi117747 SIP_DLG_REFCNT_DECR(_dialog); 18222882Svi117747 } else { 18232882Svi117747 (void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex); 18242882Svi117747 } 18252882Svi117747 return (dialog); 18262882Svi117747 } 18272882Svi117747 18282882Svi117747 /* 18292882Svi117747 * Initialize the hash table 18302882Svi117747 */ 18312882Svi117747 void 18322882Svi117747 sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *), 18332882Svi117747 void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int)) 18342882Svi117747 { 18352882Svi117747 int cnt; 18362882Svi117747 18372882Svi117747 for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 18382882Svi117747 sip_dialog_hash[cnt].hash_count = 0; 18392882Svi117747 sip_dialog_hash[cnt].hash_head = NULL; 18402882Svi117747 sip_dialog_hash[cnt].hash_tail = NULL; 18412882Svi117747 (void) pthread_mutex_init( 18422882Svi117747 &sip_dialog_hash[cnt].sip_hash_mutex, NULL); 18432882Svi117747 sip_dialog_phash[cnt].hash_count = 0; 18442882Svi117747 sip_dialog_phash[cnt].hash_head = NULL; 18452882Svi117747 sip_dialog_phash[cnt].hash_tail = NULL; 18462882Svi117747 (void) pthread_mutex_init( 18472882Svi117747 &sip_dialog_phash[cnt].sip_hash_mutex, NULL); 18482882Svi117747 } 18492882Svi117747 if (ulp_dlg_del != NULL) 18502882Svi117747 sip_ulp_dlg_del_cb = ulp_dlg_del; 18512882Svi117747 18522882Svi117747 if (ulp_state_cb != NULL) 18532882Svi117747 sip_dlg_ulp_state_cb = ulp_state_cb; 18542882Svi117747 } 18554702Sgm209912 18564702Sgm209912 /* 18574702Sgm209912 * Copy the new contact header of re-INVITE 18584702Sgm209912 */ 18594702Sgm209912 void 18604702Sgm209912 sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg) 18614702Sgm209912 { 18624702Sgm209912 sip_header_t chdr = NULL; 18634702Sgm209912 sip_header_t nhdr = NULL; 18644702Sgm209912 18654702Sgm209912 (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); 18664702Sgm209912 chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); 18674702Sgm209912 (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); 18684702Sgm209912 18694702Sgm209912 if (chdr == NULL) 18704702Sgm209912 return; 18714702Sgm209912 18724702Sgm209912 (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); 18734702Sgm209912 if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state 18744702Sgm209912 != SIP_DLG_CONFIRMED) { 18754702Sgm209912 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 18764702Sgm209912 return; 18774702Sgm209912 } 18784702Sgm209912 18794702Sgm209912 if (((nhdr = sip_dup_header(chdr)) != NULL)) { 18804702Sgm209912 if (dialog->sip_dlg_new_local_contact != NULL) 18814702Sgm209912 sip_free_header(dialog->sip_dlg_new_local_contact); 18824702Sgm209912 dialog->sip_dlg_new_local_contact = nhdr; 18834702Sgm209912 } 18844702Sgm209912 (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); 18854702Sgm209912 } 1886*5842Sgm209912 1887*5842Sgm209912 /* 1888*5842Sgm209912 * Given a state, return the string - This is mostly for debug purposes 1889*5842Sgm209912 */ 1890*5842Sgm209912 char * 1891*5842Sgm209912 sip_get_dialog_state_str(int state) 1892*5842Sgm209912 { 1893*5842Sgm209912 switch (state) { 1894*5842Sgm209912 case SIP_DLG_NEW: 1895*5842Sgm209912 return ("SIP_DLG_NEW"); 1896*5842Sgm209912 case SIP_DLG_EARLY: 1897*5842Sgm209912 return ("SIP_DLG_EARLY"); 1898*5842Sgm209912 case SIP_DLG_CONFIRMED: 1899*5842Sgm209912 return ("SIP_DLG_CONFIRMED"); 1900*5842Sgm209912 case SIP_DLG_DESTROYED: 1901*5842Sgm209912 return ("SIP_DLG_DESTROYED"); 1902*5842Sgm209912 default: 1903*5842Sgm209912 return ("UNKNOWN"); 1904*5842Sgm209912 } 1905*5842Sgm209912 } 1906