summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-01-30 18:40:05 +0000
committerBenny Prijono <bennylp@teluu.com>2006-01-30 18:40:05 +0000
commit0d61adeb5f784b45f76d76dad9974f4111fb3c8c (patch)
tree4fe8830715bd6af57dd91ebca780318a645435cd /pjsip
parent7638eeee106fe58a1225f642e733629f29418818 (diff)
Finished implementation of UA layer (to be tested)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@127 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/build/pjsip.dsw24
-rw-r--r--pjsip/build/pjsip_core.dsp144
-rw-r--r--pjsip/build/pjsip_ua.dsp25
-rw-r--r--pjsip/build/test_pjsip.dsp4
-rw-r--r--pjsip/include/pjsip-ua/sip_dialog.h635
-rw-r--r--pjsip/include/pjsip.h (renamed from pjsip/include/pjsip_core.h)40
-rw-r--r--pjsip/include/pjsip/sip_auth.h12
-rw-r--r--pjsip/include/pjsip/sip_config.h4
-rw-r--r--pjsip/include/pjsip/sip_dialog.h324
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h91
-rw-r--r--pjsip/include/pjsip/sip_errno.h16
-rw-r--r--pjsip/include/pjsip/sip_module.h11
-rw-r--r--pjsip/include/pjsip/sip_msg.h524
-rw-r--r--pjsip/include/pjsip/sip_transaction.h1
-rw-r--r--pjsip/include/pjsip/sip_transport.h8
-rw-r--r--pjsip/include/pjsip/sip_types.h17
-rw-r--r--pjsip/include/pjsip/sip_ua_layer.h (renamed from pjsip/include/pjsip-ua/sip_ua.h)45
-rw-r--r--pjsip/include/pjsip/sip_uri.h16
-rw-r--r--pjsip/src/pjsip-ua/sip_dialog.c1802
-rw-r--r--pjsip/src/pjsip-ua/sip_ua.c473
-rw-r--r--pjsip/src/pjsip/sip_auth_client.c36
-rw-r--r--pjsip/src/pjsip/sip_dialog.c1138
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c99
-rw-r--r--pjsip/src/pjsip/sip_errno.c6
-rw-r--r--pjsip/src/pjsip/sip_msg.c376
-rw-r--r--pjsip/src/pjsip/sip_parser.c16
-rw-r--r--pjsip/src/pjsip/sip_tel_uri.c12
-rw-r--r--pjsip/src/pjsip/sip_transaction.c38
-rw-r--r--pjsip/src/pjsip/sip_transport.c45
-rw-r--r--pjsip/src/pjsip/sip_ua_layer.c674
-rw-r--r--pjsip/src/pjsip/sip_uri.c38
-rw-r--r--pjsip/src/pjsip/sip_util.c10
-rw-r--r--pjsip/src/test-pjsip/dlg_core_test.c (renamed from pjsip/src/pjsip-ua/sip_ua_private.h)18
-rw-r--r--pjsip/src/test-pjsip/msg_logger.c4
-rw-r--r--pjsip/src/test-pjsip/msg_test.c45
-rw-r--r--pjsip/src/test-pjsip/test.c2
-rw-r--r--pjsip/src/test-pjsip/transport_loop_test.c2
-rw-r--r--pjsip/src/test-pjsip/transport_test.c6
-rw-r--r--pjsip/src/test-pjsip/transport_udp_test.c2
-rw-r--r--pjsip/src/test-pjsip/tsx_basic_test.c2
-rw-r--r--pjsip/src/test-pjsip/tsx_uac_test.c6
-rw-r--r--pjsip/src/test-pjsip/tsx_uas_test.c6
-rw-r--r--pjsip/src/test-pjsip/txdata_test.c2
-rw-r--r--pjsip/src/test-pjsip/uri_test.c38
44 files changed, 3508 insertions, 3329 deletions
diff --git a/pjsip/build/pjsip.dsw b/pjsip/build/pjsip.dsw
index 5e6dfe03..00310dc7 100644
--- a/pjsip/build/pjsip.dsw
+++ b/pjsip/build/pjsip.dsw
@@ -15,6 +15,18 @@ Package=<4>
###############################################################################
+Project: "pjlib++"="..\..\pjlib\build\pjlib++.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
Project: "pjlib_util"="..\..\pjlib-util\build\pjlib_util.dsp" - Package Owner=<4>
Package=<5>
@@ -39,6 +51,18 @@ Package=<4>
###############################################################################
+Project: "pjsip++"=".\pjsip++.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
Project: "pjsip_core"=.\pjsip_core.dsp - Package Owner=<4>
Package=<5>
diff --git a/pjsip/build/pjsip_core.dsp b/pjsip/build/pjsip_core.dsp
index 9a283221..30299861 100644
--- a/pjsip/build/pjsip_core.dsp
+++ b/pjsip/build/pjsip_core.dsp
@@ -85,73 +85,96 @@ LIB32=link.exe -lib
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "Base (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_client.c
+SOURCE=..\src\pjsip\sip_errno.c
# End Source File
+# End Group
+# Begin Group "Messaging and Parsing (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_msg.c
+SOURCE=..\src\pjsip\sip_msg.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_parser.c
+SOURCE=..\src\pjsip\sip_parser.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_server.c
+SOURCE=..\src\pjsip\sip_tel_uri.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_endpoint.c
+SOURCE=..\src\pjsip\sip_uri.c
# End Source File
+# End Group
+# Begin Group "Core (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_errno.c
+SOURCE=..\src\pjsip\sip_endpoint.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_msg.c
+SOURCE=..\src\pjsip\sip_util.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_parser.c
+SOURCE=..\src\pjsip\sip_util_proxy.c
# End Source File
+# End Group
+# Begin Group "Transport Layer (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
SOURCE=..\src\pjsip\sip_resolve.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_tel_uri.c
+SOURCE=..\src\pjsip\sip_transport.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_transaction.c
+SOURCE=..\src\pjsip\sip_transport_loop.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_transport.c
+SOURCE=..\src\pjsip\sip_transport_udp.c
# End Source File
+# End Group
+# Begin Group "Authentication (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_transport_loop.c
+SOURCE=..\src\pjsip\sip_auth_client.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_transport_udp.c
+SOURCE=..\src\pjsip\sip_auth_msg.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_uri.c
+SOURCE=..\src\pjsip\sip_auth_parser.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_util.c
+SOURCE=..\src\pjsip\sip_auth_server.c
# End Source File
+# End Group
+# Begin Group "Transaction Layer (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_util_proxy.c
+SOURCE=..\src\pjsip\sip_transaction.c
# End Source File
# Begin Source File
@@ -159,40 +182,72 @@ SOURCE=..\src\pjsip\sip_util_statefull.c
# PROP Exclude_From_Build 1
# End Source File
# End Group
+# Begin Group "UA Layer (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_dialog.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_ua_layer.c
+# End Source File
+# End Group
+# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Group "Base Types (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_config.h
+# End Source File
# Begin Source File
-SOURCE=..\include\pjsip_core.h
+SOURCE=..\include\pjsip\sip_errno.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\print_util.h
+SOURCE=..\include\pjsip\sip_private.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_auth.h
+SOURCE=..\include\pjsip\sip_types.h
# End Source File
+# End Group
+# Begin Group "Messaging and Parsing (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_auth_msg.h
+SOURCE=..\include\pjsip\print_util.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_auth_parser.h
+SOURCE=..\include\pjsip\sip_msg.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_config.h
+SOURCE=..\include\pjsip\sip_parser.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_endpoint.h
+SOURCE=..\include\pjsip\sip_tel_uri.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_errno.h
+SOURCE=..\include\pjsip\sip_uri.h
+# End Source File
+# End Group
+# Begin Group "Core (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_endpoint.h
# End Source File
# Begin Source File
@@ -204,51 +259,68 @@ SOURCE=..\include\pjsip\sip_module.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_msg.h
+SOURCE=..\include\pjsip\sip_util.h
# End Source File
+# End Group
+# Begin Group "Transport Layer (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_parser.h
+SOURCE=..\include\pjsip\sip_resolve.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_private.h
+SOURCE=..\include\pjsip\sip_transport.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_resolve.h
+SOURCE=..\include\pjsip\sip_transport_loop.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_tel_uri.h
+SOURCE=..\include\pjsip\sip_transport_udp.h
# End Source File
+# End Group
+# Begin Group "Authentication (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_transaction.h
+SOURCE=..\include\pjsip\sip_auth.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_transport.h
+SOURCE=..\include\pjsip\sip_auth_msg.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_transport_loop.h
+SOURCE=..\include\pjsip\sip_auth_parser.h
# End Source File
+# End Group
+# Begin Group "Transaction Layer (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_transport_udp.h
+SOURCE=..\include\pjsip\sip_transaction.h
# End Source File
+# End Group
+# Begin Group "UA Layer (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_types.h
+SOURCE=..\include\pjsip\sip_dialog.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_uri.h
+SOURCE=..\include\pjsip\sip_ua_layer.h
# End Source File
+# End Group
# Begin Source File
-SOURCE=..\include\pjsip\sip_util.h
+SOURCE=..\include\pjsip.h
# End Source File
# End Group
# Begin Group "Inline Files"
diff --git a/pjsip/build/pjsip_ua.dsp b/pjsip/build/pjsip_ua.dsp
index 4d7ae9e5..c5986076 100644
--- a/pjsip/build/pjsip_ua.dsp
+++ b/pjsip/build/pjsip_ua.dsp
@@ -87,19 +87,16 @@ LIB32=link.exe -lib
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
-SOURCE="..\src\pjsip-ua\sip_dialog.c"
-# End Source File
-# Begin Source File
-
SOURCE="..\src\pjsip-ua\sip_reg.c"
-# End Source File
-# Begin Source File
-SOURCE="..\src\pjsip-ua\sip_ua.c"
-# End Source File
-# Begin Source File
+!IF "$(CFG)" == "pjsip_ua - Win32 Release"
+
+!ELSEIF "$(CFG)" == "pjsip_ua - Win32 Debug"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
-SOURCE="..\src\pjsip-ua\sip_ua_private.h"
# End Source File
# End Group
# Begin Group "Header Files"
@@ -107,16 +104,8 @@ SOURCE="..\src\pjsip-ua\sip_ua_private.h"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
-SOURCE="..\include\pjsip-ua\sip_dialog.h"
-# End Source File
-# Begin Source File
-
SOURCE="..\include\pjsip-ua\sip_regc.h"
# End Source File
-# Begin Source File
-
-SOURCE="..\include\pjsip-ua\sip_ua.h"
-# End Source File
# End Group
# End Target
# End Project
diff --git a/pjsip/build/test_pjsip.dsp b/pjsip/build/test_pjsip.dsp
index d890d9d5..306cb30b 100644
--- a/pjsip/build/test_pjsip.dsp
+++ b/pjsip/build/test_pjsip.dsp
@@ -89,6 +89,10 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
+SOURCE="..\src\test-pjsip\dlg_core_test.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\src\test-pjsip\main.c"
# End Source File
# Begin Source File
diff --git a/pjsip/include/pjsip-ua/sip_dialog.h b/pjsip/include/pjsip-ua/sip_dialog.h
deleted file mode 100644
index d46e3873..00000000
--- a/pjsip/include/pjsip-ua/sip_dialog.h
+++ /dev/null
@@ -1,635 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __PJSIP_DIALOG_H__
-#define __PJSIP_DIALOG_H__
-
-/**
- * @file dialog.h
- * @brief SIP Dialog abstraction
- */
-
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_auth.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA_DIALOG SIP Dialog
- * @ingroup PJSUA
- * @{
- * \brief
- * This file contains SIP dialog, a higher level abstraction of SIP session.
- *
- * \par Overview
- * A SIP dialog is an abstraction of communication session between two user
- * agents that persist for some time. The dialog facilitates sequencing of
- * messages between the user agents and proper routing of requests between both
- * of them. The dialog represents a context in which to interpret SIP messages.
- * However method independent User Agent processing for requests and responses
- * outside of a dialog exists, hence a dialog is not necessary for message
- * processing.
- *
- * A dialog is identified at each User Agent with a dialog Id, which consists
- * of a Call-Id value, a local tag and a remote tag.
- *
- * A dialog contains certain pieces of data needed for further message
- * transmissions within the dialog. This data consists of:
- * - Dialog Id - used to identify the dialog.
- * - Local sequence number - used to order requests from the UA to its peer.
- * - Remote sequence number - used to order requests from its peer to the UA.
- * - Local URI - the address of the local party.
- * - Remote URI - the address of the remote party.
- * - Remote target - the address from the Contact header field of the request
- * or response or refresh request or response.
- * - "secure" boolean - determines if the dialog is secure.
- * - Route set - an ordered list of URIs. The route set is the list of servers
- * that need to be traversed to send a request to the peer.
- * - Authentication info - array of authentication credentials to be used
- * by the dialog to authenticate to proxies and servers.
- *
- * \par Manipulating Dialog
- * Application should use functions declared in this file to do something with
- * the dialog. Among other things, application can:
- * - create outgoing dialog (#pjsip_dlg_init()).
- * - sends outgoing invitation (#pjsip_dlg_invite()).
- * - sends response (provisional and final) to incoming invitation
- * (#pjsip_dlg_answer())
- * - disconnect dialog (#pjsip_dlg_disconnect()).
- * - send other request (#pjsip_dlg_create_request() and #pjsip_dlg_send_msg())
- *
- * \par Getting Dialog's Notification
- * Dialog emits notification about various things that's happening to it (e.g.
- * a message is received, dialog state has changed, etc.). Normally it is in
- * the interest of the application to capture these notifications, by
- * supplying the function to be called when the event occurs in #pjsip_dlg_callback
- * structure, and register this structure to user agent by calling
- * #pjsip_ua_set_dialog_callback().
- *
- * \par Incoming Invitation
- * Upon receiving a new incoming invitation, user agent will automatically create
- * a new dialog, and inform application via \b pjsip_dlg_callback.
- */
-
-/** Forward declaration for user agent structure. */
-typedef struct pjsip_user_agent pjsip_user_agent;
-
-/** Forward declaration for dialog structure. */
-typedef struct pjsip_dlg pjsip_dlg;
-
-/**
- * \brief Type of events that are reported by the dialog to the application callback
- * function.
- */
-typedef enum pjsip_dlg_event_e
-{
- /** Dialog state has changed. */
- PJSIP_DIALOG_EVENT_STATE_CHANGED,
-
- /** Any mid-call messages (reinvitation, message, etc.). */
- PJSIP_DIALOG_EVENT_MID_CALL_REQUEST,
-
- /** Other events (low level events). */
- PJSIP_DIALOG_EVENT_OTHER,
-
-} pjsip_dlg_event_e;
-
-
-/**
- * \brief Structure registered by applications to receive dialog notifications
- * from the User Agent.
- *
- * Applications registers this structure to get notifications from the User Agent
- * about dialog state changes and other events. Application can set any of
- * the callback function to NULL if it doesn't want to handle the notification,
- * however, setting some callbacks to NULL probably will cause some undesired
- * result (such as setting \b on_incoming to NULL will cause the creation of
- * a lot of dialogs with no owner).
- */
-struct pjsip_dlg_callback
-{
- /**
- * This is a low level, uninterpreted callback that is called by framework
- * for all kinds of events, such as transaction events, dialog events, etc.
- * @param dlg The dialog.
- * @param dlg_event The type of dialog event.
- * @param event The event descriptor.
- */
- void (*on_all_events)(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,
- pjsip_event *event );
-
- /**
- * This is a low level callback that is called by the framework when the
- * underlying transaction is about to send outgoing message. This callback
- * is provided to allow application to modify the message before it is
- * transmitted.
- * @param dlg The dialog.
- * @param tsx The transaction that transmits the message.
- * @param tdata The transmission data, which contains the message.
- * @param retransmission The number of times this message has been sent.
- * Zero indicates the message is about to be sent the first time,
- * one indicates this is the first retransmission, etc.
- */
- void (*on_before_tx)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_tx_data *tdata, pj_bool_t retransmission);
-
- /**
- * This is a low level callback that is called by the framework when the dialog
- * has sent a message. Note that a receive of retransmission will not trigger
- * this callback since retransmission is handled internally by transaction.
- * @param dlg The dialog.
- * @param tsx The transaction that transmits the message.
- * @param tdata The transmission data, which contains the message.
- */
- void (*on_tx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_tx_data *tdata);
-
- /**
- * This is a low level callback that is called by the framework when the
- * dialog has received a message. Note that a receipt of retransmission
- * will not trigger this callback since retransmission is handled internally
- * by transaction.
- * @param dlg The dialog.
- * @param tsx The transaction that receives the message.
- * @param rdata The receive data, which contains the message.
- */
- void (*on_rx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_rx_data *rdata);
-
- /**
- * This callback is called by the framework when the user agent
- * instance receives an incoming INVITE message.
- * @param dlg The new dialog that's just created to handle the incoming call.
- * @param tsx The INVITE transaction that's just created.
- * @param rdata The receive data, which contains the INVITE message.
- */
- void (*on_incoming)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_rx_data *rdata);
-
- /**
- * This callback is called by the framework when the dialog is sending
- * the first outgoing INVITE message.
- * @param dlg The dialog.
- * @param tsx The INVITE transaction.
- * @param tdata The transmit data, which contains the INVITE message.
- */
- void (*on_calling)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_tx_data *tdata);
-
- /**
- * This callback is called by the framework when the initial INVITE
- * transaction has sent/received provisional response.
- * @param dlg The dialog.
- * @param tsx The transaction.
- * @param event The event, which src_type will always be either
- * PJSIP_EVENT_RX_MSG or PJSIP_EVENT_TX_MSG. The provisional
- * response message itself will be in either \b rdata or \b tdata.
- * @see pjsip_event.
- */
- void (*on_provisional)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_event *event);
-
- /**
- * This callback is called for both UAS and UAC dialog when 200 response
- * to INVITE is sent or received.
- * @param dlg The dialog.
- * @param event The event, which src_type can only be either
- * PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
- * @see pjsip_event
- */
- void (*on_connecting)(pjsip_dlg *dlg, pjsip_event *event);
-
- /**
- * This callback is called for both UAS and UAC when an ACK request is
- * sent or received by the dialog.
- * @param dlg The dialog.
- * @param event The event, which src_type can only be either
- * PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
- * @see pjsip_event
- */
- void (*on_established)(pjsip_dlg *dlg, pjsip_event *event);
-
- /**
- * This callback is called when the dialog is disconnected, i.e. upon
- * sending/receiving non-200 response to INVITE, sending/receiving
- * CANCEL to initial INVITE, and sending/receiving BYE.
- *
- * @param dlg The dialog.
- * @param event The event.
- * @see pjsip_event
- */
- void (*on_disconnected)(pjsip_dlg *dlg, pjsip_event *event);
-
- /**
- * This callback is called when the dialog is about to be destroyed.
- * @param dlg The dialog.
- */
- void (*on_terminated)(pjsip_dlg *dlg);
-
- /**
- * This callback will be called when the dialog receives mid call events
- * such as re-invitation or incoming pager.
- *
- * @param dlg The dialog.
- * @param event The event.
- */
- void (*on_mid_call_events)(pjsip_dlg *dlg, pjsip_event *event);
-
-}; /* struct pjsip_dlg_callback */
-
-
-
-/**
- * Dialog state.
- */
-typedef enum pjsip_dlg_state_e
-{
- /**
- * State NULL is after the dialog is instantiated but before any
- * initialization is done.
- */
- PJSIP_DIALOG_STATE_NULL,
-
- /**
- * State INCOMING is after the (callee) dialog has been initialized with
- * the incoming request, but before any responses is sent by the dialog.
- */
- PJSIP_DIALOG_STATE_INCOMING,
-
- /**
- * State CALLING is after the (caller) dialog has sent outgoing invitation
- * but before any responses are received.
- */
- PJSIP_DIALOG_STATE_CALLING,
-
- /**
- * State PROCEEDING is after the dialog sent/received provisional
- * responses, but before final response is sent/received.
- */
- PJSIP_DIALOG_STATE_PROCEEDING,
-
- /**
- * State CONNECTING is after the dialog has sent/received final response
- * to the invitation, but before acknowledgement is sent.
- */
- PJSIP_DIALOG_STATE_CONNECTING,
-
- /**
- * State ESTABLISHED occurs after the invitation has been accepted and
- * acknowledged.
- */
- PJSIP_DIALOG_STATE_ESTABLISHED,
-
- /**
- * State DISCONNECTED occurs after either party successfully disconnect
- * the session.
- */
- PJSIP_DIALOG_STATE_DISCONNECTED,
-
- /**
- * State TERMINATE occurs when the dialog is ready to be destroyed.
- */
- PJSIP_DIALOG_STATE_TERMINATED,
-
-} pjsip_dlg_state_e;
-
-
-/**
- * Get the dialog string state.
- *
- * @param state Dialog state.
- * @return The string describing the state.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state);
-
-/**
- * This structure is used to describe dialog's participants, which in this
- * case is local party (i.e. us) and remote party.
- */
-typedef struct pjsip_dlg_party
-{
- pjsip_uri *target; /**< Target URL. */
- pjsip_fromto_hdr *info; /**< URL in From/To header. */
- pj_str_t tag; /**< Tag. */
- pjsip_contact_hdr *contact; /**< URL in Contact. */
- pj_sockaddr_in addr; /**< The current transport address. */
- int cseq; /**< Sequence number counter. */
-} pjsip_dlg_party;
-
-
-/**
- * This structure describes the dialog structure.
- */
-struct pjsip_dlg
-{
- PJ_DECL_LIST_MEMBER(struct pjsip_dlg)
-
- char obj_name[PJ_MAX_OBJ_NAME]; /**< Log identification. */
-
- pjsip_user_agent *ua; /**< User agent instance. */
- pj_pool_t *pool; /**< Dialog's pool. */
- pjsip_dlg_state_e state; /**< Dialog's call state. */
- pjsip_role_e role; /**< Dialog's role. */
- pj_mutex_t *mutex; /**< Dialog's mutex. */
-
- pjsip_dlg_party local; /**< Local party info. */
- pjsip_dlg_party remote; /**< Remote party info. */
-
- pjsip_cid_hdr *call_id; /**< Call-ID */
- pj_bool_t secure; /**< Use secure transport? */
-
- pjsip_route_hdr route_set; /**< Dialog's route set. */
- pjsip_transaction *invite_tsx; /**< Current INVITE transaction. */
- int pending_tsx_count; /**< Total pending tsx count. */
-
- int cred_count; /**< Number of credentials. */
- pjsip_cred_info *cred_info; /**< Array of credentials. */
-
- pjsip_auth_session auth_sess; /**< List of auth session. */
-
- pjsip_msg_body *body;
-
- void *user_data; /**< Application's data. */
-
- int (*handle_tsx_event)(struct pjsip_dlg *, /**< Internal state handler.*/
- pjsip_transaction *,
- pjsip_event *);
-};
-
-
-/**
- * Initialize dialog with local and remote info. This function is normally
- * called after application creates the dialog with #pjsip_ua_create_dialog
- * for UAC dialogs.
- *
- * This function will initialize local and remote info from the URL, generate
- * a globally unique Call-ID, initialize CSeq, and initialize other dialog's
- * internal attributes.
- *
- * @param dlg The dialog to initialize.
- * @param local_info URI/name address to be used as local info
- * (From and Contact headers).
- * @param remote_info URI/name address to be used as remote info (To header).
- * @param target URI for initial remote's target, or NULL to set the
- * initial target the same as remote_info.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
- const pj_str_t *local_info,
- const pj_str_t *remote_info,
- const pj_str_t *target);
-
-
-/**
- * Set authentication credentials to be used by this dialog.
- *
- * If authentication credentials are set for the dialog, the dialog will try to
- * perform authentication automatically using the credentials supplied, and
- * also cache the last Authorization or Proxy-Authorization headers for next
- * requests.
- *
- * If none of the credentials are suitable or accepted by remote, then
- * the dialog will just pass the authorization failure response back to
- * application.
- *
- * @param dlg The dialog.
- * @param count Number of credentials in the array.
- * @param cred Array of credentials.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,
- int count,
- const pjsip_cred_info cred[]);
-
-/**
- * Override local contact details.
- *
- * Call this function to change the contact details to be advertised in Contact
- * header. Application normally need to call this function for incoming calls
- * before answering the call with 200/OK, because for an incoming dialogs, the
- * initial local contact info are generated from the To header, which is
- * normally not the appropriate one.
- *
- * @param dlg The dialog.
- * @param contact The contact to use.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
- const pj_str_t *contact );
-
-
-/**
- * Set initial route set to be used by the dialog. This initial route set
- * governs where and how the initial INVITE request will be routed. This
- * initial route set will be overwritten with the route set found in the
- * 2xx response of INVITE.
- *
- * Application only needs to call this function if it wants to have custom
- * route for individual dialogs. If only a single route for all dialogs is
- * needed, then application can set the global route by calling function
- * #pjsip_endpt_set_proxies().
- *
- * @param dlg The dialog.
- * @param route_set The route set list.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
- const pjsip_route_hdr *route_set );
-
-
-/**
- * Variation of #pjsip_dlg_set_route_set where the headers will be used
- * as it is (i.e. without cloned).
- *
- * @param dlg The dialog.
- * @param route_set The route set list.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
- pjsip_route_hdr *route_set);
-
-/**
- * Create initial outgoing INVITE message.
- *
- * This function is just a simple wrapper to #pjsip_dlg_create_request(),
- * so it follows the same rule there. In addition, this function also adds
- * \b Allow header to the outgoing request.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- *
- * @return The dialog transmit data, or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg );
-
-
-/**
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response. Application can only call this function when there's
- * a pending invitation to be answered.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @param code The response code, which can be:
- * - 100-199 Provisional response (application can issue multiple
- * provisional responses).
- * - 200-299 To answer the invitation (normally status code 200
- * is sent).
- * - 300-699 To reject the invitation.
- * @return Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code );
-
-
-/**
- * High level function to create message to disconnect dialog. Depending
- * on dialog's state, this function will either create CANCEL, final response,
- * or BYE message. A status code must be supplied, which will be set if dialog
- * will be transmitting a final response to INVITE.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @param status_code The status code for disconnection.
- * @return Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, int status_code);
-
-/**
- * Create CANCEL message to cancel pending outgoing dialog invitation.
- * Normally application should call #pjsip_dlg_disconnect() instead, because
- * that function will create the correct message regardless of the state of
- * the dialog.
- *
- * Application can call this function at anytime after it issues outgoing
- * invitation and before receiving final response. However, there's no
- * guarantee that the invitation will be successfully cancelled, since the
- * CANCEL request and the final response can pass over in the wire. So the
- * application must prepare to have the dialog connected even after the
- * dialog is cancelled.
- *
- * The final state of the dialog will be reported in the dialog callback.
- * If the CANCEL request succeeded, then the dialog will be disconnected with
- * status code \a PJSIP_SC_REQUEST_TERMINATED.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state.
- *
- * Upon return of this function, the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @return The dialog transmit data containing the CANCEL message,
- * or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg );
-
-
-/**
- * Create BYE message. Application shouldn't normally need to use this function,
- * but rather it's preferable to use #pjsip_dlg_disconnect() instead because
- * that function will work to disconnect the session no matter what the state
- * is.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @return The BYE message or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg );
-
-/**
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request
- * by calling #pjsip_dlg_send_msg().
- *
- * This function will initialize the request message with dialog's properties
- * as follows:
- * - the request line is initialized with the method and the target is
- * initialized from current remote target.
- * - \b From, \b To, \b Contact, and \b Call-Id headers will be added.
- * - An initial \b CSeq header will be provided (although the value will be
- * verified again when the message is actually sent with #pjsip_dlg_send_msg().
- * - \b Route headers will be added from dialog's route set.
- * - Authentication headers (\b Authorization or \b Proxy-Authorization) will
- * be added from dialog's authorization cache.
- *
- * Note that upon return the reference counter of the transmit data
- * will be set to one. When the message is sent, #pjsip_dlg_send_msg() will
- * decrement the reference counter, and when the reference counter reach zero,
- * the message will be deleted.
- *
- * @param dlg The dialog.
- * @param method The request method.
- * @param cseq Specify CSeq, or -1 to let the dialog specify CSeq.
- *
- * @return Transmit data for the new request.
- *
- * @see pjsip_dlg_send_msg()
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq);
-
-
-/**
- * This function can be called by application to send outgoing message (request
- * or response) to remote party. Note that after calling this function, the
- * transmit data will be deleted regardless of the return status. To prevent
- * deletion, application must increase the reference count, but then it will
- * be responsible to delete this transmit data itself (by decreasing the
- * reference count).
- *
- * @param dlg The dialog.
- * @param tdata The transmit data, which contains the request message.
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg,
- pjsip_tx_data *tdata );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif /* __PJSIP_DIALOG_H__ */
-
diff --git a/pjsip/include/pjsip_core.h b/pjsip/include/pjsip.h
index 5947d4b1..b7f2dd95 100644
--- a/pjsip/include/pjsip_core.h
+++ b/pjsip/include/pjsip.h
@@ -16,25 +16,41 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_CORE_H__
-#define __PJSIP_CORE_H__
+#ifndef __PJSIP_H__
+#define __PJSIP_H__
+/* Base types. */
#include <pjsip/sip_types.h>
-#include <pjsip/sip_auth.h>
-#include <pjsip/sip_endpoint.h>
#include <pjsip/sip_errno.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_module.h>
+
+/* Messaging and parsing. */
+#include <pjsip/sip_uri.h>
+#include <pjsip/sip_tel_uri.h>
#include <pjsip/sip_msg.h>
#include <pjsip/sip_parser.h>
-#include <pjsip/sip_resolve.h>
-#include <pjsip/sip_tel_uri.h>
-#include <pjsip/sip_transaction.h>
+
+/* Core */
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_util.h>
+
+/* Transport layer */
#include <pjsip/sip_transport.h>
#include <pjsip/sip_transport_udp.h>
#include <pjsip/sip_transport_loop.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_util.h>
+#include <pjsip/sip_resolve.h>
+
+/* Authentication. */
+#include <pjsip/sip_auth.h>
+
+/* Transaction layer. */
+#include <pjsip/sip_transaction.h>
+
+/* UA Layer. */
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_dialog.h>
+
-#endif /* __PJSIP_CORE_H__ */
+#endif /* __PJSIP_H__ */
diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h
index e5f80655..7a8eb610 100644
--- a/pjsip/include/pjsip/sip_auth.h
+++ b/pjsip/include/pjsip/sip_auth.h
@@ -187,6 +187,18 @@ PJ_DECL(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
unsigned options);
+/**
+ * Clone client initialization session.
+ *
+ * @param pool Pool to use.
+ * @param sess Structure to put the duplicated session.
+ * @param rhs The client session to be cloned.
+ *
+ * @return PJ_SUCCESS on success;
+ */
+PJ_DECL(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
+ pjsip_auth_clt_sess *sess,
+ const pjsip_auth_clt_sess *rhs);
/**
* Set the credentials to be used during the session. This will duplicate
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 158d4a75..ec4a4aad 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -53,6 +53,10 @@
#define PJSIP_POOL_TSX_INC 256
#define PJSIP_MAX_TSX_KEY_LEN (PJSIP_MAX_URL_SIZE*2)
+/* User agent. */
+#define PJSIP_POOL_LEN_USER_AGENT 1024
+#define PJSIP_POOL_INC_USER_AGENT 1024
+
/* Message/URL related constants. */
#define PJSIP_MAX_CALL_ID_LEN PJ_GUID_STRING_LENGTH
#define PJSIP_MAX_TAG_LEN PJ_GUID_STRING_LENGTH
diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h
new file mode 100644
index 00000000..9e827c78
--- /dev/null
+++ b/pjsip/include/pjsip/sip_dialog.h
@@ -0,0 +1,324 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJSIP_SIP_DIALOG_H__
+#define __PJSIP_SIP_DIALOG_H__
+
+
+/**
+ * @file dialog.h
+ * @brief SIP Dialog abstraction
+ */
+
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_auth.h>
+#include <pjsip/sip_errno.h>
+#include <pj/sock.h>
+#include <pj/assert.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * This structure is used to describe dialog's participants, which in this
+ * case is local party (i.e. us) and remote party.
+ */
+typedef struct pjsip_dlg_party
+{
+ pjsip_fromto_hdr *info; /**< From/To header, inc tag. */
+ pj_uint32_t tag_hval; /**< Hashed value of the tag. */
+ pjsip_contact_hdr *contact; /**< Contact header. */
+ pj_int32_t first_cseq;/**< First CSeq seen. */
+ pj_int32_t cseq; /**< Next sequence number. */
+} pjsip_dlg_party;
+
+
+/**
+ * This structure describes the dialog structure.
+ */
+struct pjsip_dialog
+{
+ /** The dialog set list. */
+ PJ_DECL_LIST_MEMBER(pjsip_dialog);
+
+ /* Dialog's system properties. */
+ char obj_name[PJ_MAX_OBJ_NAME]; /**< Standard id. */
+ pj_pool_t *pool; /**< Dialog's pool. */
+ pj_mutex_t *mutex; /**< Dialog's mutex. */
+ pjsip_user_agent *ua; /**< User agent instance. */
+
+ /* The dialog set. */
+ void *dlg_set;
+
+ /* Dialog's session properties. */
+ pjsip_uri *target; /**< Current target. */
+ pjsip_dlg_party local; /**< Local party info. */
+ pjsip_dlg_party remote; /**< Remote party info. */
+ pjsip_role_e role; /**< Initial role. */
+ pj_bool_t secure; /**< Use secure transport? */
+ pjsip_cid_hdr *call_id; /**< Call-ID header. */
+ pjsip_route_hdr route_set; /**< Route set. */
+ pjsip_auth_clt_sess auth_sess; /**< Client authentication session. */
+
+ /** Session counter. */
+ int sess_count;
+
+ /** Transaction counter. */
+ int tsx_count;
+
+ /* Dialog usages. */
+ unsigned usage_cnt; /**< Number of registered usages. */
+ pjsip_module *usage[PJSIP_MAX_MODULE]; /**< Array of usages, priority sorted */
+
+ /** Module specific data. */
+ void *mod_data[PJSIP_MAX_MODULE];
+};
+
+
+/**
+ * This utility function returns PJ_TRUE if the specified method is a
+ * dialog creating request. This method property is used to determine
+ * whether Contact header should be included in outgoing request.
+ */
+PJ_DECL(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m);
+
+/**
+ * Create a new dialog and return the instance in p_dlg parameter.
+ * After creating the dialog, application can add modules as dialog usages
+ * by calling #pjsip_dlg_add_usage().
+ *
+ * If the request has To tag parameter, dialog's local tag will be initialized
+ * from this value. Otherwise a globally unique id generator will be invoked to
+ * create dialog's local tag.
+ *
+ * This function also initializes the dialog's route set based on the
+ * Record-Route headers in the request, if present.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
+ const pj_str_t *local_uri,
+ const pj_str_t *local_contact_uri,
+ const pj_str_t *remote_uri,
+ const pj_str_t *target,
+ pjsip_dialog **p_dlg);
+
+
+/**
+ * Initialize UAS dialog from the information found in the incoming request
+ * that creates a dialog (such as INVITE, REFER, or SUBSCRIBE), and set the
+ * local Contact to contact. If contact is not specified, the local contact
+ * is initialized from the URI in the To header in the request.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg);
+
+
+/**
+ * Create a new (forked) dialog on receipt on forked response in rdata.
+ * The new dialog will be created from original_dlg, except that it will have
+ * new remote tag as copied from the To header in the response. Upon return,
+ * the new_dlg will have been registered to the user agent. Applications just
+ * need to add modules as dialog's usages.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_fork(const pjsip_dialog *original_dlg,
+ const pjsip_rx_data *rdata,
+ pjsip_dialog **new_dlg );
+
+/**
+ * Set dialog's initial route set to route_set list. This can only be called
+ * for UAC dialog, before any request is sent. After dialog has been
+ * established, the route set can not be changed.
+ *
+ * For UAS dialog,the route set will be initialized in pjsip_dlg_create_uas()
+ * from the Record-Route headers in the incoming request.
+ *
+ * The route_set argument is standard list of Route headers (i.e. with
+ * sentinel).
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
+ const pjsip_route_hdr *route_set );
+
+/**
+ * Increment the number of sessions in the dialog. Note that initially
+ * (after created) the dialog has the session counter set to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg );
+
+
+/**
+ * Decrement the number of sessions in the dialog. Once the session counter
+ * reach zero and there is no pending transaction, the dialog will be
+ * destroyed. Note that this function may destroy the dialog immediately
+ * if there is no pending transaction when this function is called.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg );
+
+/**
+ * Add a module as dialog usage, and optionally set the module specific data.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
+ pjsip_module *module,
+ void *mod_data );
+
+/**
+ * Attach module specific data to the dialog. Application can also set
+ * the value directly by accessing dlg->mod_data[module_id].
+ */
+PJ_INLINE(pj_status_t) pjsip_dlg_set_mod_data( pjsip_dialog *dlg,
+ int mod_id,
+ void *data )
+{
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
+ PJ_EINVAL);
+ dlg->mod_data[mod_id] = data;
+ return PJ_SUCCESS;
+}
+
+/**
+ * Get module specific data previously attached to the dialog. Application
+ * can also get value directly by accessing dlg->mod_data[module_id].
+ */
+PJ_INLINE(void*) pjsip_dlg_get_mod_data(pjsip_dialog *dlg,
+ int mod_id)
+{
+ PJ_ASSERT_RETURN(dlg, NULL);
+ PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
+ NULL);
+ return dlg->mod_data[mod_id];
+}
+
+
+
+/**
+ * Get the dialog instance in the incoming rdata. If an incoming message
+ * matches an existing dialog, the user agent must have put the matching
+ * dialog instance in the rdata, or otherwise this function will return
+ * NULL if the message didn't match any existing dialog.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_rdata_get_dlg( pjsip_rx_data *rdata );
+
+/**
+ * Get the associated dialog in a transaction.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_tsx_get_dlg( pjsip_transaction *tsx );
+
+
+/**
+ * Create a basic/generic request with the specified method and optionally
+ * specify the cseq. Use value -1 for cseq to have the dialog automatically
+ * put next cseq number for the request. Otherwise for some requests,
+ * e.q. CANCEL and ACK, application must put the CSeq in the original
+ * INVITE request as the parameter.
+ *
+ * This function will also put Contact header where appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_request( pjsip_dialog *dlg,
+ const pjsip_method *method,
+ int cseq,
+ pjsip_tx_data **tdata);
+
+
+/**
+ * Send request message to remote peer. If the request is not an ACK request,
+ * the dialog will send the request statefully, by creating an UAC transaction
+ * and send the request with the transaction.
+ *
+ * Also when the request is not ACK or CANCEL, the dialog will increment its
+ * local cseq number and update the cseq in the request according to dialog's
+ * cseq.
+ *
+ * If p_tsx is not null, this argument will be set with the transaction
+ * instance that was used to send the request.
+ *
+ * This function will decrement the transmit data's reference counter
+ * regardless the status of the operation.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_send_request ( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ pjsip_transaction **p_tsx );
+
+
+/**
+ * Create a response message for the incoming request in rdata with status
+ * code st_code and optional status text st_text. This function is different
+ * than endpoint's API #pjsip_endpt_create_response() in that the dialog
+ * function adds Contact header and Record-Routes headers in the response
+ * where appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ pjsip_tx_data **tdata);
+
+
+/**
+ * Modify previously sent response with other status code. Contact header
+ * will be added when appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ int st_code,
+ const pj_str_t *st_text);
+
+
+/**
+ * Send response message statefully. The transaction instance MUST be the
+ * transaction that was reported on on_rx_request() callback.
+ *
+ * This function decrements the transmit data's reference counter regardless
+ * the status of the operation.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_send_response( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_tx_data *tdata);
+
+
+
+/* Receives transaction event (called by user_agent module) */
+void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_event *e );
+
+void pjsip_dlg_on_rx_request( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata );
+
+void pjsip_dlg_on_rx_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif /* __PJSIP_SIP_DIALOG_H__ */
+
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index 527cd886..ef9d44c9 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -228,6 +228,19 @@ PJ_DECL(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt,
pjsip_transaction **p_tsx);
/**
+ * Find transaction in endpoint's transaction table by the transaction's key.
+ * This function normally is only used by modules. The key for a transaction
+ * can be created by calling #pjsip_tsx_create_key.
+ *
+ * @param endpt The endpoint instance.
+ * @param key Transaction key, as created with #pjsip_tsx_create_key.
+ *
+ * @return The transaction, or NULL if it's not found.
+ */
+PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
+ const pj_str_t *key );
+
+/**
* Register the transaction to the endpoint's transaction table.
* Before the transaction is registered, it must have been initialized as
* either UAS or UAC by calling #pjsip_tsx_init_uac or #pjsip_tsx_init_uas.
@@ -316,40 +329,78 @@ pjsip_endpt_acquire_transport( pjsip_endpoint *endpt,
int addr_len,
pjsip_transport **p_transport);
-/**
- * Get additional headers to be put in outgoing request message.
- * This function is normally called by transaction layer when sending outgoing
- * requests.
- *
- * @param endpt The endpoint.
+
+/*****************************************************************************
*
- * @return List of additional headers to be put in outgoing requests.
+ * Capabilities Management
+ *
+ * Modules may implement new capabilities to the stack. These capabilities
+ * are indicated by the appropriate SIP header fields, such as Accept,
+ * Accept-Encoding, Accept-Language, Allow, Supported, etc.
+ *
+ * When a module provides new capabilities to the stack, it registers these
+ * capabilities to the endpoint by supplying new tags (strings) to the
+ * appropriate header fields. Application (or other modules) can then query
+ * these header fields to get the list of supported capabilities, and may
+ * include these headers in the outgoing message.
+ *****************************************************************************
*/
-PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt);
/**
- * Get "Allow" header from endpoint. The endpoint builds the "Allow" header
- * from the list of methods supported by modules.
+ * Get the value of the specified capability header field.
*
* @param endpt The endpoint.
+ * @param htype The header type to be retrieved, which value may be:
+ * - PJSIP_H_ACCEPT
+ * - PJSIP_H_ALLOW
+ * - PJSIP_H_SUPPORTED
+ * @param hname If htype specifies PJSIP_H_OTHER, then the header name
+ * must be supplied in this argument. Otherwise the value
+ * must be set to NULL.
*
- * @return "Allow" header, or NULL if endpoint doesn't have "Allow" header.
+ * @return The appropriate header, or NULL if the header is not
+ * available.
*/
-PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt );
+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
+ int htype,
+ const pj_str_t *hname);
/**
- * Find transaction in endpoint's transaction table by the transaction's key.
- * This function normally is only used by modules. The key for a transaction
- * can be created by calling #pjsip_tsx_create_key.
+ * Add or register new capabilities as indicated by the tags to the
+ * appropriate header fields in the endpoint.
*
- * @param endpt The endpoint instance.
- * @param key Transaction key, as created with #pjsip_tsx_create_key.
+ * @param endpt The endpoint.
+ * @param mod The module which registers the capability.
+ * @param htype The header type to be set, which value may be:
+ * - PJSIP_H_ACCEPT
+ * - PJSIP_H_ALLOW
+ * - PJSIP_H_SUPPORTED
+ * @param hname If htype specifies PJSIP_H_OTHER, then the header name
+ * must be supplied in this argument. Otherwise the value
+ * must be set to NULL.
+ * @param count The number of tags in the array.
+ * @param tags Array of tags describing the capabilities or extensions
+ * to be added to the appropriate header.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
+ pjsip_module *mod,
+ int htype,
+ const pj_str_t *hname,
+ unsigned count,
+ const pj_str_t tags[]);
+
+/**
+ * Get list of additional headers to be put in outgoing request message.
*
- * @return The transaction, or NULL if it's not found.
+ * @param e The endpoint.
+ *
+ * @return List of headers.
*/
-PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
- const pj_str_t *key );
+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *e);
+
/**
* Set list of SIP proxies to be visited for all outbound request messages.
diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h
index 9c04c755..f7dc18cc 100644
--- a/pjsip/include/pjsip/sip_errno.h
+++ b/pjsip/include/pjsip/sip_errno.h
@@ -140,6 +140,11 @@ PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
/**
* @hideinitializer
+ * General Invalid URI error.
+ */
+#define PJSIP_EINVALIDURI (PJSIP_ERRNO_START_PJSIP + 39) /* 171039 */
+/**
+ * @hideinitializer
* Unsupported URL scheme.
*/
#define PJSIP_EINVALIDSCHEME (PJSIP_ERRNO_START_PJSIP + 40) /* 171040 */
@@ -347,6 +352,17 @@ PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
#define PJSIP_EAUTHINVALIDDIGEST (PJSIP_ERRNO_START_PJSIP+110) /* 171110 */
+/************************************************************
+ * UA AND DIALOG ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Missing From/To tag.
+ */
+#define PJSIP_EMISSINGTAG (PJSIP_ERRNO_START_PJSIP+120) /* 171120 */
+
+
+
PJ_END_DECL
#endif /* __PJSIP_SIP_ERRNO_H__ */
diff --git a/pjsip/include/pjsip/sip_module.h b/pjsip/include/pjsip/sip_module.h
index 161e43d2..57d1652d 100644
--- a/pjsip/include/pjsip/sip_module.h
+++ b/pjsip/include/pjsip/sip_module.h
@@ -24,6 +24,7 @@
* @brief Module helpers
*/
#include <pjsip/sip_types.h>
+#include <pj/list.h>
PJ_BEGIN_DECL
@@ -68,16 +69,6 @@ struct pjsip_module
void *user_data;
/**
- * Number of methods supported by this module.
- */
- int method_cnt;
-
- /**
- * Array of methods supported by this module.
- */
- const pjsip_method *methods[8];
-
- /**
* Pointer to function to be called to initialize the module.
*
* @param endpt The endpoint instance.
diff --git a/pjsip/include/pjsip/sip_msg.h b/pjsip/include/pjsip/sip_msg.h
index 3be3c2f8..cebaf3f0 100644
--- a/pjsip/include/pjsip/sip_msg.h
+++ b/pjsip/include/pjsip/sip_msg.h
@@ -173,48 +173,48 @@ typedef enum pjsip_hdr_e
* DO NOT CHANGE THE VALUE/ORDER OF THE HEADER IDs!!!.
*/
PJSIP_H_ACCEPT,
- PJSIP_H_ACCEPT_ENCODING_UNIMP,
- PJSIP_H_ACCEPT_LANGUAGE_UNIMP,
- PJSIP_H_ALERT_INFO_UNIMP,
+ PJSIP_H_ACCEPT_ENCODING_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_ACCEPT_LANGUAGE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_ALERT_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_ALLOW,
- PJSIP_H_AUTHENTICATION_INFO_UNIMP,
+ PJSIP_H_AUTHENTICATION_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_AUTHORIZATION,
PJSIP_H_CALL_ID,
- PJSIP_H_CALL_INFO_UNIMP,
+ PJSIP_H_CALL_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_CONTACT,
- PJSIP_H_CONTENT_DISPOSITION_UNIMP,
- PJSIP_H_CONTENT_ENCODING_UNIMP,
- PJSIP_H_CONTENT_LANGUAGE_UNIMP,
+ PJSIP_H_CONTENT_DISPOSITION_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_CONTENT_ENCODING_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_CONTENT_LANGUAGE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_CONTENT_LENGTH,
PJSIP_H_CONTENT_TYPE,
PJSIP_H_CSEQ,
- PJSIP_H_DATE_UNIMP,
- PJSIP_H_ERROR_INFO_UNIMP,
+ PJSIP_H_DATE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_ERROR_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_EXPIRES,
PJSIP_H_FROM,
- PJSIP_H_IN_REPLY_TO_UNIMP,
+ PJSIP_H_IN_REPLY_TO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_MAX_FORWARDS,
- PJSIP_H_MIME_VERSION_UNIMP,
+ PJSIP_H_MIME_VERSION_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_MIN_EXPIRES,
- PJSIP_H_ORGANIZATION_UNIMP,
- PJSIP_H_PRIORITY_UNIMP,
+ PJSIP_H_ORGANIZATION_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_PRIORITY_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_PROXY_AUTHENTICATE,
PJSIP_H_PROXY_AUTHORIZATION,
- PJSIP_H_PROXY_REQUIRE_UNIMP,
+ PJSIP_H_PROXY_REQUIRE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_RECORD_ROUTE,
- PJSIP_H_REPLY_TO_UNIMP,
+ PJSIP_H_REPLY_TO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_REQUIRE,
PJSIP_H_RETRY_AFTER,
PJSIP_H_ROUTE,
- PJSIP_H_SERVER_UNIMP,
- PJSIP_H_SUBJECT_UNIMP,
+ PJSIP_H_SERVER_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_SUBJECT_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_SUPPORTED,
- PJSIP_H_TIMESTAMP_UNIMP,
+ PJSIP_H_TIMESTAMP_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_TO,
PJSIP_H_UNSUPPORTED,
- PJSIP_H_USER_AGENT_UNIMP,
+ PJSIP_H_USER_AGENT_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_VIA,
- PJSIP_H_WARNING_UNIMP,
+ PJSIP_H_WARNING_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_WWW_AUTHENTICATE,
PJSIP_H_OTHER,
@@ -748,6 +748,49 @@ PJ_INLINE(void) pjsip_msg_insert_first_hdr( pjsip_msg *msg, pjsip_hdr *hdr )
PJ_DECL(pj_ssize_t) pjsip_msg_print(const pjsip_msg *msg,
char *buf, pj_size_t size);
+
+/*
+ * Some usefull macros to find common headers.
+ */
+
+
+/**
+ * Find Call-ID header.
+ *
+ * @param msg The message.
+ * @return Call-ID header instance.
+ */
+#define PJSIP_MSG_CID_HDR(msg) \
+ ((pjsip_cid_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CALL_ID, NULL))
+
+/**
+ * Find CSeq header.
+ *
+ * @param msg The message.
+ * @return CSeq header instance.
+ */
+#define PJSIP_MSG_CSEQ_HDR(msg) \
+ ((pjsip_cseq_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL))
+
+/**
+ * Find From header.
+ *
+ * @param msg The message.
+ * @return From header instance.
+ */
+#define PJSIP_MSG_FROM_HDR(msg) \
+ ((pjsip_from_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL))
+
+/**
+ * Find To header.
+ *
+ * @param msg The message.
+ * @return To header instance.
+ */
+#define PJSIP_MSG_TO_HDR(msg) \
+ ((pjsip_to_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL))
+
+
/**
* @}
*/
@@ -766,8 +809,10 @@ PJ_DECL(pj_ssize_t) pjsip_msg_print(const pjsip_msg *msg,
*/
typedef struct pjsip_generic_string_hdr
{
- PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr); /**< Standard header field. */
- pj_str_t hvalue; /**< hvalue */
+ /** Standard header field. */
+ PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr);
+ /** hvalue */
+ pj_str_t hvalue;
} pjsip_generic_string_hdr;
@@ -778,25 +823,38 @@ typedef struct pjsip_generic_string_hdr
* @param pool The pool.
* @param hname The header name to be assigned to the header, or NULL to
* assign the header name with some string.
+ * @param hvalue Optional string to be assigned as the value.
*
* @return The header, or THROW exception.
*/
-PJ_DECL(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,
- const pj_str_t *hname );
+PJ_DECL(pjsip_generic_string_hdr*)
+pjsip_generic_string_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hname,
+ const pj_str_t *hvalue);
/**
- * Create a generic header along with the text content.
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
*
- * @param pool The pool.
- * @param hname The header name.
- * @param hvalue The header text content.
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string later.
+ * @param hvalue Optional string to be assigned as the value.
*
- * @return The header instance.
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
*/
PJ_DECL(pjsip_generic_string_hdr*)
-pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
- const pj_str_t *hname,
- const pj_str_t *hvalue);
+pjsip_generic_string_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hname,
+ const pj_str_t *hvalue);
+
/**
* @}
@@ -827,25 +885,36 @@ typedef struct pjsip_generic_int_hdr
* @param pool The pool.
* @param hname The header name to be assigned to the header, or NULL to
* assign the header name with some string.
+ * @param hvalue The value to be assigned to the header.
*
* @return The header, or THROW exception.
*/
-PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
- const pj_str_t *hname );
+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hname,
+ int hvalue );
+
/**
- * Create a generic header along with the value.
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
*
- * @param pool The pool.
- * @param hname The header name.
- * @param value The header value content.
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string later.
+ * @param value Value to be assigned to the header.
*
- * @return The header instance.
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
*/
-PJ_DECL(pjsip_generic_int_hdr*)
-pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
- const pj_str_t *hname,
- int value);
+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hname,
+ int value );
/**
* @}
@@ -873,11 +942,33 @@ typedef struct pjsip_generic_array_hdr
* Create generic array header.
*
* @param pool Pool to allocate memory from.
+ * @param hname Header name.
*
* @return New generic array header.
*/
-PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_create(pj_pool_t *pool,
- const pj_str_t *hnames);
+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_create(pj_pool_t *pool,
+ const pj_str_t *hname);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string later.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_init(pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hname);
+
/**
* @}
@@ -905,6 +996,22 @@ typedef pjsip_generic_array_hdr pjsip_accept_hdr;
*/
PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -929,6 +1036,24 @@ typedef pjsip_generic_array_hdr pjsip_allow_hdr;
PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_init( pj_pool_t *pool,
+ void *mem );
+
/**
* @}
*/
@@ -961,6 +1086,24 @@ PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+
+/**
* @}
*/
@@ -989,6 +1132,24 @@ typedef struct pjsip_clen_hdr
PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+
+/**
* @}
*/
@@ -1018,6 +1179,23 @@ typedef struct pjsip_cseq_hdr
PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
@@ -1054,6 +1232,23 @@ typedef struct pjsip_contact_hdr
PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
@@ -1083,6 +1278,23 @@ typedef struct pjsip_ctype_hdr
PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
@@ -1099,10 +1311,33 @@ typedef pjsip_generic_int_hdr pjsip_expires_hdr;
/**
* Create a new Expires header.
*
- * @param pool The pool.
- * @return A new Expires header.
+ * @param pool The pool.
+ * @param value The expiration value.
+ *
+ * @return A new Expires header.
*/
-PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool );
+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool,
+ int value);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The expiration value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value );
+
/**
* @}
@@ -1141,6 +1376,23 @@ typedef pjsip_fromto_hdr pjsip_to_hdr;
PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* Create a To header.
*
* @param pool The pool.
@@ -1149,12 +1401,29 @@ PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool );
PJ_DECL(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_to_hdr*) pjsip_to_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* Convert the header to a From header.
*
* @param pool The pool.
* @return "From" header.
*/
-PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );
+PJ_DECL(pjsip_from_hdr*) pjsip_fromto_hdr_set_from( pjsip_fromto_hdr *hdr );
/**
* Convert the header to a To header.
@@ -1162,7 +1431,7 @@ PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );
* @param pool The pool.
* @return "To" header.
*/
-PJ_DECL(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );
+PJ_DECL(pjsip_to_hdr*) pjsip_fromto_hdr_set_to( pjsip_fromto_hdr *hdr );
/**
* @}
@@ -1176,19 +1445,39 @@ PJ_DECL(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );
* @ingroup PJSIP_MSG
* @{
*/
-typedef pjsip_generic_int_hdr pjsip_max_forwards_hdr;
+typedef pjsip_generic_int_hdr pjsip_max_fwd_hdr;
/**
* Create new Max-Forwards header instance.
*
* @param pool The pool.
+ * @param value The Max-Forwards value.
*
* @return New Max-Forwards header instance.
*/
-PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_max_fwd_hdr*)
+pjsip_max_fwd_hdr_create(pj_pool_t *pool, int value);
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The Max-Forwards value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_max_fwd_hdr*)
+pjsip_max_fwd_hdr_init( pj_pool_t *pool, void *mem, int value );
+
+/**
* @}
*/
@@ -1203,16 +1492,37 @@ PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);
typedef pjsip_generic_int_hdr pjsip_min_expires_hdr;
/**
- * Create new Max-Forwards header instance.
+ * Create new Min-Expires header instance.
*
* @param pool The pool.
+ * @param value The Min-Expires value.
*
- * @return New Max-Forwards header instance.
+ * @return New Min-Expires header instance.
*/
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool,
+ int value);
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The Min-Expires value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value );
+
+/**
* @}
*/
@@ -1249,6 +1559,23 @@ typedef pjsip_routing_hdr pjsip_route_hdr;
*/
PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool );
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_init( pj_pool_t *pool,
+ void *mem );
+
/**
* Create new Route header from the pool.
*
@@ -1257,6 +1584,23 @@ PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool );
*/
PJ_DECL(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool );
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_route_hdr*) pjsip_route_hdr_init( pj_pool_t *pool,
+ void *mem );
+
/**
* Convert generic routing header to Record-Route header.
*
@@ -1295,6 +1639,22 @@ typedef pjsip_generic_array_hdr pjsip_require_hdr;
*/
PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -1314,10 +1674,26 @@ typedef pjsip_generic_int_hdr pjsip_retry_after_hdr;
* Create new Retry-After header instance.
*
* @param pool The pool.
+ * @param value The Retry-After value.
*
* @return New Retry-After header instance.
*/
-PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool,
+ int value);
+
+/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The Retry-After value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value );
/**
@@ -1342,6 +1718,17 @@ typedef pjsip_generic_array_hdr pjsip_supported_hdr;
*/
PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -1365,6 +1752,17 @@ typedef pjsip_generic_array_hdr pjsip_unsupported_hdr;
*/
PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -1408,6 +1806,18 @@ typedef struct pjsip_via_hdr
PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index 065b71c2..712fa8ad 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -75,6 +75,7 @@ struct pjsip_transaction
pjsip_method method; /**< The method. */
int cseq; /**< The CSeq */
pj_str_t transaction_key;/**< Hash table key. */
+ pj_uint32_t hashed_key; /**< Key's hashed value. */
pj_str_t branch; /**< The branch Id. */
/*
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index f8968f90..5dd23c1f 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -67,6 +67,12 @@ enum pjsip_transport_flags_e
((tp)->flag & PJSIP_TRANSPORT_RELIABLE)
/**
+ * Check if transport tp is secure.
+ */
+#define PJSIP_TRANSPORT_IS_SECURE(tp) \
+ ((tp)->flag & PJSIP_TRANSPORT_SECURE)
+
+/**
* Get the transport type from the transport name.
*
* @param name Transport name, such as "TCP", or "UDP".
@@ -233,7 +239,7 @@ struct pjsip_rx_data
pjsip_cseq_hdr *cseq;
/** Max forwards header. */
- pjsip_max_forwards_hdr *max_fwd;
+ pjsip_max_fwd_hdr *max_fwd;
/** The first route header. */
pjsip_route_hdr *route;
diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index 72fe3af5..fc79f95a 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -102,6 +102,11 @@ typedef struct pjsip_hdr pjsip_hdr;
typedef struct pjsip_uri pjsip_uri;
/**
+ * Forward declaration for SIP method (sip_msg.h)
+ */
+typedef struct pjsip_method pjsip_method;
+
+/**
* Opaque data type for the resolver engine (sip_resolve.h).
*/
typedef struct pjsip_resolver_t pjsip_resolver_t;
@@ -117,6 +122,18 @@ typedef struct pjsip_cred_info pjsip_cred_info;
*/
typedef struct pjsip_module pjsip_module;
+
+/**
+ * Forward declaration for user agent type (sip_ua_layer.h).
+ */
+typedef pjsip_module pjsip_user_agent;
+
+/**
+ * Forward declaration for dialog (sip_dialog.h).
+ */
+typedef struct pjsip_dialog pjsip_dialog;
+
+
/**
* Transaction role.
*/
diff --git a/pjsip/include/pjsip-ua/sip_ua.h b/pjsip/include/pjsip/sip_ua_layer.h
index a1d7c423..e12a55a8 100644
--- a/pjsip/include/pjsip-ua/sip_ua.h
+++ b/pjsip/include/pjsip/sip_ua_layer.h
@@ -16,13 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_SIP_UA_H__
-#define __PJSIP_SIP_UA_H__
+#ifndef __PJSIP_SIP_UA_LAYER_H__
+#define __PJSIP_SIP_UA_LAYER_H__
/**
- * @file sip_ua.h
- * @brief SIP User Agent Module
+ * @file sip_ua_layer.h
+ * @brief SIP User Agent Layer Module
*/
+#include <pjsip/sip_types.h>
PJ_BEGIN_DECL
@@ -32,26 +33,30 @@ PJ_BEGIN_DECL
*/
/**
- * @defgroup PJSUA_UA SIP User Agent
+ * @defgroup PJSUA_UA SIP User Agent Module
* @ingroup PJSUA
* @{
* \brief
* User Agent manages the interactions between application and SIP dialogs.
*/
-/** User agent type. */
-typedef pjsip_module pjsip_user_agent;
-
+/** User agent initialization parameter. */
+typedef struct pjsip_ua_init_param
+{
+ pjsip_dialog* (*on_dlg_forked)(pjsip_dialog *first_set, pjsip_rx_data *res);
+} pjsip_ua_init_param;
/**
* Initialize user agent layer and register it to the specified endpoint.
*
* @param endpt The endpoint where the user agent will be
* registered.
+ * @param prm UA initialization parameter.
*
* @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t) pjsip_ua_init(pjsip_endpoint *endpt);
+PJ_DECL(pj_status_t) pjsip_ua_init(pjsip_endpoint *endpt,
+ const pjsip_ua_init_param *prm);
/**
* Get the instance of the user agent.
@@ -67,6 +72,26 @@ PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void);
*/
PJ_DECL(pj_status_t) pjsip_ua_destroy(void);
+/**
+ * Get the endpoint instance of a user agent module.
+ *
+ * @param ua The user agent instance.
+ *
+ * @return The endpoint instance where the user agent is
+ * registered.
+ */
+PJ_DECL(pjsip_endpoint*) pjsip_ua_get_endpt(pjsip_user_agent *ua);
+
+
+/*
+ * Internal.
+ */
+
+PJ_DECL(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
+ pjsip_dialog *dlg );
+PJ_DECL(pj_status_t) pjsip_ua_unregister_dlg(pjsip_user_agent *ua,
+ pjsip_dialog *dlg );
+
/**
* @}
@@ -75,5 +100,5 @@ PJ_DECL(pj_status_t) pjsip_ua_destroy(void);
PJ_END_DECL
-#endif /* __PJSIP_UA_H__ */
+#endif /* __PJSIP_SIP_UA_LAYER_H__ */
diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h
index 3ee19354..6973c524 100644
--- a/pjsip/include/pjsip/sip_uri.h
+++ b/pjsip/include/pjsip/sip_uri.h
@@ -161,9 +161,9 @@ typedef struct pjsip_uri_vptr
* @param size the size of the buffer.
* @return the length printed.
*/
- int (*p_print)(pjsip_uri_context_e context,
- const void *uri,
- char *buf, pj_size_t size);
+ pj_ssize_t (*p_print)(pjsip_uri_context_e context,
+ const void *uri,
+ char *buf, pj_size_t size);
/**
* Compare two URIs according to the context.
@@ -332,20 +332,20 @@ PJ_INLINE(void*) pjsip_uri_clone( pj_pool_t *pool, const void *uri )
* @param secure Tlag to indicate whether secure transport should be used.
* @return SIP URL.
*/
-PJ_DECL(pjsip_sip_uri*) pjsip_url_create( pj_pool_t *pool, int secure );
+PJ_DECL(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, int secure );
/**
* Create new SIPS URL and initialize all fields with zero or NULL.
* @param pool The pool.
* @return SIPS URL.
*/
-PJ_DECL(pjsip_sip_uri*) pjsips_url_create( pj_pool_t *pool );
+PJ_DECL(pjsip_sip_uri*) pjsip_sips_uri_create( pj_pool_t *pool );
/**
* Initialize SIP URL (all fields are set to NULL or zero).
* @param url The URL.
*/
-PJ_DECL(void) pjsip_url_init(pjsip_sip_uri *url, int secure);
+PJ_DECL(void) pjsip_sip_uri_init(pjsip_sip_uri *url, int secure);
/**
* Perform full assignment to the SIP URL.
@@ -353,8 +353,8 @@ PJ_DECL(void) pjsip_url_init(pjsip_sip_uri *url, int secure);
* @param url Destination URL.
* @param rhs The source URL.
*/
-PJ_DECL(void) pjsip_url_assign(pj_pool_t *pool, pjsip_sip_uri *url,
- const pjsip_sip_uri *rhs);
+PJ_DECL(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
+ const pjsip_sip_uri *rhs);
/**
* Create new instance of name address and initialize all fields with zero or
diff --git a/pjsip/src/pjsip-ua/sip_dialog.c b/pjsip/src/pjsip-ua/sip_dialog.c
deleted file mode 100644
index 722c06d8..00000000
--- a/pjsip/src/pjsip-ua/sip_dialog.c
+++ /dev/null
@@ -1,1802 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_util.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_parser.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/guid.h>
-#include <pj/except.h>
-#include <pj/pool.h>
-
-/* TLS to keep dialog lock record (initialized by UA) */
-int pjsip_dlg_lock_tls_id;
-
-struct dialog_lock_data
-{
- struct dialog_lock_data *prev;
- pjsip_dlg *dlg;
- int is_alive;
-};
-
-/*
- * Static function prototypes.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
- pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq );
-static int dlg_on_all_state_pre( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_all_state_post( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_null( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_incoming( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_calling( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_proceeding( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_proceeding_caller( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_proceeding_callee( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_connecting( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_established( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_disconnected( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_terminated( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-
-/*
- * Dialog state handlers.
- */
-static int (*dlg_state_handlers[])(struct pjsip_dlg *, pjsip_transaction *,
- pjsip_event *) =
-{
- &dlg_on_state_null,
- &dlg_on_state_incoming,
- &dlg_on_state_calling,
- &dlg_on_state_proceeding,
- &dlg_on_state_connecting,
- &dlg_on_state_established,
- &dlg_on_state_disconnected,
- &dlg_on_state_terminated,
-};
-
-/*
- * Dialog state names.
- */
-static const char* dlg_state_names[] =
-{
- "STATE_NULL",
- "STATE_INCOMING",
- "STATE_CALLING",
- "STATE_PROCEEDING",
- "STATE_CONNECTING",
- "STATE_ESTABLISHED",
- "STATE_DISCONNECTED",
- "STATE_TERMINATED",
-};
-
-
-/*
- * Get the dialog string state, normally for logging purpose.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state)
-{
- return dlg_state_names[state];
-}
-
-/* Lock dialog mutex. */
-static void lock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
- struct dialog_lock_data *prev;
-
- pj_mutex_lock(dlg->mutex);
- prev = pj_thread_local_get(pjsip_dlg_lock_tls_id);
- lck->prev = prev;
- lck->dlg = dlg;
- lck->is_alive = 1;
- pj_thread_local_set(pjsip_dlg_lock_tls_id, lck);
-}
-
-/* Carefully unlock dialog mutex, protect against situation when the dialog
- * has already been destroyed.
- */
-static pj_status_t unlock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
- pj_assert(pj_thread_local_get(pjsip_dlg_lock_tls_id) == lck);
- pj_assert(dlg == lck->dlg);
-
- pj_thread_local_set(pjsip_dlg_lock_tls_id, lck->prev);
- if (lck->is_alive)
- pj_mutex_unlock(dlg->mutex);
-
- return lck->is_alive ? 0 : -1;
-}
-
-/*
- * This is called by dialog's FSM to change dialog's state.
- */
-static void dlg_set_state( pjsip_dlg *dlg, pjsip_dlg_state_e state,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(event);
-
- PJ_LOG(4, (dlg->obj_name, "State %s-->%s (ev=%s, src=%s, data=%p)",
- pjsip_dlg_state_str(dlg->state), pjsip_dlg_state_str(state),
- event ? pjsip_event_str(event->type) : "",
- event ? pjsip_event_str(event->src_type) : "",
- event ? event->src.data : NULL));
-
- dlg->state = state;
- dlg->handle_tsx_event = dlg_state_handlers[state];
-}
-
-/*
- * Invoke dialog's callback.
- * This function is called by dialog's FSM, and interpret the event and call
- * the corresponding callback registered by application.
- */
-static void dlg_call_dlg_callback( pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,
- pjsip_event *event )
-{
- pjsip_dlg_callback *cb = dlg->ua->dlg_cb;
- if (!cb) {
- PJ_LOG(4,(dlg->obj_name, "Can not call callback (none registered)."));
- return;
- }
-
- /* Low level event: call the all-events callback. */
- if (cb->on_all_events) {
- (*cb->on_all_events)(dlg, dlg_event, event);
- }
-
- /* Low level event: call the tx/rx callback if this is a tx/rx event. */
- if (event->type == PJSIP_EVENT_BEFORE_TX && cb->on_before_tx)
- {
- (*cb->on_before_tx)(dlg, event->obj.tsx, event->src.tdata, event->data.long_data);
- }
- else if (event->type == PJSIP_EVENT_TX_MSG &&
- event->src_type == PJSIP_EVENT_TX_MSG && cb->on_tx_msg)
- {
- (*cb->on_tx_msg)(dlg, event->obj.tsx, event->src.tdata);
- }
- else if (event->type == PJSIP_EVENT_RX_MSG &&
- event->src_type == PJSIP_EVENT_RX_MSG && cb->on_rx_msg) {
- (*cb->on_rx_msg)(dlg, event->obj.tsx, event->src.rdata);
- }
-
- /* Now trigger high level events.
- * High level event should only occurs when dialog's state has changed,
- * except for on_provisional, which may be called multiple times whenever
- * response message is sent
- */
- if (dlg->state == PJSIP_DIALOG_STATE_PROCEEDING &&
- (event->type== PJSIP_EVENT_TSX_STATE_CHANGED) &&
- event->obj.tsx == dlg->invite_tsx)
- {
- /* Sent/received provisional responses. */
- if (cb->on_provisional)
- (*cb->on_provisional)(dlg, event->obj.tsx, event);
- }
-
- if (dlg_event == PJSIP_DIALOG_EVENT_MID_CALL_REQUEST) {
- if (cb->on_mid_call_events)
- (*cb->on_mid_call_events)(dlg, event);
- return;
- }
-
- if (dlg_event != PJSIP_DIALOG_EVENT_STATE_CHANGED)
- return;
-
- if (dlg->state == PJSIP_DIALOG_STATE_INCOMING) {
-
- /* New incoming dialog. */
- pj_assert (event->src_type == PJSIP_EVENT_RX_MSG);
- (*cb->on_incoming)(dlg, event->obj.tsx, event->src.rdata);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_CALLING) {
-
- /* Dialog has just sent the first INVITE. */
- if (cb->on_calling) {
- (*cb->on_calling)(dlg, event->obj.tsx, event->src.tdata);
- }
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_DISCONNECTED) {
-
- if (cb->on_disconnected)
- (*cb->on_disconnected)(dlg, event);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_TERMINATED) {
-
- if (cb->on_terminated)
- (*cb->on_terminated)(dlg);
-
- pjsip_ua_destroy_dialog(dlg);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_CONNECTING) {
-
- if (cb->on_connecting)
- (*cb->on_connecting)(dlg, event);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
-
- if (cb->on_established)
- (*cb->on_established)(dlg, event);
- }
-}
-
-/*
- * This callback receives event from the transaction layer (via User Agent),
- * or from dialog timer (for 200/INVITE or ACK retransmission).
- */
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- int status = 0;
- struct dialog_lock_data lck;
-
- PJ_LOG(4, (dlg->obj_name, "state=%s (evt=%s, src=%s)",
- pjsip_dlg_state_str(dlg->state),
- pjsip_event_str(event->type),
- pjsip_event_str(event->src_type)));
-
-
- lock_dialog(dlg, &lck);
-
- status = dlg_on_all_state_pre( dlg, tsx, event);
-
- if (status==0) {
- status = (*dlg->handle_tsx_event)(dlg, tsx, event);
- }
- if (status==0) {
- status = dlg_on_all_state_post( dlg, tsx, event);
- }
-
- unlock_dialog(dlg, &lck);
-}
-
-/*
- * This function contains common processing in all states, and it is called
- * before the FSM is invoked.
- */
-static int dlg_on_all_state_pre( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(event)
-
- if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED)
- return 0;
-
- if (tsx && (tsx->state==PJSIP_TSX_STATE_CALLING ||
- tsx->state==PJSIP_TSX_STATE_TRYING))
- {
- ++dlg->pending_tsx_count;
-
- } else if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED)
- {
- --dlg->pending_tsx_count;
- if (tsx == dlg->invite_tsx)
- dlg->invite_tsx = NULL;
- }
-
- if (tsx->method.id == PJSIP_INVITE_METHOD) {
- tsx->handle_ack = 1;
- }
- return 0;
-}
-
-
-/*
- * This function contains common processing in all states, and it is called
- * after the FSM is invoked.
- */
-static int dlg_on_all_state_post( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(event)
-
- if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) {
- if (dlg->pending_tsx_count == 0 &&
- dlg->state != PJSIP_DIALOG_STATE_CONNECTING &&
- dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED &&
- dlg->state != PJSIP_DIALOG_STATE_TERMINATED)
- {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/*
- * Internal function to initialize dialog, contains common initialization
- * for both UAS and UAC dialog.
- */
-static pj_status_t dlg_init( pjsip_dlg *dlg )
-{
- /* Init mutex. */
- dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
- if (!dlg->mutex) {
- PJ_PERROR((dlg->obj_name, "pj_mutex_create()"));
- return -1;
- }
-
- /* Init route-set (Initially empty) */
- pj_list_init(&dlg->route_set);
-
- /* Init auth credential list. */
- pj_list_init(&dlg->auth_sess);
-
- return PJ_SUCCESS;
-}
-
-/*
- * This one is called just before dialog is destroyed.
- * It is called while mutex is held.
- */
-PJ_DEF(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg )
-{
- struct dialog_lock_data *lck;
-
- //PJ_TODO(CHECK_THIS);
- pj_assert(dlg->pending_tsx_count == 0);
-
- /* Mark dialog as dead. */
- lck = pj_thread_local_get(pjsip_dlg_lock_tls_id);
- while (lck) {
- if (lck->dlg == dlg)
- lck->is_alive = 0;
- lck = lck->prev;
- }
-}
-
-/*
- * Initialize dialog from the received request.
- * This is an internal function which is called by the User Agent (sip_ua.c),
- * and it will initialize most of dialog's properties with values from the
- * received message.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg, pjsip_rx_data *rdata )
-{
- pjsip_msg *msg = rdata->msg;
- pjsip_to_hdr *to;
- pjsip_contact_hdr *contact;
- pjsip_name_addr *name_addr;
- pjsip_sip_uri *url;
- unsigned flag;
- pjsip_event event;
-
- pj_assert(dlg && rdata);
-
- PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p)", rdata));
-
- /* Must be an INVITE request. */
- pj_assert(msg->type == PJSIP_REQUEST_MSG &&
- msg->line.req.method.id == PJSIP_INVITE_METHOD);
-
- /* Init general dialog data. */
- if (dlg_init(dlg) != PJ_SUCCESS) {
- return -1;
- }
-
- /* Get the To header. */
- to = rdata->to;
-
- /* Copy URI in the To header as our local URI. */
- dlg->local.info = pjsip_hdr_clone( dlg->pool, to);
-
- /* Set tag in the local info. */
- dlg->local.info->tag = dlg->local.tag;
-
- /* Create local Contact to be advertised in the response.
- * At the moment, just copy URI from the local URI as our contact.
- */
- dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
- dlg->local.contact->star = 0;
- name_addr = (pjsip_name_addr *)dlg->local.info->uri;
- dlg->local.contact->uri = (pjsip_uri*) name_addr;
- url = (pjsip_sip_uri*) name_addr->uri;
- //url->port = rdata->via->sent_by.port;
- //url->port = pj_sockaddr_get_port( pjsip_transport_get_local_addr(rdata->transport) );
-
- /* Save remote URI. */
- dlg->remote.info = pjsip_hdr_clone( dlg->pool, rdata->from );
- pjsip_fromto_set_to( dlg->remote.info );
- pj_strdup( dlg->pool, &dlg->remote.tag, &rdata->from->tag );
-
- /* Save remote Contact. */
- contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
- if (contact) {
- dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
- } else {
- PJ_LOG(3,(dlg->obj_name, "No Contact header in INVITE from %s",
- pj_sockaddr_get_str_addr(&rdata->addr)));
- dlg->remote.contact = pjsip_contact_hdr_create( dlg->pool );
- dlg->remote.contact->uri = dlg->remote.info->uri;
- }
-
- /* Save Call-ID. */
- dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
- pj_strdup( dlg->pool, &dlg->call_id->id, &rdata->call_id );
-
- /* Initialize local CSeq and save remote CSeq.*/
- dlg->local.cseq = rdata->timestamp.sec & 0xFFFF;
- dlg->remote.cseq = rdata->cseq->cseq;
-
- /* Secure? */
- flag = pjsip_transport_get_flag(rdata->transport);
- dlg->secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
-
- /* Initial state is NULL. */
- event.type = event.src_type = PJSIP_EVENT_RX_MSG;
- event.src.rdata = rdata;
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
- PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p) complete", rdata));
- return PJ_SUCCESS;
-}
-
-/*
- * Set the contact details.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
- const pj_str_t *contact )
-{
- pjsip_uri *local_uri;
- pj_str_t tmp;
-
- pj_strdup_with_null(dlg->pool, &tmp, contact);
- local_uri = pjsip_parse_uri( dlg->pool, tmp.ptr, tmp.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (local_uri == NULL) {
- PJ_LOG(2, (dlg->obj_name, "set_contact: invalid URI"));
- return -1;
- }
-
- dlg->local.contact->star = 0;
- dlg->local.contact->uri = local_uri;
- return 0;
-}
-
-/*
- * Set route set.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
- const pjsip_route_hdr *route_set )
-{
- pjsip_route_hdr *hdr;
-
- pj_list_init(&dlg->route_set);
- hdr = route_set->next;
- while (hdr != route_set) {
- pjsip_route_hdr *cloned = pjsip_hdr_clone(dlg->pool, hdr);
- pj_list_insert_before( &dlg->route_set, cloned);
- hdr = hdr->next;
- }
- return 0;
-}
-
-/*
- * Set route set without cloning the header.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
- pjsip_route_hdr *route_set)
-{
- pjsip_route_hdr *hdr;
-
- pj_list_init(&dlg->route_set);
- hdr = route_set->next;
- while (hdr != route_set) {
- pj_list_insert_before( &dlg->route_set, hdr);
- hdr = hdr->next;
- }
- return 0;
-}
-
-/*
- * Application calls this function when it wants to initiate an outgoing
- * dialog (incoming dialogs are created automatically by UA when it receives
- * INVITE, by calling pjsip_dlg_init_from_rdata()).
- * This function should initialize most of the dialog's properties.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
- const pj_str_t *c_local_info,
- const pj_str_t *c_remote_info,
- const pj_str_t *c_target)
-{
- pj_time_val tv;
- pjsip_event event;
- pj_str_t buf;
-
- if (!dlg || !c_local_info || !c_remote_info) {
- pj_assert(dlg && c_local_info && c_remote_info);
- return -1;
- }
-
- PJ_LOG(5, (dlg->obj_name, "initializing"));
-
- /* Init general dialog */
- if (dlg_init(dlg) != PJ_SUCCESS) {
- return -1;
- }
-
- /* Duplicate local info. */
- pj_strdup_with_null( dlg->pool, &buf, c_local_info);
-
- /* Build local URI. */
- dlg->local.target = pjsip_parse_uri(dlg->pool, buf.ptr, buf.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (dlg->local.target == NULL) {
- PJ_LOG(2, (dlg->obj_name,
- "pjsip_dlg_init: invalid local URI %s", buf.ptr));
- return -1;
- }
-
- /* Set local URI. */
- dlg->local.info = pjsip_from_hdr_create(dlg->pool);
- dlg->local.info->uri = dlg->local.target;
- dlg->local.info->tag = dlg->local.tag;
-
- /* Create local Contact to be advertised in the response. */
- dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
- dlg->local.contact->star = 0;
- dlg->local.contact->uri = dlg->local.target;
-
- /* Set remote URI. */
- dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
-
- /* Duplicate to buffer. */
- pj_strdup_with_null( dlg->pool, &buf, c_remote_info);
-
- /* Build remote info. */
- dlg->remote.info->uri = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (dlg->remote.info->uri == NULL) {
- PJ_LOG(2, (dlg->obj_name,
- "pjsip_dlg_init: invalid remote URI %s", buf.ptr));
- return -1;
- }
-
- /* Set remote Contact initially equal to the remote URI. */
- dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
- dlg->remote.contact->star = 0;
- dlg->remote.contact->uri = dlg->remote.info->uri;
-
- /* Set initial remote target. */
- if (c_target != NULL) {
- pj_strdup_with_null( dlg->pool, &buf, c_target);
- dlg->remote.target = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen, 0);
- if (dlg->remote.target == NULL) {
- PJ_LOG(2, (dlg->obj_name,
- "pjsip_dlg_init: invalid remote target %s", buf.ptr));
- return -1;
- }
- } else {
- dlg->remote.target = dlg->remote.info->uri;
- }
-
- /* Create globally unique Call-ID */
- dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
- pj_create_unique_string( dlg->pool, &dlg->call_id->id );
-
- /* Local and remote CSeq */
- pj_gettimeofday(&tv);
- dlg->local.cseq = tv.sec & 0xFFFF;
- dlg->remote.cseq = 0;
-
- /* Initial state is NULL. */
- event.type = event.src_type = PJSIP_EVENT_TX_MSG;
- event.src.data = NULL;
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
- /* Done. */
- PJ_LOG(4, (dlg->obj_name, "%s dialog initialized, From: %.*s, To: %.*s",
- pjsip_role_name(dlg->role),
- c_local_info->slen, c_local_info->ptr,
- c_remote_info->slen, c_remote_info->ptr));
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set credentials.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,
- int count,
- const pjsip_cred_info *cred)
-{
- if (count > 0) {
- dlg->cred_info = pj_pool_alloc(dlg->pool, count * sizeof(pjsip_cred_info));
- pj_memcpy(dlg->cred_info, cred, count * sizeof(pjsip_cred_info));
- }
- dlg->cred_count = count;
- return 0;
-}
-
-/*
- * Create a new request within dialog (i.e. after the dialog session has been
- * established). The construction of such requests follows the rule in
- * RFC3261 section 12.2.1.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
- pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq )
-{
- pjsip_tx_data *tdata;
- pjsip_contact_hdr *contact;
- pjsip_route_hdr *route, *end_list;
-
- /* Contact Header field.
- * Contact can only be present in requests that establish dialog (in the
- * core SIP spec, only INVITE).
- */
- if (method->id == PJSIP_INVITE_METHOD)
- contact = dlg->local.contact;
- else
- contact = NULL;
-
- tdata = pjsip_endpt_create_request_from_hdr( dlg->ua->endpt,
- method,
- dlg->remote.target,
- dlg->local.info,
- dlg->remote.info,
- contact,
- dlg->call_id,
- cseq,
- NULL);
- if (!tdata) {
- PJ_THROW(1);
- return;
- }
-
- /* Just copy dialog route-set to Route header.
- * The transaction will do the processing as specified in Section 12.2.1
- * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
- */
- route = dlg->route_set.next;
- end_list = &dlg->route_set;
- for (; route != end_list; route = route->next ) {
- pjsip_route_hdr *r;
- r = pjsip_hdr_shallow_clone( tdata->pool, route );
- pjsip_routing_hdr_set_route(r);
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
- }
-
- /* Copy authorization headers. */
- pjsip_auth_init_req( dlg->pool, tdata, &dlg->auth_sess,
- dlg->cred_count, dlg->cred_info);
-
- *p_tdata = tdata;
-}
-
-
-/*
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq)
-{
- PJ_USE_EXCEPTION;
- struct dialog_lock_data lck;
- pjsip_tx_data *tdata = NULL;
-
- pj_assert(dlg != NULL && method != NULL);
- if (!dlg || !method) {
- return NULL;
- }
-
- PJ_LOG(5, (dlg->obj_name, "Creating request"));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Use outgoing CSeq and increment it by one. */
- if (cseq < 0)
- cseq = dlg->local.cseq + 1;
-
- PJ_LOG(5, (dlg->obj_name, "creating request %.*s cseq=%d",
- method->name.slen, method->name.ptr, cseq));
-
- /* Create the request. */
- PJ_TRY {
- dlg_create_request_throw(&tdata, dlg, method, cseq);
- PJ_LOG(5, (dlg->obj_name, "request data %s created", tdata->obj_name));
- }
- PJ_CATCH_ANY {
- /* Failed! Delete transmit data. */
- if (tdata) {
- pjsip_tx_data_dec_ref( tdata );
- tdata = NULL;
- }
- }
- PJ_END;
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-/*
- * Sends request.
- * Select the transport for the request message
- */
-static pj_status_t dlg_send_request( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
- pjsip_transaction *tsx;
- pj_status_t status = PJ_SUCCESS;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL && tdata != NULL);
- if (!dlg || !tdata) {
- return -1;
- }
-
- PJ_LOG(5, (dlg->obj_name, "sending request %s", tdata->obj_name));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Create a new transaction. */
- tsx = pjsip_endpt_create_tsx( dlg->ua->endpt );
- if (!tsx) {
- unlock_dialog(dlg, &lck);
- return -1;
- }
-
- PJ_LOG(4, (dlg->obj_name, "Created new UAC transaction: %s", tsx->obj_name));
-
- /* Initialize transaction */
- tsx->module_data[dlg->ua->mod_id] = dlg;
- status = pjsip_tsx_init_uac( tsx, tdata );
- if (status != PJ_SUCCESS) {
- unlock_dialog(dlg, &lck);
- pjsip_endpt_destroy_tsx( dlg->ua->endpt, tsx );
- return -1;
- }
- pjsip_endpt_register_tsx( dlg->ua->endpt, tsx );
-
- /* Start the transaction. */
- pjsip_tsx_on_tx_msg(tsx, tdata);
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return status;
-}
-
-/*
- * This function can be called by application to send ANY outgoing message
- * to remote party.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
- pj_status_t status;
- int tsx_status;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL && tdata != NULL);
- if (!dlg || !tdata) {
- return -1;
- }
-
- lock_dialog(dlg, &lck);
-
- if (tdata->msg->type == PJSIP_REQUEST_MSG) {
- int request_cseq;
- pjsip_msg *msg = tdata->msg;
- pjsip_cseq_hdr *cseq_hdr;
-
- switch (msg->line.req.method.id) {
- case PJSIP_CANCEL_METHOD:
-
- /* Check the INVITE transaction state. */
- tsx_status = dlg->invite_tsx->status_code;
- if (tsx_status >= 200) {
- /* Already terminated. Can't cancel. */
- status = -1;
- goto on_return;
- }
-
- /* If we've got provisional response, then send CANCEL and wait for
- * the response to INVITE to arrive. Otherwise just send CANCEL and
- * terminate the INVITE.
- */
- if (tsx_status < 100) {
- pjsip_tsx_terminate( dlg->invite_tsx,
- PJSIP_SC_REQUEST_TERMINATED);
- status = 0;
- goto on_return;
- }
-
- status = 0;
- request_cseq = dlg->invite_tsx->cseq;
- break;
-
- case PJSIP_ACK_METHOD:
- /* Sending ACK outside of transaction is not supported at present! */
- pj_assert(0);
- status = 0;
- request_cseq = dlg->local.cseq;
- break;
-
- case PJSIP_INVITE_METHOD:
- /* For an initial INVITE, reset dialog state to NULL so we get
- * 'normal' UAC notifications such as on_provisional(), etc.
- * Initial INVITE is the request that is sent when the dialog has
- * not been established yet. It's not necessarily the first INVITE
- * sent, as when the Authorization fails, subsequent INVITE are also
- * considered as an initial INVITE.
- */
- if (dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
- /* Set state to NULL. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, NULL);
-
- } else {
- /* This is a re-INVITE */
- }
- status = 0;
- request_cseq = dlg->local.cseq + 1;
- break;
-
- default:
- status = 0;
- request_cseq = dlg->local.cseq + 1;
- break;
- }
-
- if (status != 0)
- goto on_return;
-
- /* Update dialog's local CSeq, if necessary. */
- if (request_cseq != dlg->local.cseq)
- dlg->local.cseq = request_cseq;
-
- /* Update CSeq header in the request. */
- cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
- PJSIP_H_CSEQ, NULL);
- pj_assert(cseq_hdr != NULL);
-
- /* Update the CSeq */
- cseq_hdr->cseq = request_cseq;
-
- /* Force the whole message to be re-printed. */
- pjsip_tx_data_invalidate_msg( tdata );
-
- /* Now send the request. */
- status = dlg_send_request(dlg, tdata);
-
- } else {
- /*
- * This is only valid for sending response to INVITE!
- */
- pjsip_cseq_hdr *cseq_hdr;
-
- if (dlg->invite_tsx == NULL || dlg->invite_tsx->status_code >= 200) {
- status = -1;
- goto on_return;
- }
-
- cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
- PJSIP_H_CSEQ, NULL);
- pj_assert(cseq_hdr);
-
- if (cseq_hdr->method.id != PJSIP_INVITE_METHOD) {
- status = -1;
- goto on_return;
- }
-
- pj_assert(cseq_hdr->cseq == dlg->invite_tsx->cseq);
-
- pjsip_tsx_on_tx_msg(dlg->invite_tsx, tdata);
- status = 0;
- }
-
-on_return:
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- /* Whatever happen delete the message. */
- pjsip_tx_data_dec_ref( tdata );
-
- return status;
-}
-
-/*
- * Sends outgoing invitation.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg )
-{
- pjsip_method method;
- struct dialog_lock_data lck;
- const pjsip_allow_hdr *allow_hdr;
- pjsip_tx_data *tdata;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "request to send invitation"));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Create request. */
- pjsip_method_set( &method, PJSIP_INVITE_METHOD);
- tdata = pjsip_dlg_create_request( dlg, &method, -1 );
- if (tdata == NULL) {
- unlock_dialog(dlg, &lck);
- return NULL;
- }
-
- /* Invite SHOULD contain "Allow" header. */
- allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
- if (allow_hdr) {
- pjsip_msg_add_hdr( tdata->msg,
- pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
- }
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-/*
- * Cancel pending outgoing dialog invitation.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg )
-{
- pjsip_tx_data *tdata = NULL;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "request to cancel invitation"));
-
- lock_dialog(dlg, &lck);
-
- /* Check the INVITE transaction. */
- if (dlg->invite_tsx == NULL || dlg->role != PJSIP_ROLE_UAC) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
- "no INVITE transaction found"));
- goto on_return;
- }
-
- /* Construct the CANCEL request. */
- tdata = pjsip_endpt_create_cancel( dlg->ua->endpt,
- dlg->invite_tsx->last_tx );
- if (tdata == NULL) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
- "unable to construct request"));
- goto on_return;
- }
-
- /* Add reference counter to tdata. */
- pjsip_tx_data_add_ref(tdata);
-
-on_return:
- unlock_dialog(dlg, &lck);
- return tdata;
-}
-
-
-/*
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code )
-{
- pjsip_tx_data *tdata = NULL;
- pjsip_msg *msg;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "pjsip_dlg_answer: code=%d", code));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Must have pending INVITE. */
- if (dlg->invite_tsx == NULL) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: no INVITE transaction found"));
- goto on_return;
- }
- /* Must be UAS. */
- if (dlg->role != PJSIP_ROLE_UAS) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: not UAS"));
- goto on_return;
- }
- /* Must have not answered with final response before. */
- if (dlg->invite_tsx->status_code >= 200) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: transaction already terminated "
- "with status %d", dlg->invite_tsx->status_code));
- goto on_return;
- }
-
- /* Get transmit data and the message.
- * We will rewrite the message with a new status code.
- */
- only if tdata is not pending!!!
- tdata = dlg->invite_tsx->last_tx;
- msg = tdata->msg;
-
- /* Set status code and reason phrase. */
- if (code < 100 || code >= 700) code = 500;
- msg->line.status.code = code;
- msg->line.status.reason = *pjsip_get_status_text(code);
-
- /* For 2xx response, Contact and Record-Route must be added. */
- if (PJSIP_IS_STATUS_IN_CLASS(code,200)) {
- const pjsip_allow_hdr *allow_hdr;
-
- if (pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL) == NULL) {
- pjsip_contact_hdr *contact;
- contact = pjsip_hdr_shallow_clone( tdata->pool, dlg->local.contact);
- pjsip_msg_add_hdr( msg, (pjsip_hdr*)contact );
- }
-
- /* 2xx response MUST contain "Allow" header. */
- allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
- if (allow_hdr) {
- pjsip_msg_add_hdr( msg, pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
- }
- }
-
- /* for all but 100 responses, To-tag must be set. */
- if (code != 100) {
- pjsip_to_hdr *to;
- to = pjsip_msg_find_hdr( msg, PJSIP_H_TO, NULL);
- to->tag = dlg->local.tag;
- }
-
- /* Reset packet buffer. */
- pjsip_tx_data_invalidate_msg(tdata);
-
- /* Add reference counter */
- pjsip_tx_data_add_ref(tdata);
-
-on_return:
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-
-/*
- * Send BYE request to terminate the dialog's session.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg )
-{
- pjsip_method method;
- struct dialog_lock_data lck;
- pjsip_tx_data *tdata;
-
- if (!dlg) {
- pj_assert(dlg != NULL);
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "request to terminate session"));
-
- lock_dialog(dlg, &lck);
-
- pjsip_method_set( &method, PJSIP_BYE_METHOD);
- tdata = pjsip_dlg_create_request( dlg, &method, -1 );
-
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-/*
- * High level function to disconnect dialog's session. Depending on dialog's
- * state, this function will either send CANCEL, final response, or BYE to
- * trigger the disconnection. A status code must be supplied, which will be
- * sent if dialog will be transmitting a final response to INVITE.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg,
- int status_code )
-{
- pjsip_tx_data *tdata = NULL;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- switch (dlg->state) {
- case PJSIP_DIALOG_STATE_INCOMING:
- tdata = pjsip_dlg_answer(dlg, status_code);
- break;
-
- case PJSIP_DIALOG_STATE_CALLING:
- tdata = pjsip_dlg_cancel(dlg);
- break;
-
- case PJSIP_DIALOG_STATE_PROCEEDING:
- if (dlg->role == PJSIP_ROLE_UAC) {
- tdata = pjsip_dlg_cancel(dlg);
- } else {
- tdata = pjsip_dlg_answer(dlg, status_code);
- }
- break;
-
- case PJSIP_DIALOG_STATE_ESTABLISHED:
- tdata = pjsip_dlg_bye(dlg);
- break;
-
- default:
- PJ_LOG(4,(dlg->obj_name, "Invalid state %s in pjsip_dlg_disconnect()",
- dlg_state_names[dlg->state]));
- break;
- }
-
- return tdata;
-}
-
-/*
- * Handling of the receipt of 2xx/INVITE response.
- */
-static void dlg_on_recv_2xx_invite( pjsip_dlg *dlg,
- pjsip_event *event )
-{
- pjsip_msg *msg;
- pjsip_contact_hdr *contact;
- pjsip_hdr *hdr, *end_hdr;
- pjsip_method method;
- pjsip_tx_data *ack_tdata;
-
- /* Get the message */
- msg = event->src.rdata->msg;
-
- /* Update remote's tag information. */
- pj_strdup(dlg->pool, &dlg->remote.info->tag, &event->src.rdata->to_tag);
-
- /* Copy Contact information in the 2xx/INVITE response to dialog's.
- * remote contact
- */
- contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
- if (contact) {
- dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
- } else {
- /* duplicate contact from "From" header (?) */
- PJ_LOG(4,(dlg->obj_name, "Received 200/OK to INVITE with no Contact!"));
- dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
- dlg->remote.contact->uri = dlg->remote.info->uri;
- }
-
- /* Copy Record-Route header (in reverse order) as dialog's route-set,
- * overwriting previous route-set, if any, even if the received route-set
- * is empty.
- */
- pj_list_init(&dlg->route_set);
- end_hdr = &msg->hdr;
- for (hdr = msg->hdr.prev; hdr!=end_hdr; hdr = hdr->prev) {
- if (hdr->type == PJSIP_H_RECORD_ROUTE) {
- pjsip_route_hdr *r;
- r = pjsip_hdr_clone(dlg->pool, hdr);
- pjsip_routing_hdr_set_route(r);
- pj_list_insert_before(&dlg->route_set, r);
- }
- }
-
- /* On receipt of 200/INVITE response, send ACK.
- * This ack must be saved and retransmitted whenever we receive
- * 200/INVITE retransmission, until 64*T1 seconds elapsed.
- */
- pjsip_method_set( &method, PJSIP_ACK_METHOD);
- ack_tdata = pjsip_dlg_create_request( dlg, &method, dlg->invite_tsx->cseq);
- if (ack_tdata == NULL) {
- //PJ_TODO(HANDLE_CREATE_ACK_FAILURE)
- PJ_LOG(2, (dlg->obj_name, "Error sending ACK msg: can't create request"));
- return;
- }
-
- /* Send with the transaction. */
- pjsip_tsx_on_tx_ack( dlg->invite_tsx, ack_tdata);
-
- /* Decrement reference counter because pjsip_dlg_create_request
- * automatically increments the request.
- */
- pjsip_tx_data_dec_ref( ack_tdata );
-}
-
-/*
- * State NULL, before any events have been received.
- */
-static int dlg_on_state_null( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG)
- {
- pjsip_hdr *hdr, *hdr_list;
-
- pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
- /* Save the INVITE transaction. */
- dlg->invite_tsx = tsx;
-
- /* Change state to INCOMING */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_INCOMING, event);
-
- /* Create response buffer. */
- tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 100);
- pjsip_tx_data_add_ref(tsx->last_tx);
-
- /* Copy the Record-Route headers into dialog's route_set, maintaining
- * the order.
- */
- pj_list_init(&dlg->route_set);
- hdr_list = &event->src.rdata->msg->hdr;
- hdr = hdr_list->next;
- while (hdr != hdr_list) {
- if (hdr->type == PJSIP_H_RECORD_ROUTE) {
- pjsip_route_hdr *route;
- route = pjsip_hdr_clone(dlg->pool, hdr);
- pjsip_routing_hdr_set_route(route);
- pj_list_insert_before(&dlg->route_set, route);
- }
- hdr = hdr->next;
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_TX_MSG)
- {
- pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
- /* Save the INVITE transaction. */
- dlg->invite_tsx = tsx;
-
- /* Change state to CALLING. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_CALLING, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return 0;
-}
-
-/*
- * State INCOMING is after the (callee) dialog has been initialized with
- * the incoming request, but before any responses is sent by the dialog.
- */
-static int dlg_on_state_incoming( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- return dlg_on_state_proceeding_callee( dlg, tsx, event );
-}
-
-/*
- * State CALLING is after the (caller) dialog has sent outgoing invitation
- * but before any responses are received.
- */
-static int dlg_on_state_calling( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (tsx == dlg->invite_tsx) {
- return dlg_on_state_proceeding_caller( dlg, tsx, event );
- }
- return 0;
-}
-
-/*
- * State PROCEEDING is after provisional response is received.
- * Since the processing is similar to state CALLING, this function is also
- * called for CALLING state.
- */
-static int dlg_on_state_proceeding_caller( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- int dlg_is_terminated = 0;
-
- /* We only care about our INVITE transaction.
- * Ignore other transaction progression (such as CANCEL).
- */
- if (tsx != dlg->invite_tsx) {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- return 0;
- }
-
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED) {
- switch (tsx->state) {
- case PJSIP_TSX_STATE_PROCEEDING:
- if (dlg->state != PJSIP_DIALOG_STATE_PROCEEDING) {
- /* Change state to PROCEEDING */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- } else {
- /* Also notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
- break;
-
- case PJSIP_TSX_STATE_COMPLETED:
- /* Change dialog state. */
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- /* Update remote target, take it from the contact hdr. */
- pjsip_contact_hdr *contact;
- contact = pjsip_msg_find_hdr(event->src.rdata->msg,
- PJSIP_H_CONTACT, NULL);
- if (contact) {
- dlg->remote.target = pjsip_uri_clone(dlg->pool, contact->uri);
- } else {
- PJ_LOG(4,(dlg->obj_name,
- "Warning: found no Contact hdr in 200/OK"));
- }
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
- } else if (tsx->status_code==401 || tsx->status_code==407) {
- /* Handle Authentication challenge. */
- pjsip_tx_data *tdata;
- tdata = pjsip_auth_reinit_req( dlg->ua->endpt,
- dlg->pool, &dlg->auth_sess,
- dlg->cred_count, dlg->cred_info,
- tsx->last_tx, event->src.rdata);
- if (tdata) {
- /* Re-use original request, with a new transaction.
- * Need not to worry about CSeq, dialog will take care.
- */
- pjsip_dlg_send_msg(dlg, tdata);
- return 0;
- } else {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
- } else {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* Send ACK when dialog is connected. */
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- pj_assert(event->src_type == PJSIP_EVENT_RX_MSG);
- dlg_on_recv_2xx_invite(dlg, event);
- }
- break;
-
- case PJSIP_TSX_STATE_TERMINATED:
- /*
- * Transaction is terminated because of timeout or transport error.
- * To let the application go to normal state progression, call the
- * callback twice. First is to emulate disconnection, and then call
- * again (with state TERMINATED) to destroy the dialog.
- */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* The INVITE transaction will be destroyed, so release reference
- * to it.
- */
- dlg->invite_tsx = NULL;
-
- /* We should terminate the dialog now.
- * But it's possible that we have other pending transactions (for
- * example, outgoing CANCEL is in progress).
- * So destroy the dialog only if there's no other transaction.
- */
- if (dlg->pending_tsx_count == 0) {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- dlg_is_terminated = 1;
- }
- break;
-
- default:
- pj_assert(0);
- break;
- }
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
- return dlg_is_terminated ? -1 : 0;
-}
-
-/*
- * State PROCEEDING for UAS is after the callee send provisional response.
- * This function is also called for INCOMING state.
- */
-static int dlg_on_state_proceeding_callee( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- int dlg_is_terminated = 0;
-
- pj_assert( dlg->invite_tsx != NULL );
-
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_TX_MSG &&
- tsx == dlg->invite_tsx)
- {
- switch (tsx->state) {
- case PJSIP_TSX_STATE_PROCEEDING:
- /* Change state to PROCEEDING */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- break;
-
- case PJSIP_TSX_STATE_COMPLETED:
- case PJSIP_TSX_STATE_TERMINATED:
- /* Change dialog state. */
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
- } else {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* If transaction is terminated in non-2xx situation,
- * terminate dialog as well. This happens when something unexpected
- * occurs, such as transport error.
- */
- if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
- !PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200))
- {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- dlg_is_terminated = 1;
- }
- break;
-
- default:
- pj_assert(0);
- break;
- }
-
- } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->method.id == PJSIP_CANCEL_METHOD)
- {
- pjsip_tx_data *tdata;
-
- /* Check if sequence number matches the pending INVITE. */
- if (dlg->invite_tsx==NULL ||
- pj_strcmp(&tsx->branch, &dlg->invite_tsx->branch) != 0)
- {
- PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no matching INVITE"));
-
- /* No matching INVITE transaction found. */
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- PJSIP_SC_CALL_TSX_DOES_NOT_EXIST );
- pjsip_tsx_on_tx_msg(tsx, tdata);
- return 0;
- }
-
- /* Always respond the CANCEL with 200/CANCEL no matter what. */
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- 200 );
- pjsip_tsx_on_tx_msg( tsx, tdata );
-
- /* Respond the INVITE transaction with 487, only if transaction has
- * not completed.
- */
- if (dlg->invite_tsx->last_tx) {
- if (dlg->invite_tsx->status_code < 200) {
- tdata = dlg->invite_tsx->last_tx;
- tdata->msg->line.status.code = 487;
- tdata->msg->line.status.reason = *pjsip_get_status_text(487);
- /* Reset packet buffer. */
- pjsip_tx_data_invalidate_msg(tdata);
- pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
- } else {
- PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no effect, "
- "Transaction already terminated "
- "with status %d",
- dlg->invite_tsx->status_code));
- }
- } else {
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- 487);
- pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
- }
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return dlg_is_terminated ? -1 : 0;
-}
-
-static int dlg_on_state_proceeding( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (dlg->role == PJSIP_ROLE_UAC) {
- return dlg_on_state_proceeding_caller( dlg, tsx, event );
- } else {
- return dlg_on_state_proceeding_callee( dlg, tsx, event );
- }
-}
-
-static int dlg_on_state_connecting( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (tsx == dlg->invite_tsx) {
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- (tsx->state == PJSIP_TSX_STATE_TERMINATED ||
- tsx->state == PJSIP_TSX_STATE_COMPLETED ||
- tsx->state == PJSIP_TSX_STATE_CONFIRMED))
- {
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_ESTABLISHED, event);
- } else {
- /* Probably because we never get the ACK, or transport error
- * when sending ACK.
- */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
- } else {
- /* Handle case when transaction is started when dialog is connecting
- * (e.g. BYE requests cross wire.
- */
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->role == PJSIP_ROLE_UAS)
- {
- pjsip_tx_data *response;
-
- if (tsx->status_code >= 200)
- return 0;
-
- if (tsx->method.id == PJSIP_BYE_METHOD) {
- /* Set state to DISCONNECTED. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- response = pjsip_endpt_create_response( dlg->ua->endpt,
- event->src.rdata, 200);
- } else {
- response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR);
- }
-
- if (response)
- pjsip_tsx_on_tx_msg(tsx, response);
-
- return 0;
- }
- }
- return 0;
-}
-
-static int dlg_on_state_established( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(tsx)
-
- if (tsx && tsx->method.id == PJSIP_BYE_METHOD) {
- /* Set state to DISCONNECTED. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* Answer with 200/BYE. */
- if (event->src_type == PJSIP_EVENT_RX_MSG) {
- pjsip_tx_data *tdata;
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- 200 );
- if (tdata)
- pjsip_tsx_on_tx_msg( tsx, tdata );
- }
- } else if (tsx && event->src_type == PJSIP_EVENT_RX_MSG) {
- pjsip_method_e method = event->src.rdata->cseq->method.id;
-
- PJ_TODO(PROPERLY_HANDLE_REINVITATION)
-
- /* Reinvitation. The message may be INVITE or an ACK. */
- if (method == PJSIP_INVITE_METHOD) {
- if (dlg->invite_tsx && dlg->invite_tsx->status_code < 200) {
- /* Section 14.2: A UAS that receives a second INVITE before it
- * sends the final response to a first INVITE with a lower
- * CSeq sequence number on the same dialog MUST return a 500
- * (Server Internal Error) response to the second INVITE and
- * MUST include a Retry-After header field with a randomly
- * chosen value of between 0 and 10 seconds.
- */
- pjsip_retry_after_hdr *hdr;
- pjsip_tx_data *tdata =
- pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata, 500);
-
- if (!tdata)
- return 0;
-
- /* Add Retry-After. */
- hdr = pjsip_retry_after_hdr_create(tdata->pool);
- hdr->ivalue = 9;
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
-
- /* Send. */
- pjsip_tsx_on_tx_msg(tsx, tdata);
-
- return 0;
- }
-
- /* Keep this as our current INVITE transaction. */
- dlg->invite_tsx = tsx;
-
- /* Create response buffer. */
- tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt,
- event->src.rdata, 100);
- pjsip_tx_data_add_ref(tsx->last_tx);
-
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_MID_CALL_REQUEST, event);
-
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return 0;
-}
-
-static int dlg_on_state_disconnected( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(tsx)
-
- /* Handle case when transaction is started when dialog is disconnected
- * (e.g. BYE requests cross wire.
- */
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->role == PJSIP_ROLE_UAS)
- {
- pjsip_tx_data *response = NULL;
-
- if (tsx->status_code >= 200)
- return 0;
-
- if (tsx->method.id == PJSIP_BYE_METHOD) {
- response = pjsip_endpt_create_response( dlg->ua->endpt,
- event->src.rdata, 200);
- } else {
- response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR);
- }
- if (response)
- pjsip_tsx_on_tx_msg(tsx, response);
-
- return 0;
- }
- /* Handle case when outgoing BYE was rejected with 401/407 */
- else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->role == PJSIP_ROLE_UAC)
- {
- if (tsx->status_code==401 || tsx->status_code==407) {
- pjsip_tx_data *tdata;
- tdata = pjsip_auth_reinit_req( dlg->ua->endpt, dlg->pool,
- &dlg->auth_sess,
- dlg->cred_count, dlg->cred_info,
- tsx->last_tx, event->src.rdata);
- if (tdata) {
- pjsip_dlg_send_msg(dlg, tdata);
- }
- }
- }
-
-
- if (dlg->pending_tsx_count == 0) {
- /* Set state to TERMINATED. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- return -1;
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return 0;
-}
-
-static int dlg_on_state_terminated( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(dlg)
- PJ_UNUSED_ARG(tsx)
- PJ_UNUSED_ARG(event)
-
- return -1;
-}
-
diff --git a/pjsip/src/pjsip-ua/sip_ua.c b/pjsip/src/pjsip-ua/sip_ua.c
deleted file mode 100644
index ac0980f5..00000000
--- a/pjsip/src/pjsip-ua/sip_ua.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_util.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_transaction.h>
-#include <pj/list.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <pj/hash.h>
-#include <pj/pool.h>
-
-#define PJSIP_POOL_LEN_USER_AGENT 1024
-#define PJSIP_POOL_INC_USER_AGENT 0
-
-
-#define LOG_THIS "useragent.."
-
-/*
- * Static prototypes.
- */
-static pj_status_t ua_load(pjsip_endpoint *endpt);
-static pj_status_t ua_unload(void);
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *evt );
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua,
- pjsip_rx_data *rdata );
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
- pj_str_t *key );
-PJ_DECL(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg );
-
-/*
- * Module interface.
- */
-static struct user_agent
-{
- pjsip_module mod;
- pj_pool_t *pool;
- pjsip_endpoint *endpt;
- pj_mutex_t *mutex;
- pj_hash_table_t *dlg_table;
- pjsip_dialog dlg_list;
-
-} mod_ua =
-{
- {
- NULL, NULL, /* prev, next. */
- { "mod-ua", 6 }, /* Name. */
- -1, /* Id */
- PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority */
- NULL, /* User data. */
- 0, /* Number of methods supported. */
- { 0 }, /* Array of methods */
- &ua_load, /* load() */
- NULL, /* start() */
- NULL, /* stop() */
- &ua_unload, /* unload() */
- NULL, /* on_rx_request() */
- NULL, /* on_rx_response() */
- NULL, /* on_tx_request. */
- NULL, /* on_tx_response() */
- NULL, /* on_tsx_state() */
- }
-};
-
-/*
- * Initialize user agent instance.
- */
-static pj_status_t ua_load( pjsip_endpoint *endpt )
-{
- extern int pjsip_dlg_lock_tls_id; /* defined in sip_dialog.c */
- pj_status_t status;
-
- /* Initialize the user agent. */
- mod_ua.endpt = endpt;
- status = pjsip_endpt_create_pool( endpt, "pua%p", PJSIP_POOL_LEN_UA,
- PJSIP_POOL_INC_UA, &mod_ua.pool);
- if (status != PJ_SUCCESS)
- return status;
-
- status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex);
- if (status != PJ_SUCCESS)
- return status;
-
- mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT);
- if (ua->dlg_table == NULL)
- return PJ_ENOMEM;
-
- pj_list_init(&mod_ua.dlg_list);
-
- /* Initialize dialog lock. */
- pjsip_dlg_lock_tls_id = pj_thread_local_alloc();
- if (pjsip_dlg_lock_tls_id == -1) {
- return -1;
- }
- pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
-
- return PJ_SUCCESS;
-}
-
-/*
- * Destroy user agent.
- */
-static pj_status_t ua_unload()
-{
- pj_mutex_unlock(mod_ua.mutex);
-
- /* Release pool */
- if (mod_ua.pool) {
- pjsip_endpt_destroy_pool( mod_ua.endpt, mod_ua.pool );
- }
- return PJ_SUCCESS;
-}
-
-/*
- * Find dialog.
- * This function is called for a new transactions, which a dialog hasn't been
- * 'attached' to the transaction.
- */
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua, pjsip_rx_data *rdata )
-{
- pjsip_dlg *dlg;
- pj_str_t *tag;
-
- /* Non-CANCEL requests/response can be found by looking at the tag in the
- * hash table. CANCEL requests don't have tags, so instead we'll try to
- * find the UAS INVITE transaction in endpoint's hash table
- */
- if (rdata->cseq->method.id == PJSIP_CANCEL_METHOD) {
-
- /* Create key for the rdata, but this time, use INVITE as the
- * method.
- */
- pj_str_t key;
- pjsip_role_e role;
- pjsip_method invite_method;
- pjsip_transaction *invite_tsx;
-
- if (rdata->msg->type == PJSIP_REQUEST_MSG) {
- role = PJSIP_ROLE_UAS;
- } else {
- role = PJSIP_ROLE_UAC;
- }
- pjsip_method_set(&invite_method, PJSIP_INVITE_METHOD);
- pjsip_tsx_create_key(rdata->pool, &key, role, &invite_method, rdata);
-
- /* Lookup the INVITE transaction */
- invite_tsx = pjsip_endpt_find_tsx(ua->endpt, &key);
-
- /* We should find the dialog attached to the INVITE transaction */
- return invite_tsx ?
- (pjsip_dlg*) invite_tsx->module_data[ua->mod_id] : NULL;
-
- } else {
- if (rdata->msg->type == PJSIP_REQUEST_MSG) {
- tag = &rdata->to_tag;
- } else {
- tag = &rdata->from_tag;
- }
- /* Find the dialog in UA hash table */
- pj_mutex_lock(ua->mutex);
- dlg = pj_hash_get( ua->dlg_table, tag->ptr, tag->slen );
- pj_mutex_unlock(ua->mutex);
- }
-
- return dlg;
-}
-
-/*
- * This function receives event notification from transactions. It is called by
- * endpoint.
- */
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
- pjsip_user_agent *ua = mod->mod_data;
- pjsip_dlg *dlg = NULL;
- pjsip_transaction *tsx = event->obj.tsx;
-
- PJ_LOG(5, (LOG_THIS, "ua_tsx_handler(tsx=%s, evt=%s, src=%s, data=%p)",
- (tsx ? tsx->obj_name : "NULL"), pjsip_event_str(event->type),
- pjsip_event_str(event->src_type), event->src.data));
-
- /* Special case to handle ACK which doesn't match any INVITE transactions. */
- if (event->type == PJSIP_EVENT_RX_ACK_MSG) {
- /* Find the dialog based on the "tag". */
- dlg = find_dialog( ua, event->src.rdata );
-
- /* We should be able to find it. */
- if (!dlg) {
- PJ_LOG(4,(LOG_THIS, "Unable to find dialog for incoming ACK"));
- return;
- }
-
- /* Match CSeq with pending INVITE in dialog. */
- if (dlg->invite_tsx && dlg->invite_tsx->cseq==event->src.rdata->cseq->cseq) {
- /* A match found. */
- tsx = dlg->invite_tsx;
-
- /* Pass the event to transaction if transaction handles ACK. */
- if (tsx->handle_ack) {
- PJ_LOG(4,(LOG_THIS, "Re-routing strandled ACK to transaction"));
- pjsip_tsx_on_rx_msg(tsx, event->src.rdata);
- return;
- }
- } else {
- tsx = NULL;
- PJ_LOG(4,(LOG_THIS, "Unable to find INVITE tsx for incoming ACK"));
- return;
- }
- }
-
- /* For discard event, transaction is NULL. */
- if (tsx == NULL) {
- return;
- }
-
- /* Try to pickup the dlg from the transaction. */
- dlg = (pjsip_dlg*) tsx->module_data[ua->mod_id];
-
- if (dlg != NULL) {
-
- /* Nothing to do now. */
-
- } else if (event->src_type == PJSIP_EVENT_RX_MSG) {
-
- /* This must be a new UAS transaction. */
-
- /* Finds dlg that can handle this transaction. */
- dlg = find_dialog( ua, event->src.rdata);
-
- /* Create a new dlg if there's no existing dlg that can handle
- the request, ONLY if the incoming message is an INVITE request.
- */
- if (dlg==NULL && event->src.rdata->msg->type == PJSIP_REQUEST_MSG) {
-
- if (event->src.rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
- /* Create new dialog. */
- dlg = pjsip_ua_create_dialog( ua, PJSIP_ROLE_UAS );
-
- if (dlg == NULL ||
- pjsip_dlg_init_from_rdata( dlg, event->src.rdata) != 0)
- {
- pjsip_tx_data *tdata;
-
- /* Dialog initialization has failed. Respond request with 500 */
- if (dlg) {
- pjsip_ua_destroy_dialog(dlg);
- }
- tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR);
- if (tdata) {
- pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
- }
- return;
- }
-
- } else {
- pjsip_tx_data *tdata;
-
- /* Check the method */
- switch (tsx->method.id) {
- case PJSIP_INVITE_METHOD:
- case PJSIP_ACK_METHOD:
- case PJSIP_BYE_METHOD:
- case PJSIP_CANCEL_METHOD:
- /* Stale non-INVITE request.
- * For now, respond all stale requests with 481 (?).
- */
- tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata,
- PJSIP_SC_CALL_TSX_DOES_NOT_EXIST);
- if (tdata) {
- pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
- }
- break;
- }
-
- return;
- }
- } else {
- /* Check the method */
- switch (tsx->method.id) {
- case PJSIP_INVITE_METHOD:
- case PJSIP_ACK_METHOD:
- case PJSIP_BYE_METHOD:
- case PJSIP_CANCEL_METHOD:
- /* These methods belongs to dialog.
- * If we receive these methods while no dialog is found,
- * then it must be a stale responses.
- */
- break;
- default:
- return;
- }
-
- }
-
- if (dlg == NULL) {
- PJ_LOG(3, (LOG_THIS, "Receives spurious rdata %p from %s:%d",
- event->src.rdata,
- pj_sockaddr_get_str_addr(&event->src.rdata->addr),
- pj_sockaddr_get_port(&event->src.rdata->addr)));
- }
-
- /* Set the dlg in the transaction (dlg can be NULL). */
- tsx->module_data[ua->mod_id] = dlg;
-
- } else {
- /* This CAN happen with event->src_type == PJSIP_EVENT_TX_MSG
- * if UAS is responding to a transaction which does not exist.
- * Just ignore.
- */
- return;
- }
-
- /* Pass the event to the dlg. */
- if (dlg) {
- pjsip_dlg_on_tsx_event(dlg, tsx, event);
- }
-}
-
-/*
- * Register dialog to UA.
- */
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
- pj_str_t *key )
-{
- /* Assure that no entry with similar key exists in the hash table. */
- pj_assert( pj_hash_get( ua->dlg_table, key->ptr, key->slen) == 0);
-
- /* Insert entry to hash table. */
- pj_hash_set( dlg->pool, ua->dlg_table,
- key->ptr, key->slen, dlg);
-
- /* Insert to the list. */
- pj_list_insert_before(&ua->dlg_list, dlg);
- return PJ_SUCCESS;
-}
-
-/*
- * Create a new dialog.
- */
-PJ_DEF(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,
- pjsip_role_e role )
-{
- pj_pool_t *pool;
- pjsip_dlg *dlg;
-
- PJ_UNUSED_ARG(ua)
-
- /* Create pool for the dialog. */
- pool = pjsip_endpt_create_pool( ua->endpt, "pdlg%p",
- PJSIP_POOL_LEN_DIALOG,
- PJSIP_POOL_INC_DIALOG);
-
- /* Create the dialog. */
- dlg = pj_pool_calloc(pool, 1, sizeof(pjsip_dlg));
- dlg->pool = pool;
- dlg->ua = ua;
- dlg->role = role;
- sprintf(dlg->obj_name, "dlg%p", dlg);
-
- /* Create mutex for the dialog. */
- dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
- if (!dlg->mutex) {
- pjsip_endpt_destroy_pool(ua->endpt, pool);
- return NULL;
- }
-
- /* Create unique tag for the dialog. */
- pj_create_unique_string( pool, &dlg->local.tag );
-
- /* Register dialog. */
- pj_mutex_lock(ua->mutex);
- if (ua_register_dialog(ua, dlg, &dlg->local.tag) != PJ_SUCCESS) {
- pj_mutex_unlock(ua->mutex);
- pj_mutex_destroy(dlg->mutex);
- pjsip_endpt_destroy_pool( ua->endpt, pool );
- return NULL;
- }
- pj_mutex_unlock(ua->mutex);
-
- PJ_LOG(4, (dlg->obj_name, "new %s dialog created", pjsip_role_name(role)));
- return dlg;
-}
-
-/*
- * Destroy dialog.
- */
-PJ_DEF(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg )
-{
- PJ_LOG(5, (dlg->obj_name, "destroying.."));
-
- /* Lock dialog's mutex.
- * Check the mutex validity first since this function can be called
- * on dialog initialization failure (which might be because mutex could not
- * be allocated in the first place).
- */
- if (dlg->mutex) {
- pj_mutex_lock(dlg->mutex);
- }
-
- /* This must be called while holding dialog's mutex, if any. */
- pjsip_on_dialog_destroyed(dlg);
-
- /* Lock UA. */
- pj_mutex_lock(dlg->ua->mutex);
-
- /* Erase from hash table. */
- pj_hash_set( dlg->pool, dlg->ua->dlg_table,
- dlg->local.tag.ptr, dlg->local.tag.slen, NULL);
-
- /* Erase from the list. */
- pj_list_erase(dlg);
-
- /* Unlock UA. */
- pj_mutex_unlock(dlg->ua->mutex);
-
- /* Unlock mutex. */
- if (dlg->mutex) {
- pj_mutex_unlock(dlg->mutex);
- }
-
- /* Destroy the pool. */
- pjsip_endpt_destroy_pool( dlg->ua->endpt, dlg->pool);
-}
-
-/*
- * Dump user agent state to log file.
- */
-PJ_DEF(void) pjsip_ua_dump(pjsip_user_agent *ua)
-{
-#if PJ_LOG_MAX_LEVEL >= 3
- PJ_LOG(3,(LOG_THIS, "Dumping user agent"));
- PJ_LOG(3,(LOG_THIS, " Pool capacity=%u, used=%u",
- pj_pool_get_capacity(ua->pool),
- pj_pool_get_used_size(ua->pool)));
- PJ_LOG(3,(LOG_THIS, " Number of dialogs=%u", pj_hash_count(ua->dlg_table)));
-
- if (pj_hash_count(ua->dlg_table)) {
- pjsip_dlg *dlg;
-
- PJ_LOG(3,(LOG_THIS, " Dumping dialog list:"));
- dlg = ua->dlg_list.next;
- while (dlg != (pjsip_dlg*) &ua->dlg_list) {
- PJ_LOG(3, (LOG_THIS, " %s %s", dlg->obj_name,
- pjsip_dlg_state_str(dlg->state)));
- dlg = dlg->next;
- }
- }
-#endif
-}
-
diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
index 523b35a9..1caaa901 100644
--- a/pjsip/src/pjsip/sip_auth_client.c
+++ b/pjsip/src/pjsip/sip_auth_client.c
@@ -353,6 +353,42 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
}
+/* Clone session. */
+PJ_DEF(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
+ pjsip_auth_clt_sess *sess,
+ const pjsip_auth_clt_sess *rhs )
+{
+ unsigned i;
+
+ PJ_ASSERT_RETURN(pool && sess && rhs, PJ_EINVAL);
+
+ sess->pool = pool;
+ sess->endpt = (pjsip_endpoint*)rhs->endpt;
+ sess->cred_cnt = rhs->cred_cnt;
+ sess->cred_info = pj_pool_alloc(pool,
+ sess->cred_cnt*sizeof(pjsip_cred_info));
+ for (i=0; i<rhs->cred_cnt; ++i) {
+ pj_strdup(pool, &sess->cred_info[i].realm, &rhs->cred_info[i].realm);
+ pj_strdup(pool, &sess->cred_info[i].scheme, &rhs->cred_info[i].scheme);
+ pj_strdup(pool, &sess->cred_info[i].username,
+ &rhs->cred_info[i].username);
+ sess->cred_info[i].data_type = rhs->cred_info[i].data_type;
+ pj_strdup(pool, &sess->cred_info[i].data, &rhs->cred_info[i].data);
+ }
+
+ /* TODO note:
+ * Cloning the full authentication client is quite a big task.
+ * We do only the necessary bits here, i.e. cloning the credentials.
+ * The drawback of this basic approach is, a forked dialog will have to
+ * re-authenticate itself on the next request because it has lost the
+ * cached authentication headers.
+ */
+ PJ_TODO(FULL_CLONE_OF_AUTH_CLIENT_SESSION);
+
+ return PJ_SUCCESS;
+}
+
+
/* Set client credentials. */
PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess,
int cred_cnt,
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
new file mode 100644
index 00000000..d387b8ae
--- /dev/null
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -0,0 +1,1138 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_util.h>
+#include <pjsip/sip_transaction.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/guid.h>
+#include <pj/rand.h>
+#include <pj/array.h>
+#include <pj/except.h>
+#include <pj/hash.h>
+#include <pj/log.h>
+
+#define THIS_FILE "sip_dialog.c"
+
+
+PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m)
+{
+ pjsip_method subscribe = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 10}};
+ pjsip_method refer = { PJSIP_OTHER_METHOD, {"REFER", 5}};
+
+ return m->id == PJSIP_INVITE_METHOD ||
+ (pjsip_method_cmp(m, &subscribe)==0) ||
+ (pjsip_method_cmp(m, &refer)==0);
+}
+
+static pj_status_t create_dialog( pjsip_user_agent *ua,
+ pjsip_dialog **p_dlg)
+{
+ pjsip_endpoint *endpt;
+ pj_pool_t *pool;
+ pjsip_dialog *dlg;
+ pj_status_t status;
+
+ endpt = pjsip_ua_get_endpt(ua);
+ if (!endpt)
+ return PJ_EINVALIDOP;
+
+ pool = pjsip_endpt_create_pool(endpt, "dlg%p",
+ PJSIP_POOL_LEN_DIALOG,
+ PJSIP_POOL_INC_DIALOG);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ dlg = pj_pool_zalloc(pool, sizeof(pjsip_dialog));
+ PJ_ASSERT_RETURN(dlg != NULL, PJ_ENOMEM);
+
+ dlg->pool = pool;
+ pj_sprintf(dlg->obj_name, "dlg%p", dlg);
+ dlg->ua = ua;
+
+ status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ *p_dlg = dlg;
+ return PJ_SUCCESS;
+
+on_error:
+ if (dlg->mutex)
+ pj_mutex_destroy(dlg->mutex);
+ pjsip_endpt_release_pool(endpt, pool);
+ return status;
+}
+
+static void destroy_dialog( pjsip_dialog *dlg )
+{
+ if (dlg->mutex)
+ pj_mutex_destroy(dlg->mutex);
+ pjsip_endpt_release_pool(pjsip_ua_get_endpt(dlg->ua), dlg->pool);
+}
+
+
+/*
+ * Create an UAC dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
+ const pj_str_t *local_uri,
+ const pj_str_t *local_contact,
+ const pj_str_t *remote_uri,
+ const pj_str_t *target,
+ pjsip_dialog **p_dlg)
+{
+ pj_status_t status;
+ pj_str_t tmp;
+ pjsip_dialog *dlg;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(ua && local_uri && remote_uri && p_dlg, PJ_EINVAL);
+
+ /* Create dialog instance. */
+ status = create_dialog(ua, &dlg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Parse target. */
+ pj_strdup_with_null(dlg->pool, &tmp, target ? target : remote_uri);
+ dlg->target = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+ if (!dlg->target) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Init local info. */
+ dlg->local.info = pjsip_from_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp, local_uri);
+ dlg->local.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+ if (!dlg->local.info->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Generate local tag. */
+ pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
+
+ /* Calculate hash value of local tag. */
+ dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen);
+
+ /* Randomize local CSeq. */
+ dlg->local.first_cseq = pj_rand() % 0x7FFFFFFFL;
+ dlg->local.cseq = dlg->local.cseq;
+
+ /* Init local contact. */
+ dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp,
+ local_contact ? local_contact : local_uri);
+ dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
+ PJSIP_PARSE_URI_AS_NAMEADDR);
+ if (!dlg->local.contact->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Init remote info. */
+ dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp, remote_uri);
+ dlg->remote.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+ if (!dlg->remote.info->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Initialize remote's CSeq to -1. */
+ dlg->remote.cseq = dlg->remote.first_cseq = -1;
+
+ /* Initial role is UAC. */
+ dlg->role = PJSIP_ROLE_UAC;
+
+ /* Secure? */
+ dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
+
+ /* Generate Call-ID header. */
+ dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
+ pj_create_unique_string(dlg->pool, &dlg->call_id->id);
+
+ /* Initial route set is empty. */
+ pj_list_init(&dlg->route_set);
+
+ /* Init client authentication session. */
+ status = pjsip_auth_clt_init(&dlg->auth_sess, pjsip_ua_get_endpt(ua),
+ dlg->pool, 0);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register this dialog to user agent. */
+ status = pjsip_ua_register_dlg( ua, dlg );
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ /* Done! */
+ *p_dlg = dlg;
+
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_dialog(dlg);
+ return status;
+}
+
+
+/*
+ * Create UAS dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg)
+{
+ pj_status_t status;
+ pjsip_hdr *contact_hdr;
+ pjsip_rr_hdr *rr;
+ pjsip_dialog *dlg;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(ua && rdata && p_dlg, PJ_EINVAL);
+
+ /* rdata must have request message. */
+ PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
+ PJSIP_ENOTREQUESTMSG);
+
+ /* Request must not have To tag.
+ * This should have been checked in the user agent (or application?).
+ */
+ PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen == 0, PJ_EINVALIDOP);
+
+ /* The request must be a dialog establishing request. */
+ PJ_ASSERT_RETURN(
+ pjsip_method_creates_dialog(&rdata->msg_info.msg->line.req.method),
+ PJ_EINVALIDOP);
+
+ /* Create dialog instance. */
+ status = create_dialog(ua, &dlg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Init local info from the To header. */
+ dlg->local.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.to);
+ pjsip_fromto_hdr_set_from(dlg->local.info);
+
+ /* Generate local tag. */
+ pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
+
+ /* Calculate hash value of local tag. */
+ dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen);
+
+ /* Randomize local cseq */
+ dlg->local.first_cseq = pj_rand() % 0x7FFFFFFFL;
+ dlg->local.cseq = dlg->local.first_cseq;
+
+ /* Init local contact. */
+ /* TODO:
+ * Section 12.1.1, paragraph about using SIPS URI in Contact.
+ * If the request that initiated the dialog contained a SIPS URI
+ * in the Request-URI or in the top Record-Route header field value,
+ * if there was any, or the Contact header field if there was no
+ * Record-Route header field, the Contact header field in the response
+ * MUST be a SIPS URI.
+ */
+ if (contact) {
+ pj_str_t tmp;
+
+ dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp, contact);
+ dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
+ PJSIP_PARSE_URI_AS_NAMEADDR);
+ if (!dlg->local.contact->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ } else {
+ dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+ dlg->local.contact->uri = dlg->local.info->uri;
+ }
+
+ /* Init remote info from the From header. */
+ dlg->remote.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.from);
+ pjsip_fromto_hdr_set_to(dlg->remote.info);
+
+ /* Init remote's contact from Contact header. */
+ contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
+ NULL);
+ if (!contact_hdr) {
+ status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
+ goto on_error;
+ }
+ dlg->remote.contact = pjsip_hdr_clone(dlg->pool, contact_hdr);
+
+ /* Init remote's CSeq from CSeq header */
+ dlg->remote.cseq = dlg->remote.first_cseq = rdata->msg_info.cseq->cseq;
+
+ /* Set initial target to remote's Contact. */
+ dlg->target = dlg->remote.contact->uri;
+
+ /* Initial role is UAS */
+ dlg->role = PJSIP_ROLE_UAS;
+
+ /* Secure?
+ * RFC 3261 Section 12.1.1:
+ * If the request arrived over TLS, and the Request-URI contained a
+ * SIPS URI, the 'secure' flag is set to TRUE.
+ */
+ dlg->secure = PJSIP_TRANSPORT_IS_SECURE(rdata->tp_info.transport) &&
+ PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.msg->line.req.uri);
+
+ /* Call-ID */
+ dlg->call_id = pjsip_hdr_clone(dlg->pool, rdata->msg_info.cid);
+
+ /* Route set.
+ * RFC 3261 Section 12.1.1:
+ * The route set MUST be set to the list of URIs in the Record-Route
+ * header field from the request, taken in order and preserving all URI
+ * parameters. If no Record-Route header field is present in the request,
+ * the route set MUST be set to the empty set.
+ */
+ pj_list_init(&dlg->route_set);
+ rr = rdata->msg_info.record_route;
+ while (rr != NULL) {
+ pjsip_route_hdr *route;
+
+ /* Clone the Record-Route, change the type to Route header. */
+ route = pjsip_hdr_clone(dlg->pool, rr);
+ pjsip_routing_hdr_set_route(route);
+
+ /* Add to route set. */
+ pj_list_push_back(&dlg->route_set, route);
+
+ /* Find next Record-Route header. */
+ rr = rr->next;
+ if (rr == (pjsip_rr_hdr*)&rdata->msg_info.msg->hdr)
+ break;
+ rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, rr);
+ }
+
+ /* Init client authentication session. */
+ status = pjsip_auth_clt_init(&dlg->auth_sess, pjsip_ua_get_endpt(ua),
+ dlg->pool, 0);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Calculate hash value of remote tag. */
+ dlg->remote.tag_hval = pj_hash_calc(0, dlg->remote.info->tag.ptr,
+ dlg->remote.info->tag.slen);
+
+ /* Register this dialog to user agent. */
+ status = pjsip_ua_register_dlg( ua, dlg );
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Put this dialog in rdata's mod_data */
+ rdata->endpt_info.mod_data[ua->id] = dlg;
+
+ PJ_TODO(DIALOG_APP_TIMER);
+
+ /* Done. */
+ *p_dlg = dlg;
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_dialog(dlg);
+ return status;
+}
+
+
+/*
+ * Create forked dialog from a response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
+ const pjsip_rx_data *rdata,
+ pjsip_dialog **new_dlg )
+{
+ pjsip_dialog *dlg;
+ const pjsip_route_hdr *r;
+ pj_status_t status;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(first_dlg && rdata && new_dlg, PJ_EINVAL);
+
+ /* rdata must be response message. */
+ PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG,
+ PJSIP_ENOTRESPONSEMSG);
+
+ /* To tag must present in the response. */
+ PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);
+
+ /* Create the dialog. */
+ status = create_dialog((pjsip_user_agent*)first_dlg->ua, &dlg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Clone remote target. */
+ dlg->target = pjsip_uri_clone(dlg->pool, first_dlg->target);
+
+ /* Clone local info. */
+ dlg->local.info = pjsip_hdr_clone(dlg->pool, first_dlg->local.info);
+
+ /* Clone local tag. */
+ pj_strdup(dlg->pool, &dlg->local.info->tag, &first_dlg->local.info->tag);
+ dlg->local.tag_hval = first_dlg->local.tag_hval;
+
+ /* Clone local CSeq. */
+ dlg->local.first_cseq = first_dlg->local.first_cseq;
+ dlg->local.cseq = first_dlg->local.cseq;
+
+ /* Clone local Contact. */
+ dlg->local.contact = pjsip_hdr_clone(dlg->pool, first_dlg->local.contact);
+
+ /* Clone remote info. */
+ dlg->remote.info = pjsip_hdr_clone(dlg->pool, first_dlg->remote.info);
+
+ /* Set remote tag from the response. */
+ pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+
+ /* Initialize remote's CSeq to -1. */
+ dlg->remote.cseq = dlg->remote.first_cseq = -1;
+
+ /* Initial role is UAC. */
+ dlg->role = PJSIP_ROLE_UAC;
+
+ /* Secure? */
+ dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
+
+ /* Clone Call-ID header. */
+ dlg->call_id = pjsip_hdr_clone(dlg->pool, first_dlg->call_id);
+
+ /* Duplicate Route-Set. */
+ pj_list_init(&dlg->route_set);
+ r = first_dlg->route_set.next;
+ while (r != &first_dlg->route_set) {
+ pjsip_route_hdr *h;
+
+ h = pjsip_hdr_clone(dlg->pool, r);
+ pj_list_push_back(&dlg->route_set, h);
+
+ r = r->next;
+ }
+
+ /* Init client authentication session. */
+ status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess,
+ &first_dlg->auth_sess);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register this dialog to user agent. */
+ status = pjsip_ua_register_dlg(dlg->ua, dlg );
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ /* Done! */
+ *new_dlg = dlg;
+
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_dialog(dlg);
+ return status;
+}
+
+
+/*
+ * Destroy dialog.
+ */
+static pj_status_t unregister_and_destroy_dialog( pjsip_dialog *dlg )
+{
+ pj_status_t status;
+
+ /* Lock must have been held. */
+
+ /* Check dialog state. */
+ /* Number of sessions must be zero. */
+ PJ_ASSERT_RETURN(dlg->sess_count==0, PJ_EINVALIDOP);
+
+ /* MUST not have pending transactions. */
+ PJ_ASSERT_RETURN(dlg->tsx_count==0, PJ_EINVALIDOP);
+
+ /* Unregister from user agent. */
+ status = pjsip_ua_unregister_dlg(dlg->ua, dlg);
+ if (status != PJ_SUCCESS) {
+ pj_assert(!"Unexpected failed unregistration!");
+ return status;
+ }
+
+ /* Destroy this dialog. */
+ pj_mutex_destroy(dlg->mutex);
+ pjsip_endpt_release_pool(pjsip_ua_get_endpt(dlg->ua), dlg->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Set route_set
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
+ const pjsip_route_hdr *route_set )
+{
+ pjsip_route_hdr *r;
+
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+ pj_mutex_lock(dlg->mutex);
+
+ /* Clear route set. */
+ pj_list_init(&dlg->route_set);
+
+ if (!route_set) {
+ pj_mutex_unlock(dlg->mutex);
+ return PJ_SUCCESS;
+ }
+
+ r = route_set->next;
+ while (r != route_set) {
+ pjsip_route_hdr *new_r;
+
+ new_r = pjsip_hdr_clone(dlg->pool, r);
+ pj_list_push_back(&dlg->route_set, new_r);
+
+ r = r->next;
+ }
+
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Increment session counter.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg )
+{
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+ pj_mutex_lock(dlg->mutex);
+ ++dlg->sess_count;
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Decrement session counter.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg )
+{
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+ pj_mutex_lock(dlg->mutex);
+
+ --dlg->sess_count;
+
+ if (dlg->sess_count==0 && dlg->tsx_count==0)
+ status = unregister_and_destroy_dialog(dlg);
+ else {
+ pj_mutex_unlock(dlg->mutex);
+ status = PJ_SUCCESS;
+ }
+
+ return status;
+}
+
+
+/*
+ * Add usage.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
+ pjsip_module *mod,
+ void *mod_data )
+{
+ unsigned index;
+
+ PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);
+ PJ_ASSERT_RETURN(mod->id >= 0 && mod->id < PJSIP_MAX_MODULE,
+ PJ_EINVAL);
+ PJ_ASSERT_RETURN(dlg->usage_cnt < PJSIP_MAX_MODULE, PJ_EBUG);
+
+ pj_mutex_lock(dlg->mutex);
+
+ /* Usages are sorted on priority, lowest number first.
+ * Find position to put the new module, also makes sure that
+ * this module has not been registered before.
+ */
+ for (index=0; index<dlg->usage_cnt; ++index) {
+ if (dlg->usage[index] == mod) {
+ pj_assert(!"This module is already registered");
+ pj_mutex_unlock(dlg->mutex);
+ return PJSIP_ETYPEEXISTS;
+ }
+
+ if (dlg->usage[index]->priority > mod->priority)
+ break;
+ }
+
+ /* index holds position to put the module.
+ * Insert module at this index.
+ */
+ pj_array_insert(dlg->usage, sizeof(dlg->usage[0]), dlg->usage_cnt,
+ index, &mod);
+
+ /* Set module data. */
+ dlg->mod_data[mod->id] = mod_data;
+
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Create a new request within dialog (i.e. after the dialog session has been
+ * established). The construction of such requests follows the rule in
+ * RFC3261 section 12.2.1.
+ */
+static pj_status_t dlg_create_request_throw( pjsip_dialog *dlg,
+ const pjsip_method *method,
+ int cseq,
+ pjsip_tx_data **p_tdata )
+{
+ pjsip_tx_data *tdata;
+ pjsip_contact_hdr *contact;
+ pjsip_route_hdr *route, *end_list;
+ pj_status_t status;
+
+ /* Contact Header field.
+ * Contact can only be present in requests that establish dialog (in the
+ * core SIP spec, only INVITE).
+ */
+ if (pjsip_method_creates_dialog(method))
+ contact = dlg->local.contact;
+ else
+ contact = NULL;
+
+ /*
+ * Create the request by cloning from the headers in the
+ * dialog.
+ */
+ status = pjsip_endpt_create_request_from_hdr(pjsip_ua_get_endpt(dlg->ua),
+ method,
+ dlg->target,
+ dlg->local.info,
+ dlg->remote.info,
+ contact,
+ dlg->call_id,
+ cseq,
+ NULL,
+ &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Just copy dialog route-set to Route header.
+ * The transaction will do the processing as specified in Section 12.2.1
+ * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
+ */
+ route = dlg->route_set.next;
+ end_list = &dlg->route_set;
+ for (; route != end_list; route = route->next ) {
+ pjsip_route_hdr *r;
+ r = pjsip_hdr_shallow_clone( tdata->pool, route );
+ pjsip_routing_hdr_set_route(r);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
+ }
+
+ /* Copy authorization headers. */
+ status = pjsip_auth_clt_init_req( &dlg->auth_sess, tdata );
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Done. */
+ *p_tdata = tdata;
+
+ return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Create outgoing request.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_request( pjsip_dialog *dlg,
+ const pjsip_method *method,
+ int cseq,
+ pjsip_tx_data **p_tdata)
+{
+ pj_status_t status;
+ pjsip_tx_data *tdata = NULL;
+ PJ_USE_EXCEPTION;
+
+ PJ_ASSERT_RETURN(dlg && method && p_tdata, PJ_EINVAL);
+
+ /* Lock dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Use outgoing CSeq and increment it by one. */
+ if (cseq <= 0)
+ cseq = dlg->local.cseq + 1;
+
+ /* Keep compiler happy */
+ status = PJ_EBUG;
+
+ /* Create the request. */
+ PJ_TRY {
+ status = dlg_create_request_throw(dlg, method, cseq, &tdata);
+ }
+ PJ_CATCH_ANY {
+ status = PJ_ENOMEM;
+ }
+ PJ_END;
+
+ /* Failed! Delete transmit data. */
+ if (status != PJ_SUCCESS && tdata) {
+ pjsip_tx_data_dec_ref( tdata );
+ tdata = NULL;
+ }
+
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ *p_tdata = tdata;
+
+ return status;
+}
+
+
+/*
+ * Update CSeq in outgoing request to reflect the dialog.
+ * Then increment local CSeq.
+ */
+static void update_cseq( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata )
+{
+ pjsip_msg *msg = tdata->msg;
+
+ /* Start locking the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Update dialog's CSeq and message's CSeq if request is not
+ * ACK nor CANCEL.
+ */
+ if (msg->line.req.method.id != PJSIP_CANCEL_METHOD &&
+ msg->line.req.method.id != PJSIP_ACK_METHOD)
+ {
+ pjsip_cseq_hdr *ch;
+
+ ch = PJSIP_MSG_CSEQ_HDR(msg);
+ PJ_ASSERT_ON_FAIL(ch!=NULL, return);
+
+ ch->cseq = dlg->local.cseq++;
+
+ /* Force the whole message to be re-printed. */
+ pjsip_tx_data_invalidate_msg( tdata );
+ }
+
+}
+
+/*
+ * Send request statefully, and update dialog'c CSeq.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ pjsip_transaction **p_tsx )
+{
+ pjsip_transaction *tsx;
+ pj_status_t status;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,
+ PJSIP_ENOTREQUESTMSG);
+
+ /* Update CSeq */
+ update_cseq(dlg, tdata);
+
+ /* Create a new transaction.
+ * The transaction user is the user agent module.
+ */
+ status = pjsip_tsx_create_uac(dlg->ua, tdata, &tsx);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Attach this dialog to the transaction, so that user agent
+ * will dispatch events to this dialog.
+ */
+ tsx->mod_data[dlg->ua->id] = dlg;
+
+ /* Increment transaction counter. */
+ ++dlg->tsx_count;
+
+ /* Send the message. */
+ status = pjsip_tsx_send_msg(tsx, tdata);
+ if (status != PJ_SUCCESS) {
+ pjsip_tsx_terminate(tsx, tsx->status_code);
+ goto on_error;
+ }
+
+ /* Done. */
+ *p_tsx = tsx;
+
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+
+on_error:
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ /* Whatever happen delete the message. */
+ pjsip_tx_data_dec_ref( tdata );
+
+ *p_tsx = NULL;
+ return status;
+}
+
+
+/*
+ * Create response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ pjsip_tx_data **p_tdata)
+{
+ pj_status_t status;
+ pjsip_cseq_hdr *cseq;
+ pjsip_tx_data *tdata;
+ int st_class;
+
+ /* Create generic response. */
+ status = pjsip_endpt_create_response(pjsip_ua_get_endpt(dlg->ua),
+ rdata, st_code, st_text, &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Special treatment for 2xx response to request that establishes
+ * dialog.
+ *
+ * RFC 3261 Section 12.1.1
+ *
+ * When a UAS responds to a request with a response that establishes
+ * a dialog (such as a 2xx to INVITE):
+ * - MUST copy all Record-Route header field values from the request
+ * into the response (including the URIs, URI parameters, and any
+ * Record-Route header field parameters, whether they are known or
+ * unknown to the UAS) and MUST maintain the order of those values.
+ * - The Contact header field contains an address where the UAS would
+ * like to be contacted for subsequent requests in the dialog.
+ *
+ * Also from Table 3, page 119.
+ */
+ cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
+ pj_assert(cseq != NULL);
+
+ st_class = st_code / 100;
+
+ if (cseq->cseq == dlg->remote.first_cseq &&
+ (st_class==1 || st_class==2) && st_code != 100)
+ {
+ pjsip_hdr *rr, *hdr;
+
+ /* Duplicate Record-Route header from the request. */
+ rr = (pjsip_hdr*) rdata->msg_info.record_route;
+ while (rr) {
+ hdr = pjsip_hdr_clone(tdata->pool, rr);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+
+ rr = rr->next;
+ if (rr == &rdata->msg_info.msg->hdr)
+ break;
+ rr = pjsip_msg_find_hdr(rdata->msg_info.msg,
+ PJSIP_H_RECORD_ROUTE, rr);
+ }
+ }
+
+ /* Contact header. */
+ if (pjsip_method_creates_dialog(&cseq->method)) {
+ /* Add Contact header for 1xx, 2xx, 3xx and 485 response. */
+ if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
+ st_code==485)
+ {
+ /* Add contact header. */
+ pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
+
+ /* Add Allow header in 2xx and 405 response. */
+ if (st_class==2 || st_code==405) {
+ const pjsip_hdr *c_hdr;
+ c_hdr = pjsip_endpt_get_capability(pjsip_ua_get_endpt(dlg->ua),
+ PJSIP_H_ALLOW, NULL);
+ if (c_hdr) {
+ pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
+ }
+
+ /* Add Supported header in 2xx response. */
+ if (st_class==2) {
+ const pjsip_hdr *c_hdr;
+ c_hdr = pjsip_endpt_get_capability(pjsip_ua_get_endpt(dlg->ua),
+ PJSIP_H_SUPPORTED, NULL);
+ if (c_hdr) {
+ pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
+ }
+
+ }
+
+ /* Add To tag in all responses except 100 */
+ if (st_code != 100 && rdata->msg_info.to->tag.slen == 0) {
+ pjsip_to_hdr *to;
+
+ to = PJSIP_MSG_TO_HDR(tdata->msg);
+ pj_assert(to != NULL);
+
+ to->tag = dlg->local.info->tag;
+ }
+
+ /* Unlock the dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ /* Done. */
+ *p_tdata = tdata;
+ return PJ_SUCCESS;
+}
+
+/*
+ * Modify response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ int st_code,
+ const pj_str_t *st_text)
+{
+
+ PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
+ PJSIP_ENOTRESPONSEMSG);
+ PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
+
+ tdata->msg->line.status.code = st_code;
+ if (st_text) {
+ pj_strdup(tdata->pool, &tdata->msg->line.status.reason, st_text);
+ } else {
+ tdata->msg->line.status.reason = *pjsip_get_status_text(st_code);
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Send response statefully.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_send_response( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_tx_data *tdata)
+{
+ /* Sanity check. */
+ PJ_ASSERT_RETURN(dlg && tsx && tdata && tdata->msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
+ PJSIP_ENOTRESPONSEMSG);
+
+ /* The transaction must belong to this dialog. */
+ PJ_ASSERT_RETURN(tsx->mod_data[dlg->ua->id] == dlg, PJ_EINVALIDOP);
+
+ /* Check that transaction method and cseq match the response.
+ * This operation is sloooww (search CSeq header twice), that's why
+ * we only do it in debug mode.
+ */
+#if defined(PJ_DEBUG) && PJ_DEBUG!=0
+ PJ_ASSERT_RETURN( PJSIP_MSG_CSEQ_HDR(tdata->msg)->cseq == tsx->cseq &&
+ pjsip_method_cmp(&PJSIP_MSG_CSEQ_HDR(tdata->msg)->method,
+ &tsx->method)==0,
+ PJ_EINVALIDOP);
+#endif
+
+ return pjsip_tsx_send_msg(tsx, tdata);
+}
+
+
+/* This function is called by user agent upon receiving incoming response
+ * message.
+ */
+void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
+{
+ pj_status_t status;
+ pjsip_transaction *tsx;
+ unsigned i;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Create UAS transaction for this request. */
+ status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
+ PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;});
+
+ /* Put this dialog in the transaction data. */
+ tsx->mod_data[dlg->ua->id] = dlg;
+
+ /* Add transaction count. */
+ ++dlg->tsx_count;
+
+ /* Report the request to dialog usages. */
+ for (i=0; i<dlg->usage_cnt; ++i) {
+ pj_bool_t processed;
+
+ if (!dlg->usage[i]->on_rx_request)
+ continue;
+
+ processed = (*dlg->usage[i]->on_rx_request)(rdata);
+
+ if (processed)
+ break;
+ }
+
+ if (i==dlg->usage_cnt) {
+ pjsip_tx_data *tdata;
+
+ PJ_LOG(4,(dlg->obj_name,
+ "%s is unhandled by dialog usages. "
+ "Dialog will response with 500 (Internal Server Error)",
+ pjsip_rx_data_get_info(rdata)));
+ status = pjsip_endpt_create_response(pjsip_ua_get_endpt(dlg->ua),
+ rdata,
+ PJSIP_SC_INTERNAL_SERVER_ERROR,
+ NULL, &tdata);
+ if (status == PJ_SUCCESS)
+ status = pjsip_tsx_send_msg(tsx, tdata);
+
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJSIP_ERR_MSG_SIZE];
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(dlg->obj_name,"Error sending %s: %s",
+ pjsip_tx_data_get_info(tdata), errmsg));
+ pjsip_tsx_terminate(tsx, 500);
+ }
+ }
+
+on_return:
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+}
+
+/* This function is called by user agent upon receiving incoming response
+ * message.
+ */
+void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
+{
+ unsigned i;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Update the remote tag, if none is specified yet. */
+ if (dlg->remote.info->tag.slen == 0 && rdata->msg_info.to->tag.slen != 0) {
+
+ pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+
+ /* No need to update remote's tag_hval since its never used. */
+ }
+
+ /* Check that rdata already has dialog in mod_data. */
+ pj_assert(pjsip_rdata_get_dlg(rdata) == dlg);
+
+ /* Pass to dialog usages. */
+ for (i=0; i<dlg->usage_cnt; ++i) {
+ pj_bool_t processed;
+
+ if (!dlg->usage[i]->on_rx_response)
+ continue;
+
+ processed = (*dlg->usage[i]->on_rx_response)(rdata);
+
+ if (processed)
+ break;
+ }
+
+ if (i==dlg->usage_cnt) {
+ PJ_LOG(4,(dlg->obj_name, "%s is unhandled by dialog usages",
+ pjsip_rx_data_get_info(rdata)));
+ }
+
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+}
+
+/* This function is called by user agent upon receiving transaction
+ * state notification.
+ */
+void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_event *e )
+{
+ unsigned i;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ if (tsx->state == PJSIP_TSX_STATE_TERMINATED)
+ --dlg->tsx_count;
+
+ /* Pass to dialog usages. */
+ for (i=0; i<dlg->usage_cnt; ++i) {
+
+ if (!dlg->usage[i]->on_tsx_state)
+ continue;
+
+ (*dlg->usage[i]->on_tsx_state)(tsx, e);
+ }
+
+ if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 &&
+ dlg->sess_count == 0)
+ {
+ /* Time to destroy dialog. */
+ unregister_and_destroy_dialog(dlg);
+
+ } else {
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+ }
+}
+
+
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 71e7cff8..3d109e4c 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -77,18 +77,12 @@ struct pjsip_endpoint
/** Module list, sorted by priority. */
pjsip_module module_list;
- /** Number of supported methods. */
- unsigned method_cnt;
-
- /** Array of supported methods. */
- const pjsip_method *methods[MAX_METHODS];
-
- /** Allow header. */
- pjsip_allow_hdr *allow_hdr;
-
/** Route header list. */
pjsip_route_hdr route_hdr_list;
+ /** Capability header list. */
+ pjsip_hdr cap_hdr;
+
/** Additional request headers. */
pjsip_hdr req_hdr;
};
@@ -196,7 +190,6 @@ PJ_DEF(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt,
pj_list_insert_before(m, mod);
/* Done. */
- PJ_TODO(BUILD_ALLOW_HEADER_BASED_ON_MODULES_SUPPORTED_METHODS);
on_return:
pj_rwmutex_unlock_write(endpt->mod_mutex);
@@ -248,19 +241,86 @@ PJ_DEF(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,
/* Done. */
status = PJ_SUCCESS;
- PJ_TODO(REMOVE_METHODS_FROM_ALLOW_HEADER_WHEN_MODULE_IS_UNREGISTERED);
-
on_return:
pj_rwmutex_unlock_write(endpt->mod_mutex);
return status;
}
+
+/*
+ * Get the value of the specified capability header field.
+ */
+PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
+ int htype,
+ const pj_str_t *hname)
+{
+ pjsip_hdr *hdr = endpt->cap_hdr.next;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(endpt != NULL, NULL);
+ PJ_ASSERT_RETURN(htype != PJSIP_H_OTHER || hname, NULL);
+
+ if (htype != PJSIP_H_OTHER) {
+ while (hdr != &endpt->cap_hdr) {
+ if (hdr->type == htype)
+ return hdr;
+ hdr = hdr->next;
+ }
+ }
+ return NULL;
+}
+
+
/*
- * Get "Allow" header.
+ * Add or register new capabilities as indicated by the tags to the
+ * appropriate header fields in the endpoint.
*/
-PJ_DEF(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )
+PJ_DEF(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
+ pjsip_module *mod,
+ int htype,
+ const pj_str_t *hname,
+ unsigned count,
+ const pj_str_t tags[])
{
- return endpt->allow_hdr;
+ pjsip_generic_array_hdr *hdr;
+ unsigned i;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(endpt!=NULL && mod!=NULL && count>0 && tags, PJ_EINVAL);
+ PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT ||
+ htype==PJSIP_H_ALLOW ||
+ htype==PJSIP_H_SUPPORTED,
+ PJ_EINVAL);
+
+ /* Find the header. */
+ hdr = (pjsip_generic_array_hdr*) pjsip_endpt_get_capability(endpt,
+ htype, hname);
+
+ /* Create the header when it's not present */
+ if (hdr == NULL) {
+ switch (htype) {
+ case PJSIP_H_ACCEPT:
+ hdr = pjsip_accept_hdr_create(endpt->pool);
+ break;
+ case PJSIP_H_ALLOW:
+ hdr = pjsip_allow_hdr_create(endpt->pool);
+ break;
+ case PJSIP_H_SUPPORTED:
+ hdr = pjsip_supported_hdr_create(endpt->pool);
+ break;
+ default:
+ return PJ_EINVAL;
+ }
+ }
+
+ /* Add the tags to the header. */
+ for (i=0; i<count; ++i) {
+ pj_strdup(endpt->pool, &hdr->values[hdr->count], &tags[i]);
+ ++hdr->count;
+ }
+
+ /* Done. */
+ return PJ_SUCCESS;
}
/*
@@ -325,7 +385,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
pj_status_t status;
pj_pool_t *pool;
pjsip_endpoint *endpt;
- pjsip_max_forwards_hdr *mf_hdr;
+ pjsip_max_fwd_hdr *mf_hdr;
pj_lock_t *lock = NULL;
PJ_LOG(5, (THIS_FILE, "Creating endpoint instance..."));
@@ -419,10 +479,13 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
pj_list_init(&endpt->route_hdr_list);
/* Add "Max-Forwards" for request header. */
- mf_hdr = pjsip_max_forwards_hdr_create(endpt->pool);
- mf_hdr->ivalue = PJSIP_MAX_FORWARDS_VALUE;
+ mf_hdr = pjsip_max_fwd_hdr_create(endpt->pool,
+ PJSIP_MAX_FORWARDS_VALUE);
pj_list_insert_before( &endpt->req_hdr, mf_hdr);
+ /* Initialize capability header list. */
+ pj_list_init(&endpt->cap_hdr);
+
/* Done. */
*p_endpt = endpt;
return status;
diff --git a/pjsip/src/pjsip/sip_errno.c b/pjsip/src/pjsip/sip_errno.c
index a2faf1a2..077f6553 100644
--- a/pjsip/src/pjsip/sip_errno.c
+++ b/pjsip/src/pjsip/sip_errno.c
@@ -45,6 +45,7 @@ static const struct
{ PJSIP_EINVALIDSTATUS, "Invalid status code"},
+ { PJSIP_EINVALIDURI, "Invalid URI" },
{ PJSIP_EINVALIDSCHEME, "Invalid URI scheme" },
{ PJSIP_EMISSINGREQURI, "Missing Request-URI" },
{ PJSIP_EINVALIDREQURI, "Invalid Request URI" },
@@ -77,7 +78,10 @@ static const struct
{ PJSIP_EAUTHACCNOTFOUND, "Account or credential not found" },
{ PJSIP_EAUTHACCDISABLED, "Account or credential is disabled" },
{ PJSIP_EAUTHINVALIDREALM, "Invalid authorization realm"},
- { PJSIP_EAUTHINVALIDDIGEST, "Invalid authorization digest" }
+ { PJSIP_EAUTHINVALIDDIGEST, "Invalid authorization digest" },
+
+ /* UA/dialog layer. */
+ { PJSIP_EMISSINGTAG, "Missing From/To tag parameter" }
};
diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
index 6010ba05..23e97f77 100644
--- a/pjsip/src/pjsip/sip_msg.c
+++ b/pjsip/src/pjsip/sip_msg.c
@@ -498,31 +498,40 @@ static pjsip_hdr_vptr generic_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_string_hdr_print,
};
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,
- const pj_str_t *hnames )
+PJ_DEF(pjsip_generic_string_hdr*)
+pjsip_generic_string_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hnames,
+ const pj_str_t *hvalue)
{
- pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
+ pjsip_generic_string_hdr *hdr = mem;
+
init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);
if (hnames) {
pj_strdup(pool, &hdr->name, hnames);
hdr->sname = hdr->name;
}
- hdr->hvalue.ptr = NULL;
- hdr->hvalue.slen = 0;
+ if (hvalue) {
+ pj_strdup(pool, &hdr->hvalue, hvalue);
+ } else {
+ hdr->hvalue.ptr = NULL;
+ hdr->hvalue.slen = 0;
+ }
+
return hdr;
}
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
- const pj_str_t *hname,
- const pj_str_t *hvalue)
+PJ_DEF(pjsip_generic_string_hdr*)
+pjsip_generic_string_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hnames,
+ const pj_str_t *hvalue)
{
- pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, hname);
- pj_strdup(pool, &hdr->hvalue, hvalue);
- return hdr;
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
+ return pjsip_generic_string_hdr_init(pool, mem, hnames, hvalue);
}
-static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
- char *buf, pj_size_t size)
+static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
+ char *buf, pj_size_t size)
{
char *p = buf;
@@ -543,11 +552,12 @@ static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
static pjsip_generic_string_hdr* pjsip_generic_string_hdr_clone( pj_pool_t *pool,
const pjsip_generic_string_hdr *rhs)
{
- pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, &rhs->name);
+ pjsip_generic_string_hdr *hdr;
+
+ hdr = pjsip_generic_string_hdr_create(pool, &rhs->name, &rhs->hvalue);
hdr->type = rhs->type;
hdr->sname = hdr->name;
- pj_strdup( pool, &hdr->hvalue, &rhs->hvalue);
return hdr;
}
@@ -578,26 +588,28 @@ static pjsip_hdr_vptr generic_int_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_int_hdr_print,
};
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
- const pj_str_t *hnames )
+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hnames,
+ int value)
{
- pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
+ pjsip_generic_int_hdr *hdr = mem;
+
init_hdr(hdr, PJSIP_H_OTHER, &generic_int_hdr_vptr);
if (hnames) {
pj_strdup(pool, &hdr->name, hnames);
hdr->sname = hdr->name;
}
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
}
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
- const pj_str_t *hname,
- int value)
+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hnames,
+ int value)
{
- pjsip_generic_int_hdr *hdr = pjsip_generic_int_hdr_create(pool, hname);
- hdr->ivalue = value;
- return hdr;
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
+ return pjsip_generic_int_hdr_init(pool, mem, hnames, value);
}
static int pjsip_generic_int_hdr_print( pjsip_generic_int_hdr *hdr,
@@ -651,10 +663,13 @@ static pjsip_hdr_vptr generic_array_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_array_hdr_print,
};
-PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,
- const pj_str_t *hnames)
+
+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hnames)
{
- pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
+ pjsip_generic_array_hdr *hdr = mem;
+
init_hdr(hdr, PJSIP_H_OTHER, &generic_array_hdr_vptr);
if (hnames) {
pj_strdup(pool, &hdr->name, hnames);
@@ -662,6 +677,13 @@ PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,
}
hdr->count = 0;
return hdr;
+}
+
+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hnames)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
+ return pjsip_generic_array_hdr_init(pool, mem, hnames);
}
@@ -713,38 +735,69 @@ static pjsip_generic_array_hdr* pjsip_generic_array_hdr_shallow_clone( pj_pool_t
/*
* Accept header.
*/
-PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_accept_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_accept_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_ACCEPT, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_accept_hdr));
+ return pjsip_accept_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Allow header.
*/
-PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_allow_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_allow_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_ALLOW, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_allow_hdr));
+ return pjsip_allow_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Call-ID header.
*/
-PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_cid_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_cid_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_CALL_ID, &generic_hdr_vptr);
return hdr;
+
+}
+
+PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_cid_hdr));
+ return pjsip_cid_hdr_init(pool, mem);
}
@@ -763,14 +816,24 @@ static pjsip_hdr_vptr clen_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_clen_hdr_print,
};
-PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_clen_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
+ pjsip_clen_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_CONTENT_LENGTH, &clen_hdr_vptr);
hdr->len = 0;
return hdr;
}
+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
+ return pjsip_clen_hdr_init(pool, mem);
+}
+
static int pjsip_clen_hdr_print( pjsip_clen_hdr *hdr,
char *buf, pj_size_t size)
{
@@ -815,9 +878,13 @@ static pjsip_hdr_vptr cseq_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_cseq_hdr_print,
};
-PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
+ pjsip_cseq_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_CSEQ, &cseq_hdr_vptr);
hdr->cseq = 0;
hdr->method.id = PJSIP_OTHER_METHOD;
@@ -826,6 +893,12 @@ PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
return hdr;
}
+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
+ return pjsip_cseq_hdr_init(pool, mem);
+}
+
static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size)
{
char *p = buf;
@@ -884,15 +957,26 @@ static pjsip_hdr_vptr contact_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_contact_hdr_print,
};
-PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_contact_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_contact_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_contact_hdr));
init_hdr(hdr, PJSIP_H_CONTACT, &contact_hdr_vptr);
hdr->expires = -1;
pj_list_init(&hdr->other_param);
return hdr;
}
+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_contact_hdr));
+ return pjsip_contact_hdr_init(pool, mem);
+}
+
static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf,
pj_size_t size)
{
@@ -1002,11 +1086,23 @@ static pjsip_hdr_vptr ctype_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_ctype_hdr_print,
};
-PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_ctype_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_ctype_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_ctype_hdr));
init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);
return hdr;
+
+}
+
+PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_ctype_hdr));
+ return pjsip_ctype_hdr_init(pool, mem);
}
static int print_media_type(char *buf, const pjsip_media_type *media)
@@ -1066,12 +1162,25 @@ static pjsip_ctype_hdr* pjsip_ctype_hdr_clone( pj_pool_t *pool,
/*
* Expires header.
*/
-PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value)
{
- pjsip_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_expires_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_EXPIRES, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
+
+}
+
+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool,
+ int value )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_expires_hdr));
+ return pjsip_expires_hdr_init(pool, mem, value);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1093,30 +1202,53 @@ static pjsip_hdr_vptr fromto_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_fromto_hdr_print,
};
-PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_from_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_from_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_from_hdr));
init_hdr(hdr, PJSIP_H_FROM, &fromto_hdr_vptr);
pj_list_init(&hdr->other_param);
return hdr;
}
-PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
{
- pjsip_to_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_from_hdr));
+ return pjsip_from_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_init( pj_pool_t *pool,
+ void *mem )
+{
+ pjsip_to_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_to_hdr));
init_hdr(hdr, PJSIP_H_TO, &fromto_hdr_vptr);
pj_list_init(&hdr->other_param);
return hdr;
+
+}
+
+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_to_hdr));
+ return pjsip_to_hdr_init(pool, mem);
}
-PJ_DEF(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr )
+PJ_DEF(pjsip_from_hdr*) pjsip_fromto_hdr_set_from( pjsip_fromto_hdr *hdr )
{
hdr->type = PJSIP_H_FROM;
hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_FROM];
return hdr;
}
-PJ_DEF(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr )
+PJ_DEF(pjsip_to_hdr*) pjsip_fromto_hdr_set_to( pjsip_fromto_hdr *hdr )
{
hdr->type = PJSIP_H_TO;
hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_TO];
@@ -1183,12 +1315,25 @@ pjsip_fromto_hdr_shallow_clone( pj_pool_t *pool,
/*
* Max-Forwards header.
*/
-PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_max_fwd_hdr*) pjsip_max_fwd_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value)
{
- pjsip_max_forwards_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_max_fwd_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_MAX_FORWARDS, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
+
+}
+
+PJ_DEF(pjsip_max_fwd_hdr*) pjsip_max_fwd_hdr_create(pj_pool_t *pool,
+ int value)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_max_fwd_hdr));
+ return pjsip_max_fwd_hdr_init(pool, mem, value);
}
@@ -1196,14 +1341,26 @@ PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)
/*
* Min-Expires header.
*/
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value )
{
- pjsip_min_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_min_expires_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_MIN_EXPIRES, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
}
+PJ_DEF(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool,
+ int value )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_min_expires_hdr));
+ return pjsip_min_expires_hdr_init(pool, mem, value );
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Record-Route and Route header.
@@ -1219,24 +1376,45 @@ static pjsip_hdr_vptr routing_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_routing_hdr_print,
};
-PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_rr_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_rr_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_RECORD_ROUTE, &routing_hdr_vptr);
pjsip_name_addr_init(&hdr->name_addr);
pj_list_init(&hdr->other_param);
return hdr;
+
}
-PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
{
- pjsip_route_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_rr_hdr));
+ return pjsip_rr_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_init( pj_pool_t *pool,
+ void *mem )
+{
+ pjsip_route_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_ROUTE, &routing_hdr_vptr);
pjsip_name_addr_init(&hdr->name_addr);
pj_list_init(&hdr->other_param);
return hdr;
}
+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_route_hdr));
+ return pjsip_route_hdr_init(pool, mem);
+}
+
PJ_DEF(pjsip_rr_hdr*) pjsip_routing_hdr_set_rr( pjsip_routing_hdr *hdr )
{
hdr->type = PJSIP_H_RECORD_ROUTE;
@@ -1304,52 +1482,93 @@ static pjsip_routing_hdr* pjsip_routing_hdr_shallow_clone( pj_pool_t *pool,
/*
* Require header.
*/
-PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_require_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_require_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_REQUIRE, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_require_hdr));
+ return pjsip_require_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Retry-After header.
*/
-PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value )
{
- pjsip_retry_after_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_retry_after_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_RETRY_AFTER, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
}
+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool,
+ int value )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_retry_after_hdr));
+ return pjsip_retry_after_hdr_init(pool, mem, value );
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Supported header.
*/
-PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_supported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_supported_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
init_hdr(hdr, PJSIP_H_SUPPORTED, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_supported_hdr));
+ return pjsip_supported_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Unsupported header.
*/
-PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_unsupported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_unsupported_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_UNSUPPORTED, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_unsupported_hdr));
+ return pjsip_unsupported_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Via header.
@@ -1365,15 +1584,26 @@ static pjsip_hdr_vptr via_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_via_hdr_print,
};
-PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_via_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_via_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_via_hdr));
init_hdr(hdr, PJSIP_H_VIA, &via_hdr_vptr);
- //hdr->sent_by.port = 5060;
hdr->ttl_param = -1;
hdr->rport_param = -1;
pj_list_init(&hdr->other_param);
return hdr;
+
+}
+
+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_via_hdr));
+ return pjsip_via_hdr_init(pool, mem);
}
static int pjsip_via_hdr_print( pjsip_via_hdr *hdr,
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index f281824b..352ea2ed 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -1167,10 +1167,10 @@ static pjsip_sip_uri *int_parse_sip_url( pj_scanner *scanner,
}
if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
} else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {
- url = pjsip_url_create(pool, 1);
+ url = pjsip_sip_uri_create(pool, 1);
} else {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
@@ -1541,7 +1541,7 @@ static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )
/* Parse Expires header. */
static pjsip_hdr* parse_hdr_expires(pjsip_parse_ctx *ctx)
{
- pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool);
+ pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
}
@@ -1601,7 +1601,7 @@ static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx )
static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx)
{
pjsip_retry_after_hdr *hdr;
- hdr = pjsip_retry_after_hdr_create(ctx->pool);
+ hdr = pjsip_retry_after_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
}
@@ -1673,8 +1673,8 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
/* Parse Max-Forwards header. */
static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
{
- pjsip_max_forwards_hdr *hdr;
- hdr = pjsip_max_forwards_hdr_create(ctx->pool);
+ pjsip_max_fwd_hdr *hdr;
+ hdr = pjsip_max_fwd_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
if (ctx->rdata)
@@ -1687,7 +1687,7 @@ static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
static pjsip_hdr* parse_hdr_min_expires(pjsip_parse_ctx *ctx)
{
pjsip_min_expires_hdr *hdr;
- hdr = pjsip_min_expires_hdr_create(ctx->pool);
+ hdr = pjsip_min_expires_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
}
@@ -1820,7 +1820,7 @@ static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx )
{
pjsip_generic_string_hdr *hdr;
- hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL);
+ hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL, NULL);
parse_generic_string_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
diff --git a/pjsip/src/pjsip/sip_tel_uri.c b/pjsip/src/pjsip/sip_tel_uri.c
index 4563f6dc..73e50dfa 100644
--- a/pjsip/src/pjsip/sip_tel_uri.c
+++ b/pjsip/src/pjsip/sip_tel_uri.c
@@ -64,9 +64,9 @@ static pj_str_t pjsip_PH_CTX_STR = { "phone-context", 13 };
static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri* );
static void *tel_uri_get_uri( pjsip_tel_uri* );
-static int tel_uri_print( pjsip_uri_context_e context,
- const pjsip_tel_uri *url,
- char *buf, pj_size_t size);
+static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
+ const pjsip_tel_uri *url,
+ char *buf, pj_size_t size);
static int tel_uri_cmp( pjsip_uri_context_e context,
const pjsip_tel_uri *url1, const pjsip_tel_uri *url2);
static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs);
@@ -164,9 +164,9 @@ pj_status_t pjsip_tel_uri_subsys_init(void)
}
/* Print tel: URI */
-static int tel_uri_print( pjsip_uri_context_e context,
- const pjsip_tel_uri *uri,
- char *buf, pj_size_t size)
+static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
+ const pjsip_tel_uri *uri,
+ char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 61632ed7..39bc8d20 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -61,8 +61,6 @@ static struct mod_tsx_layer
-1, /* Module ID */
PJSIP_MOD_PRIORITY_TSX_LAYER, /* Priority. */
NULL, /* User_data. */
- 0, /* Methods count. */
- { NULL }, /* Array of methods. */
mod_tsx_layer_load, /* load(). */
mod_tsx_layer_start, /* start() */
mod_tsx_layer_stop, /* stop() */
@@ -507,16 +505,19 @@ static pj_status_t mod_tsx_layer_register_tsx( pjsip_transaction *tsx)
pj_mutex_lock(mod_tsx_layer.mutex);
/* Check if no transaction with the same key exists. */
- if (pj_hash_get( mod_tsx_layer.htable, &tsx->transaction_key.ptr,
- tsx->transaction_key.slen) != NULL)
- {
- pj_mutex_unlock(mod_tsx_layer.mutex);
- return PJ_EEXISTS;
- }
+ PJ_ASSERT_ON_FAIL(pj_hash_get( mod_tsx_layer.htable,
+ &tsx->transaction_key.ptr,
+ tsx->transaction_key.slen,
+ &tsx->hashed_key) == NULL,
+ {
+ pj_mutex_unlock(mod_tsx_layer.mutex);
+ return PJ_EEXISTS;
+ }
+ );
/* Register the transaction to the hash table. */
pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, tsx);
+ tsx->transaction_key.slen, tsx->hashed_key, tsx);
/* Unlock mutex. */
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -538,7 +539,7 @@ static void mod_tsx_layer_unregister_tsx( pjsip_transaction *tsx)
/* Register the transaction to the hash table. */
pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, NULL);
+ tsx->transaction_key.slen, tsx->hashed_key, NULL);
/* Unlock mutex. */
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -554,7 +555,7 @@ PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
pjsip_transaction *tsx;
pj_mutex_lock(mod_tsx_layer.mutex);
- tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen );
+ tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen, NULL );
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -648,7 +649,7 @@ static pj_bool_t mod_tsx_layer_on_rx_request(pjsip_rx_data *rdata)
/* Find transaction. */
pj_mutex_lock( mod_tsx_layer.mutex );
- tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen );
+ tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, NULL );
if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
/* Transaction not found.
@@ -689,7 +690,7 @@ static pj_bool_t mod_tsx_layer_on_rx_response(pjsip_rx_data *rdata)
/* Find transaction. */
pj_mutex_lock( mod_tsx_layer.mutex );
- tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen );
+ tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, NULL );
if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
/* Transaction not found.
@@ -1035,6 +1036,10 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uac( pjsip_module *tsx_user,
PJSIP_ROLE_UAC, &tsx->method,
&via->branch_param);
+ /* Calculate hashed key value. */
+ tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
+ tsx->transaction_key.slen);
+
PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
tsx->transaction_key.ptr));
@@ -1140,6 +1145,10 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
return status;
}
+ /* Calculate hashed key value. */
+ tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
+ tsx->transaction_key.slen);
+
/* Duplicate branch parameter for transaction. */
branch = &rdata->msg_info.via->branch_param;
pj_strdup(tsx->pool, &tsx->branch, branch);
@@ -1179,6 +1188,9 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
return status;
}
+ /* Put this transaction in rdata's mod_data. */
+ rdata->endpt_info.mod_data[mod_tsx_layer.mod.id] = tsx;
+
/* Unlock transaction and return. */
unlock_tsx(tsx, &lck);
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 46d98d99..88531876 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -43,22 +43,20 @@ static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata);
*/
static pjsip_module mod_msg_print =
{
- NULL, NULL, /* prev and next */
- { "mod-msg-print", 13}, /* Name. */
- -1, /* Id */
- PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
- NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
- NULL, /* load() */
- NULL, /* start() */
- NULL, /* stop() */
- NULL, /* unload() */
- NULL, /* on_rx_request() */
- NULL, /* on_rx_response() */
- &mod_on_tx_msg, /* on_tx_request() */
- &mod_on_tx_msg, /* on_tx_response() */
- NULL, /* on_tsx_state() */
+ NULL, NULL, /* prev and next */
+ { "mod-msg-print", 13}, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
+ NULL, /* User data. */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ NULL, /* on_rx_request() */
+ NULL, /* on_rx_response() */
+ &mod_on_tx_msg, /* on_tx_request() */
+ &mod_on_tx_msg, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
};
/*
@@ -348,7 +346,7 @@ PJ_DEF(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata )
{
if (tdata==NULL || tdata->msg==NULL)
- return "INVALID MSG";
+ return "NULL";
if (tdata->info)
return tdata->info;
@@ -589,7 +587,7 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
*/
key_len = sizeof(tp->key.type) + tp->addr_len;
pj_lock_acquire(mgr->lock);
- pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, tp);
+ pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, tp);
pj_lock_release(mgr->lock);
return PJ_SUCCESS;
@@ -617,7 +615,7 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
* Unregister from hash table.
*/
key_len = sizeof(tp->key.type) + tp->addr_len;
- pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, NULL);
+ pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, NULL);
pj_lock_release(mgr->lock);
@@ -878,7 +876,8 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
}
/* Perform basic header checking. */
- if (rdata->msg_info.cid->id.ptr == NULL ||
+ if (rdata->msg_info.cid == NULL ||
+ rdata->msg_info.cid->id.slen == 0 ||
rdata->msg_info.from == NULL ||
rdata->msg_info.to == NULL ||
rdata->msg_info.via == NULL ||
@@ -961,7 +960,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
key.type = type;
pj_memcpy(&key.addr, remote, addr_len);
- transport = pj_hash_get(mgr->table, &key, key_len);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
if (transport == NULL) {
unsigned flag = pjsip_transport_get_flag_from_type(type);
const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
@@ -974,7 +973,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pj_memset(addr, 0, sizeof(pj_sockaddr_in));
key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
- transport = pj_hash_get(mgr->table, &key, key_len);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
}
/* For datagram INET transports, try lookup with zero address.
*/
@@ -987,7 +986,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
addr->sin_family = PJ_AF_INET;
key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
- transport = pj_hash_get(mgr->table, &key, key_len);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
}
}
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
new file mode 100644
index 00000000..90885847
--- /dev/null
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -0,0 +1,674 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_transaction.h>
+#include <pj/os.h>
+#include <pj/hash.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+
+
+#define THIS_FILE "sip_ua_layer.c"
+
+/*
+ * Static prototypes.
+ */
+static pj_status_t mod_ua_load(pjsip_endpoint *endpt);
+static pj_status_t mod_ua_unload(void);
+static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata);
+static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata);
+static void mod_ua_on_tsx_state(pjsip_transaction*, pjsip_event*);
+
+
+extern long pjsip_dlg_lock_tls_id; /* defined in sip_dialog.c */
+
+/* This struct is used to represent list of dialog inside a dialog set.
+ * We don't want to use pjsip_dialog for this purpose, to save some
+ * memory (about 100 bytes per dialog set).
+ */
+struct dlg_set_head
+{
+ PJ_DECL_LIST_MEMBER(pjsip_dialog);
+};
+
+/* This struct represents a dialog set.
+ * This is the value that will be put in the UA's hash table.
+ */
+struct dlg_set
+{
+ /* To put this node in free dlg_set nodes in UA. */
+ PJ_DECL_LIST_MEMBER(struct dlg_set);
+
+ /* This is the buffer to store this entry in the hash table. */
+ char ht_entry[PJ_HASH_ENTRY_SIZE];
+
+ /* List of dialog in this dialog set. */
+ struct dlg_set_head dlg_list;
+};
+
+
+/*
+ * Module interface.
+ */
+static struct user_agent
+{
+ pjsip_module mod;
+ pj_pool_t *pool;
+ pjsip_endpoint *endpt;
+ pj_mutex_t *mutex;
+ pj_hash_table_t *dlg_table;
+ pjsip_ua_init_param param;
+ struct dlg_set free_dlgset_nodes;
+
+} mod_ua =
+{
+ {
+ NULL, NULL, /* prev, next. */
+ { "mod-ua", 6 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority */
+ NULL, /* User data. */
+ &mod_ua_load, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ &mod_ua_unload, /* unload() */
+ &mod_ua_on_rx_request, /* on_rx_request() */
+ &mod_ua_on_rx_response, /* on_rx_response() */
+ NULL, /* on_tx_request. */
+ NULL, /* on_tx_response() */
+ &mod_ua_on_tsx_state, /* on_tsx_state() */
+ }
+};
+
+/*
+ * mod_ua_load()
+ *
+ * Called when module is being loaded by endpoint.
+ */
+static pj_status_t mod_ua_load(pjsip_endpoint *endpt)
+{
+ pj_status_t status;
+
+ /* Initialize the user agent. */
+ mod_ua.endpt = endpt;
+ mod_ua.pool = pjsip_endpt_create_pool( endpt, "ua%p", PJSIP_POOL_LEN_UA,
+ PJSIP_POOL_INC_UA);
+ if (mod_ua.pool == NULL)
+ return PJ_ENOMEM;
+
+ status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT);
+ if (mod_ua.dlg_table == NULL)
+ return PJ_ENOMEM;
+
+ pj_list_init(&mod_ua.free_dlgset_nodes);
+
+ /* Initialize dialog lock. */
+ status = pj_thread_local_alloc(&pjsip_dlg_lock_tls_id);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
+
+ return PJ_SUCCESS;
+
+}
+
+/*
+ * mod_ua_unload()
+ *
+ * Called when module is being unloaded.
+ */
+static pj_status_t mod_ua_unload(void)
+{
+ pj_thread_local_free(pjsip_dlg_lock_tls_id);
+ pj_mutex_destroy(mod_ua.mutex);
+
+ /* Release pool */
+ if (mod_ua.pool) {
+ pjsip_endpt_release_pool( mod_ua.endpt, mod_ua.pool );
+ }
+ return PJ_SUCCESS;
+}
+
+/*
+ * mod_ua_on_tsx_stats()
+ *
+ * Called on changed on transaction state.
+ */
+static void mod_ua_on_tsx_state( pjsip_transaction *tsx, pjsip_event *e)
+{
+ pjsip_dialog *dlg;
+
+ /* Get the dialog where this transaction belongs. */
+ dlg = tsx->mod_data[mod_ua.mod.id];
+
+ /* Must have the dialog instance! */
+ PJ_ASSERT_ON_FAIL(dlg != NULL, return);
+
+ /* Hand over the event to the dialog. */
+ pjsip_dlg_on_tsx_state(dlg, tsx, e);
+}
+
+
+/*
+ * Init user agent module and register it to the endpoint.
+ */
+PJ_DEF(pj_status_t) pjsip_ua_init( pjsip_endpoint *endpt,
+ const pjsip_ua_init_param *prm)
+{
+ pj_status_t status;
+
+ /* Check if module already registered. */
+ PJ_ASSERT_RETURN(mod_ua.mod.id == -1, PJ_EINVALIDOP);
+
+ /* Copy param, if exists. */
+ if (prm)
+ pj_memcpy(&mod_ua.param, prm, sizeof(pjsip_ua_init_param));
+
+ /* Register the module. */
+ status = pjsip_endpt_register_module(endpt, &mod_ua.mod);
+
+ return status;
+}
+
+/*
+ * Get the instance of the user agent.
+ *
+ */
+PJ_DEF(pjsip_user_agent*) pjsip_ua_instance(void)
+{
+ return &mod_ua.mod;
+}
+
+
+/*
+ * Destroy the user agent layer.
+ */
+PJ_DEF(pj_status_t) pjsip_ua_destroy(void)
+{
+ /* Check if module already destroyed. */
+ PJ_ASSERT_RETURN(mod_ua.mod.id != -1, PJ_EINVALIDOP);
+
+ return pjsip_endpt_unregister_module(mod_ua.endpt, &mod_ua.mod);
+}
+
+
+
+/*
+ * Create key to identify dialog set.
+ */
+PJ_DEF(void) pjsip_ua_create_dlg_set_key( pj_pool_t *pool,
+ pj_str_t *set_key,
+ const pj_str_t *call_id,
+ const pj_str_t *local_tag)
+{
+ PJ_ASSERT_ON_FAIL(pool && set_key && call_id && local_tag, return;);
+
+ set_key->slen = call_id->slen + local_tag->slen + 1;
+ set_key->ptr = pj_pool_alloc(pool, set_key->slen);
+ pj_assert(set_key->ptr != NULL);
+
+ pj_memcpy(set_key->ptr, call_id->ptr, call_id->slen);
+ set_key->ptr[call_id->slen] = '$';
+ pj_memcpy(set_key->ptr + call_id->slen + 1,
+ local_tag->ptr, local_tag->slen);
+}
+
+/*
+ * Acquire one dlg_set node to be put in the hash table.
+ * This will first look in the free nodes list, then allocate
+ * a new one from UA's pool when one is not available.
+ */
+static struct dlg_set *alloc_dlgset_node(void)
+{
+ struct dlg_set *set;
+
+ if (!pj_list_empty(&mod_ua.free_dlgset_nodes)) {
+ set = mod_ua.free_dlgset_nodes.next;
+ pj_list_erase(set);
+ return set;
+ } else {
+ set = pj_pool_alloc(mod_ua.pool, sizeof(struct dlg_set));
+ return set;
+ }
+}
+
+/*
+ * Register new dialog. Called by pjsip_dlg_create_uac() and
+ * pjsip_dlg_create_uas();
+ */
+PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
+ pjsip_dialog *dlg )
+{
+ /* Sanity check. */
+ PJ_ASSERT_RETURN(ua && dlg, PJ_EINVAL);
+
+ /* For all dialogs, local tag (inc hash) must has been initialized. */
+ PJ_ASSERT_RETURN(dlg->local.info && dlg->local.info->tag.slen &&
+ dlg->local.tag_hval != 0, PJ_EBUG);
+
+ /* For UAS dialog, remote tag (inc hash) must have been initialized. */
+ PJ_ASSERT_RETURN(dlg->role==PJSIP_ROLE_UAC ||
+ (dlg->role==PJSIP_ROLE_UAS && dlg->remote.info->tag.slen
+ && dlg->remote.tag_hval != 0), PJ_EBUG);
+
+ /* Lock the user agent. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* For UAC, check if there is existing dialog in the same set. */
+ if (dlg->role == PJSIP_ROLE_UAC) {
+ struct dlg_set *dlg_set;
+
+ dlg_set = pj_hash_get( mod_ua.dlg_table, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen,
+ &dlg->local.tag_hval);
+
+ if (dlg_set) {
+ /* This is NOT the first dialog in the dialog set.
+ * Just add this dialog in the list.
+ */
+ pj_assert(dlg_set->dlg_list.next != (void*)&dlg_set->dlg_list);
+ pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+ dlg->dlg_set = dlg_set;
+
+ } else {
+ /* This is the first dialog in the dialog set.
+ * Create the dialog set and add this dialog to it.
+ */
+ dlg_set = alloc_dlgset_node();
+ pj_list_init(&dlg_set->dlg_list);
+ pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+ dlg->dlg_set = dlg_set;
+
+ /* Register the dialog set in the hash table. */
+ pj_hash_set_np(mod_ua.dlg_table,
+ dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
+ dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+ }
+
+ } else {
+ /* For UAS, create the dialog set with a single dialog as member. */
+ struct dlg_set *dlg_set;
+
+ dlg_set = alloc_dlgset_node();
+ pj_list_init(&dlg_set->dlg_list);
+ pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+ dlg->dlg_set = dlg_set;
+
+ pj_hash_set_np(mod_ua.dlg_table,
+ dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
+ dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+ }
+
+ /* Unlock user agent. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ /* Done. */
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_ua_unregister_dlg( pjsip_user_agent *ua,
+ pjsip_dialog *dlg )
+{
+ struct dlg_set *dlg_set;
+ pjsip_dialog *d;
+
+ /* Sanity-check arguments. */
+ PJ_ASSERT_RETURN(ua && dlg, PJ_EINVAL);
+
+ /* Check that dialog has been registered. */
+ PJ_ASSERT_RETURN(dlg->dlg_set, PJ_EINVALIDOP);
+
+ /* Lock user agent. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* Find this dialog from the dialog set. */
+ dlg_set = dlg->dlg_set;
+ d = dlg_set->dlg_list.next;
+ while (d != (pjsip_dialog*)&dlg_set->dlg_list && d != dlg) {
+ d = d->next;
+ }
+
+ if (d != dlg) {
+ pj_assert(!"Dialog is not registered!");
+ pj_mutex_unlock(mod_ua.mutex);
+ return PJ_EINVALIDOP;
+ }
+
+ /* Remove this dialog from the list. */
+ pj_list_erase(dlg);
+
+ /* If dialog list is empty, remove the dialog set from the hash table. */
+ if (pj_list_empty(&dlg_set->dlg_list)) {
+ pj_hash_set(NULL, mod_ua.dlg_table, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen, dlg->local.tag_hval, NULL);
+
+ /* Return dlg_set to free nodes. */
+ pj_list_push_back(&mod_ua.free_dlgset_nodes, dlg_set);
+ }
+
+ /* Unlock user agent. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ /* Done. */
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pjsip_dialog*) pjsip_rdata_get_dlg( pjsip_rx_data *rdata )
+{
+ return rdata->endpt_info.mod_data[mod_ua.mod.id];
+}
+
+PJ_DEF(pjsip_dialog*) pjsip_tsx_get_dlg( pjsip_transaction *tsx )
+{
+ return tsx->mod_data[mod_ua.mod.id];
+}
+
+
+/*
+ * Find the first dialog in dialog set in hash table for an incoming message.
+ */
+static struct dlg_set *find_dlg_set_for_msg( pjsip_rx_data *rdata )
+{
+ /* CANCEL message doesn't have To tag, so we must lookup the dialog
+ * by finding the INVITE UAS transaction being cancelled.
+ */
+ if (rdata->msg_info.cseq->method.id == PJSIP_CANCEL_METHOD) {
+
+ pjsip_dialog *dlg;
+
+ /* Create key for the rdata, but this time, use INVITE as the
+ * method.
+ */
+ pj_str_t key;
+ pjsip_role_e role;
+ pjsip_transaction *tsx;
+
+ if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
+ role = PJSIP_ROLE_UAS;
+ else
+ role = PJSIP_ROLE_UAC;
+
+ pjsip_tsx_create_key(rdata->tp_info.pool, &key, role,
+ &pjsip_invite_method, rdata);
+
+ /* Lookup the INVITE transaction */
+ tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
+
+ /* We should find the dialog attached to the INVITE transaction */
+ if (tsx) {
+ dlg = tsx->mod_data[mod_ua.mod.id];
+ pj_mutex_unlock(tsx->mutex);
+
+ return dlg->dlg_set;
+
+ } else {
+ return NULL;
+ }
+
+
+ } else {
+ pj_str_t *tag;
+ struct dlg_set *dlg_set;
+
+ if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
+ tag = &rdata->msg_info.to->tag;
+ else
+ tag = &rdata->msg_info.from->tag;
+
+ /* Lookup the dialog set. */
+ dlg_set = pj_hash_get(mod_ua.dlg_table, tag->ptr, tag->slen, NULL);
+ return dlg_set;
+ }
+}
+
+/* On received requests. */
+static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
+{
+ struct dlg_set *dlg_set;
+ pj_str_t *from_tag;
+ pjsip_dialog *dlg;
+
+ /* Lock user agent before looking up the dialog hash table. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* Lookup the dialog set, based on the To tag header. */
+ dlg_set = find_dlg_set_for_msg(rdata);
+
+ /* Bail out if dialog is not found. */
+ if (dlg_set == NULL) {
+ /* Not ours. */
+ pj_mutex_unlock(mod_ua.mutex);
+ return PJ_FALSE;
+ }
+
+ /* Dialog set has been found.
+ * Find the dialog in the dialog set based on the content of the From tag.
+ */
+ from_tag = &rdata->msg_info.from->tag;
+ dlg = dlg_set->dlg_list.next;
+ while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
+
+ if (pj_strcmp(&dlg->remote.info->tag, from_tag) == 0)
+ break;
+
+ dlg = dlg->next;
+ }
+
+ /* Dialog MUST be found! */
+ if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+ /* Not found. Mulfunction UAC? */
+ pj_mutex_unlock(mod_ua.mutex);
+ pjsip_endpt_respond_stateless(mod_ua.endpt, rdata,
+ PJSIP_SC_CALL_TSX_DOES_NOT_EXIST,
+ NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ /* Mark the dialog id of the request. */
+ rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
+
+ /* Done processing in the UA */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ /* Pass to dialog. */
+ pjsip_dlg_on_rx_request(dlg, rdata);
+
+ /* Report as handled. */
+ return PJ_TRUE;
+}
+
+
+/* On rx response notification.
+ */
+static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
+{
+ pjsip_transaction *tsx;
+ struct dlg_set *dlg_set;
+ pjsip_dialog *dlg = NULL;
+
+ /*
+ * Find the dialog instance for the response.
+ * All outgoing dialog requests are sent statefully, which means
+ * there will be an UAC transaction associated with this response,
+ * and the dialog instance will be recorded in that transaction.
+ *
+ * But even when transaction is found, there is possibility that
+ * the response is a forked response.
+ */
+
+ /* Check if transaction is present. */
+ tsx = pjsip_rdata_get_tsx(rdata);
+ if (!tsx) {
+ /* Check if dialog is present in the transaction. */
+ dlg = pjsip_tsx_get_dlg(tsx);
+ if (!dlg)
+ return PJ_FALSE;
+
+ /* Get the dialog set. */
+ dlg_set = dlg->dlg_set;
+
+ /* Even if transaction is found and (candidate) dialog has been
+ * identified, it's possible that the request has forked.
+ */
+
+ } else {
+ /* Transaction is not present.
+ * Check if this is a 2xx/OK response to INVITE, which in this
+ * case the response will be handled directly by the
+ * dialog.
+ */
+ pjsip_cseq_hdr *cseq_hdr = rdata->msg_info.cseq;
+
+ if (cseq_hdr->method.id != PJSIP_INVITE_METHOD ||
+ rdata->msg_info.msg->line.status.code / 100 != 2)
+ {
+ /* Not a 2xx response to INVITE.
+ * This must be some stateless response sent by other modules,
+ * or a very late response.
+ */
+ return PJ_FALSE;
+ }
+
+ /* Lock user agent before accessing the hash table. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* Get the dialog set. */
+ dlg_set = pj_hash_get(mod_ua.dlg_table,
+ rdata->msg_info.from->tag.ptr,
+ rdata->msg_info.from->tag.slen,
+ NULL);
+
+ /* Done with accessing the hash table. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ if (!dlg_set) {
+ /* Strayed 2xx response!! */
+ PJ_LOG(4,(THIS_FILE,
+ "Received strayed 2xx response (no dialog is found)"
+ " from %s:%d: %s",
+ rdata->pkt_info.src_name, rdata->pkt_info.src_port,
+ pjsip_rx_data_get_info(rdata)));
+
+ return PJ_TRUE;
+ }
+ }
+
+ /* At this point, we must have the dialog set, and the dialog set
+ * must have a dialog in the list.
+ */
+ pj_assert(dlg_set && !pj_list_empty(&dlg_set->dlg_list));
+
+ /* Check for forked response.
+ * Request will fork only for the initial INVITE request.
+ */
+ if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
+ rdata->msg_info.cseq->cseq == dlg_set->dlg_list.next->local.first_cseq)
+ {
+ pj_str_t *to_tag = &rdata->msg_info.to->tag;
+
+ /* Must hold UA mutex before accessing dialog set. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ dlg = dlg_set->dlg_list.next;
+ while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
+
+ /* If there is dialog with no remote tag (i.e. dialog has not
+ * been established yet), then send this response to that
+ * dialog.
+ */
+ if (dlg->remote.info->tag.slen == 0)
+ break;
+
+ /* Otherwise find the one with matching To tag. */
+ if (pj_strcmp(to_tag, &dlg->remote.info->tag) == 0)
+ break;
+
+ dlg = dlg->next;
+ }
+
+ /* If no dialog with matching remote tag is found, this must be
+ * a forked response.
+ */
+ if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+ /* Report to application about forked condition.
+ * Application can either create a dialog or ignore the response.
+ */
+ if (mod_ua.param.on_dlg_forked)
+ dlg = (*mod_ua.param.on_dlg_forked)(dlg_set->dlg_list.next,
+ rdata);
+ else
+ dlg = NULL;
+
+ /* Ignore this response if application doesn't want to
+ * create a dialog.
+ */
+ if (dlg == NULL) {
+ pj_mutex_unlock(mod_ua.mutex);
+
+ PJ_LOG(4,(THIS_FILE,
+ "Unhandled forked %s from %s:%d",
+ pjsip_rx_data_get_info(rdata),
+ rdata->pkt_info.src_name, rdata->pkt_info.src_port));
+
+ return PJ_TRUE;
+ }
+ }
+
+ /* Done with the dialog set. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ } else {
+ /* Either this is a non-INVITE response, or subsequent INVITE
+ * within dialog. The dialog should have been identified when
+ * the transaction was found.
+ */
+ pj_assert(tsx != NULL);
+ pj_assert(dlg != NULL);
+ }
+
+ /* The dialog must have been found. */
+ pj_assert(dlg != NULL);
+
+ /* Put the dialog instance in the rdata. */
+ rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
+
+ /* Pass the response to the dialog. */
+ pjsip_dlg_on_rx_response(dlg, rdata);
+
+ /* Done. */
+ return PJ_TRUE;
+}
+
+
diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c
index 17994051..c408d0d9 100644
--- a/pjsip/src/pjsip/sip_uri.c
+++ b/pjsip/src/pjsip/sip_uri.c
@@ -140,15 +140,15 @@ static pj_str_t sips_str = { "sips", 4 };
static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
const pjsip_name_addr *rhs);
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
- const pjsip_name_addr *name,
- char *buf, pj_size_t size);
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+ const pjsip_name_addr *name,
+ char *buf, pj_size_t size);
static int pjsip_name_addr_compare( pjsip_uri_context_e context,
const pjsip_name_addr *naddr1,
const pjsip_name_addr *naddr2);
-static int pjsip_url_print( pjsip_uri_context_e context,
- const pjsip_sip_uri *url,
- char *buf, pj_size_t size);
+static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
+ const pjsip_sip_uri *url,
+ char *buf, pj_size_t size);
static int pjsip_url_compare( pjsip_uri_context_e context,
const pjsip_sip_uri *url1,
const pjsip_sip_uri *url2);
@@ -204,7 +204,7 @@ static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
return name->uri;
}
-PJ_DEF(void) pjsip_url_init(pjsip_sip_uri *url, int secure)
+PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, int secure)
{
pj_memset(url, 0, sizeof(*url));
url->ttl_param = -1;
@@ -213,16 +213,16 @@ PJ_DEF(void) pjsip_url_init(pjsip_sip_uri *url, int secure)
pj_list_init(&url->header_param);
}
-PJ_DEF(pjsip_sip_uri*) pjsip_url_create( pj_pool_t *pool, int secure )
+PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, int secure )
{
pjsip_sip_uri *url = pj_pool_alloc(pool, sizeof(pjsip_sip_uri));
- pjsip_url_init(url, secure);
+ pjsip_sip_uri_init(url, secure);
return url;
}
-static int pjsip_url_print( pjsip_uri_context_e context,
- const pjsip_sip_uri *url,
- char *buf, pj_size_t size)
+static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
+ const pjsip_sip_uri *url,
+ char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
@@ -465,8 +465,8 @@ static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
}
-PJ_DEF(void) pjsip_url_assign(pj_pool_t *pool, pjsip_sip_uri *url,
- const pjsip_sip_uri *rhs)
+PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
+ const pjsip_sip_uri *rhs)
{
pj_strdup( pool, &url->user, &rhs->user);
pj_strdup( pool, &url->passwd, &rhs->passwd);
@@ -488,8 +488,8 @@ static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool, const pjsip_sip_uri *rhs)
if (!url)
return NULL;
- pjsip_url_init(url, IS_SIPS(rhs));
- pjsip_url_assign(pool, url, rhs);
+ pjsip_sip_uri_init(url, IS_SIPS(rhs));
+ pjsip_sip_uri_assign(pool, url, rhs);
return url;
}
@@ -513,9 +513,9 @@ PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)
return name_addr;
}
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
- const pjsip_name_addr *name,
- char *buf, pj_size_t size)
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+ const pjsip_name_addr *name,
+ char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index f69ad9b3..af02e994 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -128,9 +128,9 @@ static void init_request_throw( pjsip_endpoint *endpt,
while (hparam != &uri->header_param) {
pjsip_generic_string_hdr *hdr;
- hdr = pjsip_generic_string_hdr_create_with_text(tdata->pool,
- &hparam->name,
- &hparam->value);
+ hdr = pjsip_generic_string_hdr_create(tdata->pool,
+ &hparam->name,
+ &hparam->value);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)hdr);
hparam = hparam->next;
}
@@ -302,9 +302,9 @@ pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
/* Duplicate target URI and headers. */
target = pjsip_uri_clone(tdata->pool, param_target);
from = pjsip_hdr_clone(tdata->pool, param_from);
- pjsip_fromto_set_from(from);
+ pjsip_fromto_hdr_set_from(from);
to = pjsip_hdr_clone(tdata->pool, param_to);
- pjsip_fromto_set_to(to);
+ pjsip_fromto_hdr_set_to(to);
if (param_contact)
contact = pjsip_hdr_clone(tdata->pool, param_contact);
else
diff --git a/pjsip/src/pjsip-ua/sip_ua_private.h b/pjsip/src/test-pjsip/dlg_core_test.c
index 8a174afe..348e3c3a 100644
--- a/pjsip/src/pjsip-ua/sip_ua_private.h
+++ b/pjsip/src/test-pjsip/dlg_core_test.c
@@ -16,21 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_UA_PRIVATE_H__
-#define __PJSIP_UA_PRIVATE_H__
-
-/*
- * Internal dialog functions.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg,
- pjsip_rx_data *rdata );
-
-
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-
-
-#endif /* __PJSIP_UA_PRIVATE_H__ */
+#include "test.h"
+#include <pjsip.h>
diff --git a/pjsip/src/test-pjsip/msg_logger.c b/pjsip/src/test-pjsip/msg_logger.c
index faa36b53..45a4cbaf 100644
--- a/pjsip/src/test-pjsip/msg_logger.c
+++ b/pjsip/src/test-pjsip/msg_logger.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "msg_logger.c"
@@ -64,8 +64,6 @@ static pjsip_module mod_msg_logger =
-1, /* Id */
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c
index 8fe879a3..f5debe84 100644
--- a/pjsip/src/test-pjsip/msg_test.c
+++ b/pjsip/src/test-pjsip/msg_test.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define POOL_SIZE 8000
@@ -348,7 +348,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "INVITE sip:user@foo SIP/2.0\n" */
pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
msg->line.req.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user");
pj_strdup2(pool, &url->host, "foo");
@@ -360,7 +360,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
fromto->uri = (pjsip_uri*)name_addr;
pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "joe.user");
pj_strdup2(pool, &url->host, "bar.otherdomain.com");
@@ -371,7 +371,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
fromto->uri = (pjsip_uri*)name_addr;
pj_strdup2(pool, &name_addr->display, "Fellow User");
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user");
pj_strdup2(pool, &url->host, "foo.bar.domain.com");
@@ -399,7 +399,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
contact->expires = 3600;
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "joe");
pj_strdup2(pool, &url->host, "bar");
@@ -410,7 +410,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
contact->q1000 = 500;
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user");
pj_strdup2(pool, &url->host, "host");
@@ -420,7 +420,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user2");
pj_strdup2(pool, &url->host, "host2");
@@ -435,7 +435,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */
routing = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
url->lr_param = 1;
@@ -443,7 +443,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* " <sip:server10.biloxi.com;lr>\r" */
routing = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "server10.biloxi.com");
url->lr_param = 1;
@@ -451,7 +451,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Record-Route: <sip:server10.biloxi.com>,\r\n" */
routing = pjsip_rr_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "server10.biloxi.com");
url->lr_param = 0;
@@ -459,7 +459,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* " <sip:bigbox3.site3.atlanta.com;lr>\n" */
routing = pjsip_rr_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
url->lr_param = 1;
@@ -497,7 +497,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Organization: \r" */
str.ptr = "Organization";
str.slen = 12;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
generic->hvalue.ptr = NULL;
generic->hvalue.slen = 0;
@@ -505,7 +505,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Max-Forwards: 70\n" */
str.ptr = "Max-Forwards";
str.slen = 12;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
str.ptr = "70";
str.slen = 2;
@@ -514,7 +514,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "X-Header: \r\n" */
str.ptr = "X-Header";
str.slen = 8;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
str.ptr = NULL;
str.slen = 0;
@@ -523,7 +523,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* P-Associated-URI:\r\n */
str.ptr = "P-Associated-URI";
str.slen = 16;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
str.ptr = NULL;
str.slen = 0;
@@ -538,7 +538,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
pjsip_route_hdr *route;
pjsip_name_addr *name_addr;
pjsip_sip_uri *url;
- pjsip_max_forwards_hdr *max_fwd;
+ pjsip_max_fwd_hdr *max_fwd;
pjsip_to_hdr *to;
pjsip_from_hdr *from;
pjsip_contact_hdr *contact;
@@ -581,22 +581,21 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
//"Route: <sip:proxy.sipprovider.com>\r\n"
route = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)route);
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
route->name_addr.uri = (pjsip_uri*)url;
url->host = pj_str("proxy.sipprovider.com");
//"Route: <sip:proxy.supersip.com:5060>\r\n"
route = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)route);
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
route->name_addr.uri = (pjsip_uri*)url;
url->host = pj_str("proxy.supersip.com");
url->port = 5060;
//"Max-Forwards: 70\r\n"
- max_fwd = pjsip_max_forwards_hdr_create(pool);
+ max_fwd = pjsip_max_fwd_hdr_create(pool, 70);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)max_fwd);
- max_fwd->ivalue = 70;
//"To: Bob <sip:bob@biloxi.com>;tag=a6c85cf\r\n"
to = pjsip_to_hdr_create(pool);
@@ -604,7 +603,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
name_addr->display = pj_str("Bob");
to->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
name_addr->uri = (pjsip_uri*)url;
url->user = pj_str("bob");
url->host = pj_str("biloxi.com");
@@ -616,7 +615,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
name_addr->display = pj_str("Alice");
from->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
name_addr->uri = (pjsip_uri*)url;
url->user = pj_str("alice");
url->host = pj_str("atlanta.com");
@@ -638,7 +637,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, PJ_TRUE);
+ url = pjsip_sip_uri_create(pool, PJ_TRUE);
name_addr->uri = (pjsip_uri*)url;
url->user = pj_str("bob");
url->host = pj_str("192.0.2.4");
diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c
index d634cc80..dd3453f8 100644
--- a/pjsip/src/test-pjsip/test.c
+++ b/pjsip/src/test-pjsip/test.c
@@ -20,7 +20,7 @@
#include "test.h"
#include <pjlib.h>
-#include <pjsip_core.h>
+#include <pjsip.h>
#define THIS_FILE "test.c"
diff --git a/pjsip/src/test-pjsip/transport_loop_test.c b/pjsip/src/test-pjsip/transport_loop_test.c
index f4e6bb3c..351fb7b6 100644
--- a/pjsip/src/test-pjsip/transport_loop_test.c
+++ b/pjsip/src/test-pjsip/transport_loop_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "transport_loop_test.c"
diff --git a/pjsip/src/test-pjsip/transport_test.c b/pjsip/src/test-pjsip/transport_test.c
index 74f6d796..df6f55eb 100644
--- a/pjsip/src/test-pjsip/transport_test.c
+++ b/pjsip/src/test-pjsip/transport_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "transport_test.c"
@@ -101,8 +101,6 @@ static pjsip_module my_module =
-1, /* Id */
PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
@@ -305,8 +303,6 @@ static pjsip_module rt_module =
-1, /* Id */
PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/transport_udp_test.c b/pjsip/src/test-pjsip/transport_udp_test.c
index ebc0557d..cf5f0ca5 100644
--- a/pjsip/src/test-pjsip/transport_udp_test.c
+++ b/pjsip/src/test-pjsip/transport_udp_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "transport_udp_test.c"
diff --git a/pjsip/src/test-pjsip/tsx_basic_test.c b/pjsip/src/test-pjsip/tsx_basic_test.c
index 1db86f8d..6be0ea2a 100644
--- a/pjsip/src/test-pjsip/tsx_basic_test.c
+++ b/pjsip/src/test-pjsip/tsx_basic_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "tsx_basic_test.c"
diff --git a/pjsip/src/test-pjsip/tsx_uac_test.c b/pjsip/src/test-pjsip/tsx_uac_test.c
index 2ec94e5a..c699bc54 100644
--- a/pjsip/src/test-pjsip/tsx_uac_test.c
+++ b/pjsip/src/test-pjsip/tsx_uac_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "tsx_uac_test.c"
@@ -103,8 +103,6 @@ static pjsip_module tsx_user =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
@@ -124,8 +122,6 @@ static pjsip_module msg_receiver =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/tsx_uas_test.c b/pjsip/src/test-pjsip/tsx_uas_test.c
index ecc174c4..ed8f8574 100644
--- a/pjsip/src/test-pjsip/tsx_uas_test.c
+++ b/pjsip/src/test-pjsip/tsx_uas_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "tsx_uas_test.c"
@@ -142,8 +142,6 @@ static pjsip_module tsx_user =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
@@ -163,8 +161,6 @@ static pjsip_module msg_sender =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/txdata_test.c b/pjsip/src/test-pjsip/txdata_test.c
index 327ea084..d39fad42 100644
--- a/pjsip/src/test-pjsip/txdata_test.c
+++ b/pjsip/src/test-pjsip/txdata_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL))
diff --git a/pjsip/src/test-pjsip/uri_test.c b/pjsip/src/test-pjsip/uri_test.c
index 28bdedd9..a221f4ca 100644
--- a/pjsip/src/test-pjsip/uri_test.c
+++ b/pjsip/src/test-pjsip/uri_test.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "uri_test.c"
@@ -317,7 +317,7 @@ struct uri_test
static pjsip_uri *create_uri0(pj_pool_t *pool)
{
/* "sip:localhost" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
return (pjsip_uri*)url;
@@ -326,7 +326,7 @@ static pjsip_uri *create_uri0(pj_pool_t *pool)
static pjsip_uri *create_uri1(pj_pool_t *pool)
{
/* "sip:user@localhost" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2( pool, &url->user, "user");
pj_strdup2( pool, &url->host, "localhost");
@@ -337,7 +337,7 @@ static pjsip_uri *create_uri1(pj_pool_t *pool)
static pjsip_uri *create_uri2(pj_pool_t *pool)
{
/* "sip:user:password@localhost:5060" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2( pool, &url->user, "user");
pj_strdup2( pool, &url->passwd, "password");
@@ -350,7 +350,7 @@ static pjsip_uri *create_uri2(pj_pool_t *pool)
static pjsip_uri *create_uri3(pj_pool_t *pool)
{
/* Like: "sip:localhost:5060", but without the port. */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
return (pjsip_uri*)url;
@@ -359,7 +359,7 @@ static pjsip_uri *create_uri3(pj_pool_t *pool)
static pjsip_uri *create_uri4(pj_pool_t *pool)
{
/* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
pj_strdup2(pool, &url->transport_param, "tcp");
@@ -386,7 +386,7 @@ static pjsip_uri *create_uri5(pj_pool_t *pool)
/* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
"?Subject=Hello%20There&Server=SIP%20Server"
*/
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
pj_strdup2(pool, &url->user_param, "phone");
@@ -405,7 +405,7 @@ static pjsip_uri *create_uri5(pj_pool_t *pool)
static pjsip_uri *create_uri6(pj_pool_t *pool)
{
/* "sips:localhost" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 1);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 1);
pj_strdup2(pool, &url->host, "localhost");
return (pjsip_uri*)url;
@@ -417,7 +417,7 @@ static pjsip_uri *create_uri7(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &url->host, "localhost");
@@ -430,7 +430,7 @@ static pjsip_uri *create_uri8(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 1);
+ url = pjsip_sip_uri_create(pool, 1);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Power Administrator");
@@ -444,7 +444,7 @@ static pjsip_uri *create_uri9(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "User");
@@ -460,7 +460,7 @@ static pjsip_uri *create_uri10(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Strange User\\\"\\\\\\\"");
@@ -474,7 +474,7 @@ static pjsip_uri *create_uri11(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Rogue User\\");
@@ -488,7 +488,7 @@ static pjsip_uri *create_uri12(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Strange User\"");
@@ -500,7 +500,7 @@ static pjsip_uri *create_uri13(pj_pool_t *pool)
{
/* "sip:localhost;pvalue=\"hello world\"" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
//pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");
param_add(url->other_param, "pvalue", "hello world");
@@ -513,7 +513,7 @@ static pjsip_uri *create_uri14(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me");
@@ -528,7 +528,7 @@ static pjsip_uri *create_uri15(pj_pool_t *pool)
{
/* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, ALPHANUM "-_.com");
return (pjsip_uri*)url;
}
@@ -537,7 +537,7 @@ static pjsip_uri *create_uri16(pj_pool_t *pool)
{
/* "sip:" USER_CHAR ":" PASS_CHAR "@host" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->user, USER_CHAR);
pj_strdup2(pool, &url->passwd, PASS_CHAR);
pj_strdup2(pool, &url->host, "host");
@@ -548,7 +548,7 @@ static pjsip_uri *create_uri17(pj_pool_t *pool)
{
/* "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21;lr;other=1;transport=sctp;other2" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "host");
pj_strdup2(pool, &url->user_param, "ip");
pj_strdup2(pool, &url->transport_param, "sctp");