OpenSolaris_b135/lib/libsip/common/sip_dialog_ui.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <sip.h>

#include "sip_msg.h"
#include "sip_miscdefs.h"
#include "sip_parse_uri.h"
#include "sip_dialog.h"

/*
 * Create a request using the state maintained in the dialog.
 */
sip_msg_t
sip_create_dialog_req(sip_method_t method, sip_dialog_t dialog,
    char *transport, char *sent_by, int sent_by_port, char *via_param,
    uint32_t maxforward, int cseq)
{
	_sip_dialog_t	*_dialog;
	sip_msg_t	sip_msg;
	char		*uri;
	int		oldseq = 0;

	if (!sip_manage_dialog || dialog == NULL || transport == NULL ||
	    sent_by == NULL) {
		return (NULL);
	}
	if ((sip_msg = sip_new_msg()) == NULL)
		return (NULL);
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	/*
	 * Depending on the route set, if any, the request URI could either
	 * be the contact URI or the 1st URI from the route set.
	 */
	uri = (char *)sip_dialog_req_uri(_dialog);
	if (uri == NULL)
		goto err_ret;
	if (sip_add_request_line(sip_msg, method, uri) != 0) {
		free(uri);
		goto err_ret;
	}
	free(uri);
	if (sip_copy_header(sip_msg, _dialog->sip_dlg_local_uri_tag, NULL) != 0)
		goto err_ret;
	if (sip_copy_header(sip_msg, _dialog->sip_dlg_remote_uri_tag, NULL) !=
	    0) {
		goto err_ret;
	}
	if (sip_copy_header(sip_msg, _dialog->sip_dlg_local_contact, NULL) != 0)
		goto err_ret;
	if (sip_add_via(sip_msg, transport, sent_by, sent_by_port, via_param) !=
	    0) {
		goto err_ret;
	}
	if (sip_add_maxforward(sip_msg, maxforward) != 0)
		goto err_ret;
	if (sip_copy_header(sip_msg, _dialog->sip_dlg_call_id, NULL) != 0)
		goto err_ret;
	if (cseq < 0) {
		if (_dialog->sip_dlg_local_cseq == 0)
			_dialog->sip_dlg_local_cseq = 1;
		oldseq = _dialog->sip_dlg_local_cseq;
		cseq = ++_dialog->sip_dlg_local_cseq;
	}
	if (sip_add_cseq(sip_msg, method, cseq) != 0) {
		_dialog->sip_dlg_local_cseq = oldseq;
		goto err_ret;
	}
	/*
	 * The route set, even if empty, overrides any pre-existing route set.
	 * If the route set is empty, the UAC MUST NOT add a Route header
	 * field to the request.
	 */
	(void) sip_delete_header_by_name(sip_msg, SIP_ROUTE);

	if (_dialog->sip_dlg_route_set != NULL) {
		if (sip_copy_header(sip_msg, _dialog->sip_dlg_route_set,
		    NULL) != 0) {
			_dialog->sip_dlg_local_cseq = oldseq;
			goto err_ret;
		}
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (sip_msg);
err_ret:
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	sip_free_msg(sip_msg);
	return (NULL);
}

/*
 * Create a request using the state maintained in the dialog. The request will
 * not have Contact header.
 */
sip_msg_t
sip_create_dialog_req_nocontact(sip_method_t method, sip_dialog_t dialog,
    char *transport, char *sent_by, int sent_by_port, char *via_param,
    uint32_t maxforward, int cseq)
{
	sip_msg_t	sip_msg;

	sip_msg = sip_create_dialog_req(method, dialog, transport, sent_by,
	    sent_by_port, via_param, maxforward, cseq);
	if (sip_msg != NULL) {
		if (sip_delete_header_by_name(sip_msg, SIP_CONTACT) != 0) {
			sip_free_msg(sip_msg);
			return (NULL);
		}
	}

	return (sip_msg);
}

/*
 * Get the Dialog method
 */
int
sip_get_dialog_method(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog) {
		if (error != NULL)
			*error = EINVAL;
		return (0);
	}
	if (dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (0);
	}
	_dialog = (_sip_dialog_t *)dialog;
	return (_dialog->sip_dlg_method);
}

/*
 * Get the Dialog state
 */
int
sip_get_dialog_state(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog) {
		if (error != NULL)
			*error = EINVAL;
		return (0);
	}
	if (dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (0);
	}
	_dialog = (_sip_dialog_t *)dialog;
	return (_dialog->sip_dlg_state);
}

/*
 * Return the dialog callid
 */
const sip_str_t *
sip_get_dialog_callid(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const struct sip_value	*val;
	const sip_str_t		*callid = NULL;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_call_id != NULL) {
		val = sip_get_header_value(_dialog->sip_dlg_call_id, error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		callid = &((sip_hdr_value_t *)val)->str_val;
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (callid);
}

/*
 * Return the dialog localtag.
 */
const sip_str_t *
sip_get_dialog_local_tag(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const sip_str_t		*ltag = NULL;
	const struct sip_value	*val;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_local_uri_tag != NULL) {
		val = sip_get_header_value(_dialog->sip_dlg_local_uri_tag,
		    error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		ltag = sip_get_param_value((sip_header_value_t)val, "tag",
		    error);
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (ltag);
}

/*
 * Return the dialog remotetag
 */
const sip_str_t *
sip_get_dialog_remote_tag(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const sip_str_t		*ttag = NULL;
	const struct sip_value	*val;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_remote_uri_tag != NULL) {
		val = sip_get_header_value(_dialog->sip_dlg_remote_uri_tag,
		    error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		ttag = sip_get_param_value((sip_header_value_t)val, "tag",
		    error);
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);

	return (ttag);
}

/*
 * Return the dialog localuri.
 */
const struct sip_uri *
sip_get_dialog_local_uri(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const _sip_uri_t	*luri = NULL;
	const struct sip_value	*val;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_local_uri_tag != NULL) {
		val = sip_get_header_value(_dialog->sip_dlg_local_uri_tag,
		    error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		luri = val->sip_value_parse_uri;
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);

	return ((sip_uri_t)luri);
}

/*
 * Return the dialog remoteuri.
 */
const struct sip_uri *
sip_get_dialog_remote_uri(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const _sip_uri_t	*ruri = NULL;
	const struct sip_value	*val;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_remote_uri_tag != NULL) {
		val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
		    error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		ruri = val->sip_value_parse_uri;
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return ((sip_uri_t)ruri);
}

/*
 * Return the dialog remotetarg.
 */
const struct sip_uri *
sip_get_dialog_remote_target_uri(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const struct sip_uri	*rtarg = NULL;
	const struct sip_value	*val;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_remote_target != NULL) {
		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
		    error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		rtarg = val->sip_value_parse_uri;
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);

	return ((sip_uri_t)rtarg);
}

/*
 * Return the dialog local contact uri.
 */
const struct sip_uri *
sip_get_dialog_local_contact_uri(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;
	const struct sip_uri	*lcuri = NULL;
	const struct sip_value	*val;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	if (dialog->sip_dlg_local_contact != NULL) {
		val = sip_get_header_value(_dialog->sip_dlg_local_contact,
		    error);
		if (val == NULL) {
			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
			return (NULL);
		}
		lcuri = val->sip_value_parse_uri;
	}
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);

	return ((sip_uri_t)lcuri);
}

/*
 * Return the dialog route set
 */
const sip_str_t *
sip_get_dialog_route_set(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t		*_dialog;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (NULL);
	}
	_dialog = (_sip_dialog_t *)dialog;
	if (_dialog->sip_dlg_rset.sip_str_len > 0)
		return (&_dialog->sip_dlg_rset);
	return (NULL);
}

/*
 * Return the dialog secure
 */
boolean_t
sip_is_dialog_secure(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;
	boolean_t	issecure;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (B_FALSE);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	issecure = _dialog->sip_dlg_secure;
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (issecure);
}

/*
 * Return the dialog local cseq
 */
uint32_t
sip_get_dialog_local_cseq(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;
	uint32_t	cseq;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (0);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	cseq = _dialog->sip_dlg_local_cseq;
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (cseq);
}

/*
 * Return the dialog remote cseq
 */
uint32_t
sip_get_dialog_remote_cseq(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;
	uint32_t	cseq;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (0);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	cseq = _dialog->sip_dlg_remote_cseq;
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (cseq);
}

/*
 * Return the dialog type
 */
int
sip_get_dialog_type(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;
	int		type;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (-1);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	type = _dialog->sip_dlg_type;
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (type);
}

/*
 * Return the number of messages exchanged within a dialog.
 */
int
sip_get_dialog_msgcnt(sip_dialog_t dialog, int *error)
{
	_sip_dialog_t	*_dialog;
	int		nmsgs;

	if (error != NULL)
		*error = 0;
	if (!sip_manage_dialog || dialog == NULL) {
		if (error != NULL)
			*error = EINVAL;
		return (-1);
	}
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	nmsgs = _dialog->sip_dlg_msgcnt;
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (nmsgs);
}

/*
 * Partial dialog ?
 */
boolean_t
sip_incomplete_dialog(sip_dialog_t dialog)
{
	_sip_dialog_t	*_dialog;
	boolean_t	isnew;

	if (!sip_manage_dialog || dialog == NULL)
		return (B_FALSE);
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	isnew = _dialog->sip_dlg_state == SIP_DLG_NEW;
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
	return (isnew);
}

/*
 * Hold dialog
 */
void
sip_hold_dialog(sip_dialog_t dialog)
{
	_sip_dialog_t	*_dialog;

	if (!sip_manage_dialog || dialog == NULL)
		return;
	_dialog = (_sip_dialog_t *)dialog;
	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
	SIP_DLG_REFCNT_INCR(_dialog);
	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
}

/*
 * Release dialog
 */
void
sip_release_dialog(sip_dialog_t dialog)
{
	_sip_dialog_t	*_dialog;

	if (!sip_manage_dialog || dialog == NULL)
		return;
	_dialog = (_sip_dialog_t *)dialog;
	SIP_DLG_REFCNT_DECR(_dialog);
}

/*
 * Delete a dialog
 */
void
sip_delete_dialog(sip_dialog_t dialog)
{
	if (!sip_manage_dialog || dialog == NULL)
		return;
	sip_dialog_terminate(dialog, NULL);
}