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
sip_release_dialog_res(_sip_dialog_t * dialog)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 *
sip_add_route_to_set(sip_hdr_value_t * value)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 *
sip_dialog_req_uri(sip_dialog_t dialog)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
sip_dialog_free_rset(sip_dlg_route_set_t * rset)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
sip_dlg_recompute_rset(_sip_dialog_t * dialog,_sip_msg_t * sip_msg,int what)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
sip_dialog_set_route_hdr(_sip_dialog_t * dialog,sip_dlg_route_set_t * rset_head,int rcnt,int rlen)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
sip_dialog_get_route_set(_sip_dialog_t * dialog,_sip_msg_t * sip_msg,int what)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
sip_seed_dialog(sip_conn_object_t obj,_sip_msg_t * sip_msg,boolean_t dlg_on_fork,int dlg_type)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 *
sip_dlg_xchg_from_to(sip_msg_t sip_msg,int what)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
sip_complete_dialog(_sip_msg_t * sip_msg,_sip_dialog_t * dialog)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
sip_dialog_match(void * obj,void * hindex)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
sip_dialog_dontfree(void * obj,void * hindex,int * found)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
sip_dialog_free(void * obj,void * hindex,int * found)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
sip_dialog_find(_sip_msg_t * sip_msg)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
sip_dlg_self_destruct(void * args)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
sip_dialog_terminate(_sip_dialog_t * dialog,sip_msg_t sip_msg)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
sip_dialog_delete(_sip_dialog_t * dialog)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
sip_get_rtarg(_sip_dialog_t * dialog,_sip_msg_t * sip_msg)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
sip_dialog_process(_sip_msg_t * sip_msg,sip_dialog_t * sip_dialog)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 *
sip_copy_partial_dialog(_sip_dialog_t * dialog)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
sip_update_dialog(sip_dialog_t dialog,_sip_msg_t * sip_msg)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
sip_dialog_init(void (* ulp_dlg_del)(sip_dialog_t,sip_msg_t,void *),void (* ulp_state_cb)(sip_dialog_t,sip_msg_t,int,int))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
sip_dialog_add_new_contact(sip_dialog_t dialog,_sip_msg_t * sip_msg)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 *
sip_get_dialog_state_str(int state)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