sip_dialog.c revision d8a40387f8abe74df38502eca4b369b9eada4864
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * CDDL HEADER START
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The contents of this file are subject to the terms of the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Common Development and Distribution License (the "License").
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * You may not use this file except in compliance with the License.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * See the License for the specific language governing permissions
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * and limitations under the License.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * When distributing Covered Code, include this CDDL HEADER in each
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * If applicable, add the following below this CDDL HEADER, with the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * fields enclosed by brackets "[]" replaced with your own identifying
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * information: Portions Copyright [yyyy] [name of copyright owner]
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * CDDL HEADER END
2c2c41837e330b002c4220a39638150db504fe0evi * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Use is subject to license terms.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#pragma ident "%Z%%M% %I% %E% SMI"
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Dialog state change callback function
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vivoid (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vivoid (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Exchange From/To header
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Complete dialog hash table
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Partial dialog hash table
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Route set structure
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vitypedef struct sip_dlg_route_set_s {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_t sip_seed_dialog(sip_conn_object_t, _sip_msg_t *,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_t sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_t sip_update_dialog(sip_dialog_t, _sip_msg_t *);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic int sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Timer object for partial dialogs
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vitypedef struct sip_dialog_timer_obj_s {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * To avoid duplication all over the place
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic void
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Get the route information from the 'value' and add it to the route
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * check for CRLF
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * loose routing
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Check if the 'lr' param is present for this route.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error != 0) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Depending on the route-set, determine the request URI.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi val = sip_get_header_value(_dialog->sip_dlg_remote_target,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Free the route set.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Recompute route-set
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * If the route set is empty, the UAC MUST place the remote target URI
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * into the Request-URI. The UAC MUST NOT add a Route header field to
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * the request.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * If the route set is not empty, and the first URI in the route set
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * contains the lr parameter (see Section 19.1.1), the UAC MUST place
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * the remote target URI into the Request-URI and MUST include a Route
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * header field containing the route set values in order, including all
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * parameters.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * If the route set is not empty, and its first URI does not contain the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * lr parameter, the UAC MUST place the first URI from the route set
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * into the Request-URI, stripping any parameters that are not allowed
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * in a Request-URI. The UAC MUST add a Route header field containing
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * the remainder of the route set values in order, including all
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * parameters. The UAC MUST then place the remote target URI into the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Route header field as the last value.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sizeof (char);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * rcnt - 1 is for the number of COMMAs
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * UAC Behavior
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The route set MUST be set to the list of URIs in the Record-Route
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * header field from the response, taken in reverse order and preserving
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * all URI parameters.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * UAS behavior
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The route set MUST be set to the list of URIs in the Record-Route
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * header field from the request, taken in order and preserving all URI
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * parameters.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Add one for COMMA
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Check for CRLF
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * UAS behavior:
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The remote sequence number MUST be set to the value of the sequence
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * number in the CSeq header field of the request. The local sequence
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * number MUST be empty. The call identifier component of the dialog ID
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * MUST be set to the value of the Call-ID in the request. The local
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * tag component of the dialog ID MUST be set to the tag in the To field
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * in the response to the request (which always includes a tag), and the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * remote tag component of the dialog ID MUST be set to the tag from the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * From field in the request. A UAS MUST be prepared to receive a
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * request without a tag in the From field, in which case the tag is
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * considered to have a value of null.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The remote URI MUST be set to the URI in the From field, and the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * local URI MUST be set to the URI in the To field.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The remote target MUST be set to the URI from the Contact header field
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * of the request.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * UAC behavior:
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The local sequence number MUST be set to the value of the sequence
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * number in the CSeq header field of the request. The remote sequence
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * number MUST be empty (it is established when the remote UA sends a
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * request within the dialog). The call identifier component of the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * dialog ID MUST be set to the value of the Call-ID in the request.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The local tag component of the dialog ID MUST be set to the tag in
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * the From field in the request, and the remote tag component of the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * dialog ID MUST be set to the tag in the To field of the response. A
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * UAC MUST be prepared to receive a response without a tag in the To
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * field, in which case the tag is considered to have a value of null.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The remote URI MUST be set to the URI in the To field, and the local
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * URI MUST be set to the URI in the From field.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The remote target MUST be set to the URI from the Contact header field
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * of the response.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * This is the routine that seeds a dialog.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi method = sip_get_request_method((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Only INVITE and SUBSCRIBE supported
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error != 0 || (method != INVITE && method != SUBSCRIBE))
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * A request outside of a dialog MUST NOT contain a To tag
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Sanity check since we just store the headers in the dialog
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * We will take the TO header with the tag when we complete this
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * We take the remote target from the incoming request on the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * UAS. For the UAC, we will take it from the response.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
d8a40387f8abe74df38502eca4b369b9eada4864gm * We take the local contact from the originating request on
d8a40387f8abe74df38502eca4b369b9eada4864gm * UAC. For the UAS, we will take it from the response.
d8a40387f8abe74df38502eca4b369b9eada4864gm if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) ==
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Get the route set from the request, if present
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Set the partial dialog timer with the INVITE timeout val
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Since at the client we never pass the partial dialog, we need not
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * invoke the callback when the partial dialog self-destructs.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Add it to the partial hash table
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * When creating a dialog from a NOTIFY request, we need to get the FROM
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * header for the dialog from the TO header of the NOTIFY.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sizeof (char) + SIP_SPACE_LEN;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * FROM and TO have common parsing functions
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi newhdr->sip_header_functions = hdr->sip_header_functions;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * This is the response that completes the dialog that was created
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * in sip_seed_dialog().
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi method = sip_get_request_method((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error == 0) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error != 0 ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Per 12.1 the UAS must include the contact header
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * for a dialog establishing response, so if we
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * don't find one, we terminate it.
d8a40387f8abe74df38502eca4b369b9eada4864gm * We take the local contact for UAS Dialog from the response (either
d8a40387f8abe74df38502eca4b369b9eada4864gm * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE
d8a40387f8abe74df38502eca4b369b9eada4864gm * request)
d8a40387f8abe74df38502eca4b369b9eada4864gm if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Cancel the partial dialog timer
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi val = sip_get_header_value(dialog->sip_dlg_local_uri_tag,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Get an ID for this dialog
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Add it to the hash table
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * So that sip_dialog_delete() does not try to remove
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * this from the hash table.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Check if this dialog is a match.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Don't delete, just take it out of the hash
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Free resources associated with the dialog, the object will be removed
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * from the hash list by sip_hash_delete.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The UAS will receive the request from the transaction layer. If the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * request has a tag in the To header field, the UAS core computes the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * dialog identifier corresponding to the request and compares it with
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * existing dialogs. If there is a match, this is a mid-dialog request.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * We keep this partial dialog for the duration of the INVITE
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * transaction timeout duration, i.e. Timer B.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_dialog_timer_obj_t *tim_obj = (sip_dialog_timer_obj_t *)args;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi _sip_dialog_t *dialog = (_sip_dialog_t *)tim_obj->dialog;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Terminate a dialog
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Delete a dialog
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * partial dialog, not in the hash table
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Cancel the partial dialog timer
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Get the remote target from the CONTACT header from the 200 OK response
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Process an incoming request/response
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/* ARGSUSED */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (sip_get_request_method((sip_msg_t)sip_msg, &error) !=
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Requests that do not change in any way the state
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * of a dialog may be received within a dialog.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * They are processed as if they had been received
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * outside the dialog.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * For dialogs that have been established with an
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * INVITE, the only target refresh request defined is
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * re-INVITE.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Target-Refresh request
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (_dialog->sip_dlg_method == INVITE && method == INVITE) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error == 0) {
5878c602b2d040000355d54d766aac95446139a9gm return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Let the user delete the dialog if it is not a 1XX/2XX resp
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * for an early INVITE dialog.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Copy partial dialog to create a complete dialog
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_dup_header(dialog->sip_dlg_remote_target)) == NULL ||
d8a40387f8abe74df38502eca4b369b9eada4864gm sip_dup_header(dialog->sip_dlg_local_contact)) == NULL ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Update the dialog using the response
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi method = sip_get_request_method((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE ||
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (error != 0) {
d8a40387f8abe74df38502eca4b369b9eada4864gm method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
d8a40387f8abe74df38502eca4b369b9eada4864gm if (error != 0) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Let the user delete the dialog if it is not a 1XX/2XX resp
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * for an early dialog.
d8a40387f8abe74df38502eca4b369b9eada4864gm * If we recieved provisional response before we would
d8a40387f8abe74df38502eca4b369b9eada4864gm * not have captured local contact. So store it now.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * This decr/incr dance is because the caller
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * has incremented the ref on the partial
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * dialog, we release it here and incr the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * ref on the new dialog which will be
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * released by the caller.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * take it out of the list so that further
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * responses will not result in a dialog.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * We will have an extra refcount when we
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * come back from sip_complete_dialog(), i.e.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * one when the partial dialog was created -
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * in sip_seed_dialog(), one held by the caller
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * and one that will be added by
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * sip_complete_dialog(). We need to release
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * the one added by the sip_seed_dialog(),
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * since the one in sip_complete_dialog()
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * is for the same purpose.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Initialize the hash table
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *),
d8a40387f8abe74df38502eca4b369b9eada4864gm * Copy the new contact header of re-INVITE
d8a40387f8abe74df38502eca4b369b9eada4864gmsip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg)
d8a40387f8abe74df38502eca4b369b9eada4864gm chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);