Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Enumerations | Functions | Variables
res_pjsip_session.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjlib.h>
#include <pjmedia.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
#include "asterisk/res_pjsip_session_caps.h"
#include "asterisk/callerid.h"
#include "asterisk/datastore.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/astobj2.h"
#include "asterisk/lock.h"
#include "asterisk/uuid.h"
#include "asterisk/pbx.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/causes.h"
#include "asterisk/sdp_srtp.h"
#include "asterisk/dsp.h"
#include "asterisk/acl.h"
#include "asterisk/features_config.h"
#include "asterisk/pickup.h"
#include "asterisk/test.h"
#include "asterisk/stream.h"
#include "asterisk/vector.h"
Include dependency graph for res_pjsip_session.c:

Go to the source code of this file.

Data Structures

struct  ast_sip_session_delayed_request
 Structure used for sending delayed requests. More...
 
struct  ast_sip_session_suspender
 struct controlling the suspension of the session's serializer. More...
 
struct  new_invite
 
struct  sdp_handler_list
 
struct  sip_session_media_bundle_group
 Bundle group building structure. More...
 

Macros

#define CHECKER()
 
#define DATASTORE_BUCKETS   53
 
#define DEFAULT_NUM_SESSION_MEDIA   2
 
#define FREE_STATE()
 
#define GET_STREAM_NAME_SAFE(_stream)   (_stream ? ast_stream_get_name(_stream) : "")
 
#define GET_STREAM_SAFE(_topology, _i)   (_i < ast_stream_topology_get_count(_topology) ? ast_stream_topology_get_stream(_topology, _i) : NULL)
 
#define GET_STREAM_STATE_SAFE(_stream)   (_stream ? ast_stream_get_state(_stream) : AST_STREAM_STATE_END)
 
#define MEDIA_BUCKETS   7
 
#define MOD_DATA_NAT_HOOK   "nat_hook"
 
#define MOD_DATA_ON_RESPONSE   "on_response"
 
#define print_debug_details(inv, tsx, e)   __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e))
 
#define RESET_STATE(__num)
 
#define SDP_HANDLER_BUCKETS   11
 
#define STATE_NONE(_stream_state)   (_stream_state == AST_STREAM_STATE_END)
 
#define STATE_REMOVED(_stream_state)   (_stream_state == AST_STREAM_STATE_REMOVED)
 
#define STREAM_REMOVED(_stream)   (ast_stream_get_state(_stream) == AST_STREAM_STATE_REMOVED)
 

Enumerations

enum  delayed_method { DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, DELAYED_METHOD_BYE }
 
enum  sip_get_destination_result { SIP_GET_DEST_EXTEN_FOUND, SIP_GET_DEST_EXTEN_NOT_FOUND, SIP_GET_DEST_EXTEN_PARTIAL, SIP_GET_DEST_UNSUPPORTED_URI }
 

Functions

static void __print_debug_details (const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_bundle_groups (struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer)
 
static int add_sdp_streams (struct ast_sip_session_media *session_media, struct ast_sip_session *session, pjmedia_sdp_session *answer, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
struct ast_sip_channel_pvtast_sip_channel_pvt_alloc (void *pvt, struct ast_sip_session *session)
 Allocate a new SIP channel pvt structure. More...
 
struct ast_sip_sessionast_sip_dialog_get_session (pjsip_dialog *dlg)
 Retrieves a session from a dialog. More...
 
int ast_sip_session_add_datastore (struct ast_sip_session *session, struct ast_datastore *datastore)
 Add a datastore to a SIP session. More...
 
struct ast_sip_sessionast_sip_session_alloc (struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata)
 Allocate a new SIP session. More...
 
struct ast_datastoreast_sip_session_alloc_datastore (const struct ast_datastore_info *info, const char *uid)
 Alternative for ast_datastore_alloc() More...
 
int ast_sip_session_create_invite (struct ast_sip_session *session, pjsip_tx_data **tdata)
 Creates an INVITE request. More...
 
struct ast_sip_sessionast_sip_session_create_outgoing (struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, struct ast_stream_topology *req_topology)
 Create a new outgoing SIP session. More...
 
int ast_sip_session_defer_termination (struct ast_sip_session *session)
 Defer local termination of a session until remote side terminates, or an amount of time passes. More...
 
void ast_sip_session_defer_termination_cancel (struct ast_sip_session *session)
 Cancel a pending deferred termination. More...
 
void ast_sip_session_end_if_deferred (struct ast_sip_session *session)
 End the session if it had been previously deferred. More...
 
struct ast_datastoreast_sip_session_get_datastore (struct ast_sip_session *session, const char *name)
 Retrieve a session datastore. More...
 
const char * ast_sip_session_get_name (const struct ast_sip_session *session)
 Get the channel or endpoint name associated with the session. More...
 
int ast_sip_session_is_pending_stream_default (const struct ast_sip_session *session, const struct ast_stream *stream)
 Determines if a provided pending stream will be the default stream or not. More...
 
int ast_sip_session_media_add_read_callback (struct ast_sip_session *session, struct ast_sip_session_media *session_media, int fd, ast_sip_session_media_read_cb callback)
 Set a read callback for a media session with a specific file descriptor. More...
 
struct ast_sip_session_mediaast_sip_session_media_get_transport (struct ast_sip_session *session, struct ast_sip_session_media *session_media)
 Retrieve the underlying media session that is acting as transport for a media session. More...
 
int ast_sip_session_media_set_write_callback (struct ast_sip_session *session, struct ast_sip_session_media *session_media, ast_sip_session_media_write_cb callback)
 Set a write callback for a media session. More...
 
struct ast_sip_session_mediaast_sip_session_media_state_add (struct ast_sip_session *session, struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
 Allocate an ast_session_media and add it to the media state's vector. More...
 
struct ast_sip_session_media_stateast_sip_session_media_state_alloc (void)
 Allocate a session media state structure. More...
 
struct ast_sip_session_media_stateast_sip_session_media_state_clone (const struct ast_sip_session_media_state *media_state)
 Clone a media state. More...
 
void ast_sip_session_media_state_free (struct ast_sip_session_media_state *media_state)
 Free a session media state structure. More...
 
void ast_sip_session_media_state_reset (struct ast_sip_session_media_state *media_state)
 Reset a media state to a clean state. More...
 
void ast_sip_session_media_stats_save (struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
 Save a media stats. More...
 
int ast_sip_session_refresh (struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *media_state)
 Send a reinvite or UPDATE on a session. More...
 
int ast_sip_session_regenerate_answer (struct ast_sip_session *session, ast_sip_session_sdp_creation_cb on_sdp_creation)
 Regenerate SDP Answer. More...
 
int ast_sip_session_register_sdp_handler (struct ast_sip_session_sdp_handler *handler, const char *stream_type)
 Register an SDP handler. More...
 
void ast_sip_session_remove_datastore (struct ast_sip_session *session, const char *name)
 Remove a session datastore from the session. More...
 
void ast_sip_session_resume_reinvite (struct ast_sip_session *session)
 Resumes processing of a deferred incoming re-invite. More...
 
void ast_sip_session_send_request (struct ast_sip_session *session, pjsip_tx_data *tdata)
 Send a SIP request. More...
 
void ast_sip_session_send_request_with_cb (struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response)
 Send a SIP request and get called back when a response is received. More...
 
void ast_sip_session_send_response (struct ast_sip_session *session, pjsip_tx_data *tdata)
 Send a SIP response. More...
 
void ast_sip_session_suspend (struct ast_sip_session *session)
 Request and wait for the session serializer to be suspended. More...
 
void ast_sip_session_terminate (struct ast_sip_session *session, int response)
 Terminate a session and, if possible, send the provided response code. More...
 
void ast_sip_session_unregister_sdp_handler (struct ast_sip_session_sdp_handler *handler, const char *stream_type)
 Unregister an SDP handler. More...
 
void ast_sip_session_unsuspend (struct ast_sip_session *session)
 Request the session serializer be unsuspended. More...
 
 AST_TEST_DEFINE (test_resolve_refresh_media_states)
 
static int check_content_disposition (pjsip_rx_data *rdata)
 
static int check_content_disposition_in_multipart (pjsip_multipart_part *part)
 
static void check_delayed_requests (struct ast_sip_session *session, int(*cb)(void *vsession))
 
static int check_request_status (pjsip_inv_session *inv, pjsip_event *e)
 
static int check_sdp_content_type_supported (pjsip_media_type *content_type)
 
static struct pjmedia_sdp_session * create_local_sdp (pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
 
static int datastore_cmp (void *obj, void *arg, int flags)
 
static int datastore_hash (const void *obj, int flags)
 
static int delay_request (struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, enum delayed_method method, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queue_head)
 
static const char * delayed_method2str (enum delayed_method method)
 
static struct ast_sip_session_delayed_requestdelayed_request_alloc (enum delayed_method method, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state)
 
static void delayed_request_free (struct ast_sip_session_delayed_request *delay)
 
static pj_bool_t does_method_match (const pj_str_t *message_method, const char *supplement_method)
 
static pjmedia_sdp_session * generate_session_refresh_sdp (struct ast_sip_session *session)
 
static enum sip_get_destination_result get_destination (struct ast_sip_session *session, pjsip_rx_data *rdata)
 Determine where in the dialplan a call should go. More...
 
static int get_mid_bundle_group (const pjmedia_sdp_session *sdp, const char *mid)
 
static int handle_incoming (struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
 
static void handle_incoming_before_media (pjsip_inv_session *inv, struct ast_sip_session *session, pjsip_rx_data *rdata)
 
static void handle_incoming_request (struct ast_sip_session *session, pjsip_rx_data *rdata)
 
static void handle_incoming_response (struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
 
static int handle_incoming_sdp (struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
 
static int handle_negotiated_sdp (struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
 
static int handle_negotiated_sdp_session_media (struct ast_sip_session_media *session_media, struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
 
static void handle_new_invite_request (pjsip_rx_data *rdata)
 
static void handle_outgoing_request (struct ast_sip_session *session, pjsip_tx_data *tdata)
 
static void handle_outgoing_response (struct ast_sip_session *session, pjsip_tx_data *tdata)
 
static void handle_session_begin (struct ast_sip_session *session)
 
static void handle_session_destroy (struct ast_sip_session *session)
 
static void handle_session_end (struct ast_sip_session *session)
 
static pj_bool_t has_supplement (const struct ast_sip_session *session, const pjsip_rx_data *rdata)
 
static struct ast_sip_session_media_stateinternal_sip_session_media_state_alloc (size_t sessions, size_t read_callbacks)
 
static int invite_collision_timeout (void *vsession)
 
static int invite_proceeding (void *vsession)
 
static int invite_terminated (void *vsession)
 
static int is_media_state_valid (const char *session_name, struct ast_sip_session_media_state *state)
 
static int is_stream_limitation_reached (enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)
 
static int load_module (void)
 
static int media_stats_local_ssrc_cmp (const struct ast_rtp_instance_stats *vec_elem, const struct ast_rtp_instance_stats *srch)
 
static int new_invite (struct new_invite *invite)
 
static int new_invite_initial_answer (pjsip_inv_session *inv_session, pjsip_rx_data *rdata, int answer_code, int terminate_code, pj_bool_t notify)
 
static pj_bool_t outbound_invite_auth (pjsip_rx_data *rdata)
 
static pjsip_inv_session * pre_session_setup (pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
 
static int remove_handler (void *obj, void *arg, void *data, int flags)
 
static void remove_stream_from_bundle (struct ast_sip_session_media *session_media, struct ast_stream *stream)
 
static void reschedule_reinvite (struct ast_sip_session *session, ast_sip_session_response_cb on_response)
 
static void resend_reinvite (pj_timer_heap_t *timer, pj_timer_entry *entry)
 
static struct ast_sip_session_media_stateresolve_refresh_media_states (const char *session_name, struct ast_sip_session_media_state *delayed_pending_state, struct ast_sip_session_media_state *delayed_active_state, struct ast_sip_session_media_state *current_active_state, int run_post_validation)
 
static int sdp_handler_list_cmp (void *obj, void *arg, int flags)
 
static int sdp_handler_list_hash (const void *obj, int flags)
 
static int sdp_requires_deferral (struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
 Determine whether the SDP provided requires deferral of negotiating or not. More...
 
static int send_delayed_request (struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
 
static void session_datastore_destroy (void *obj)
 
static void session_destructor (void *obj)
 
static int session_end (void *vsession)
 
static int session_end_completion (void *vsession)
 
static int session_end_if_disconnected (int id, pjsip_inv_session *inv)
 
static void session_inv_on_create_offer (pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
 
static void session_inv_on_media_update (pjsip_inv_session *inv, pj_status_t status)
 
static void session_inv_on_new_session (pjsip_inv_session *inv, pjsip_event *e)
 
static pjsip_redirect_op session_inv_on_redirected (pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
 
static void session_inv_on_rx_offer (pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
 
static void session_inv_on_state_changed (pjsip_inv_session *inv, pjsip_event *e)
 
static void session_inv_on_tsx_state_changed (pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
 
static void session_media_dtor (void *obj)
 
static void session_media_set_handler (struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
 Set an SDP stream handler for a corresponding session media. More...
 
static pj_bool_t session_on_rx_request (pjsip_rx_data *rdata)
 Called when a new SIP request comes into PJSIP. More...
 
static pj_bool_t session_on_rx_response (pjsip_rx_data *rdata)
 
static void session_on_tsx_state (pjsip_transaction *tsx, pjsip_event *e)
 
static void session_outgoing_nat_hook (pjsip_tx_data *tdata, struct ast_sip_transport *transport)
 Hook for modifying outgoing messages with SDP to contain the proper address information. More...
 
static pj_bool_t session_reinvite_on_rx_request (pjsip_rx_data *rdata)
 
static void session_termination_cb (pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
 
static int session_termination_task (void *data)
 
static void set_from_header (struct ast_sip_session *session)
 
static int set_mid_and_bundle_group (struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
 
static void set_remote_mslabel_and_stream_group (struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream, struct ast_stream *asterisk_stream)
 
static int setup_outbound_invite_auth (pjsip_dialog *dlg)
 
static void sip_channel_destroy (void *obj)
 Destructor for SIP channel. More...
 
static void sip_session_defer_termination_stop_timer (struct ast_sip_session *session)
 
static int sip_session_refresh (struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queued)
 
static int sip_session_suspend_task (void *data)
 
static void sip_session_suspender_dtor (void *vdoomed)
 
static int stream_destroy (void *obj, void *arg, int flags)
 
static int test_is_media_session_equal (struct ast_sip_session_media *left, struct ast_sip_session_media *right)
 
static int test_is_media_state_equal (struct ast_sip_session_media_state *left, struct ast_sip_session_media_state *right, int assert_on_failure)
 
static struct ast_sip_session_mediatest_media_add (struct ast_sip_session_media_state *media_state, const char *name, enum ast_media_type type, enum ast_stream_state state, int position)
 
static struct ast_streamtest_stream_alloc (const char *name, enum ast_media_type type, enum ast_stream_state state)
 
static int unload_module (void)
 
static int update_completed (void *vsession)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Session resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static pjsip_inv_callback inv_callback
 
static struct ast_sip_nat_hooknat_hook
 NAT hook for modifying outgoing messages with SDP. More...
 
static pjsip_module outbound_invite_auth_module
 
static struct ao2_containersdp_handlers
 Registered SDP stream handlers. More...
 
static pjsip_module session_module
 
static pjsip_module session_reinvite_module
 

Macro Definition Documentation

◆ CHECKER

#define CHECKER ( )

Referenced by AST_TEST_DEFINE().

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Definition at line 1226 of file res_pjsip_session.c.

Referenced by ast_sip_session_alloc().

◆ DEFAULT_NUM_SESSION_MEDIA

#define DEFAULT_NUM_SESSION_MEDIA   2

Definition at line 61 of file res_pjsip_session.c.

Referenced by ast_sip_session_media_state_alloc().

◆ FREE_STATE

#define FREE_STATE ( )

◆ GET_STREAM_NAME_SAFE

#define GET_STREAM_NAME_SAFE (   _stream)    (_stream ? ast_stream_get_name(_stream) : "")

Definition at line 1739 of file res_pjsip_session.c.

Referenced by is_media_state_valid(), and resolve_refresh_media_states().

◆ GET_STREAM_SAFE

#define GET_STREAM_SAFE (   _topology,
  _i 
)    (_i < ast_stream_topology_get_count(_topology) ? ast_stream_topology_get_stream(_topology, _i) : NULL)

Definition at line 1737 of file res_pjsip_session.c.

Referenced by resolve_refresh_media_states().

◆ GET_STREAM_STATE_SAFE

#define GET_STREAM_STATE_SAFE (   _stream)    (_stream ? ast_stream_get_state(_stream) : AST_STREAM_STATE_END)

Definition at line 1738 of file res_pjsip_session.c.

Referenced by resolve_refresh_media_states().

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1227 of file res_pjsip_session.c.

◆ MOD_DATA_NAT_HOOK

#define MOD_DATA_NAT_HOOK   "nat_hook"

Definition at line 58 of file res_pjsip_session.c.

Referenced by session_outgoing_nat_hook().

◆ MOD_DATA_ON_RESPONSE

#define MOD_DATA_ON_RESPONSE   "on_response"

◆ print_debug_details

#define print_debug_details (   inv,
  tsx,
 
)    __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e))

◆ RESET_STATE

#define RESET_STATE (   __num)

Referenced by AST_TEST_DEFINE().

◆ SDP_HANDLER_BUCKETS

#define SDP_HANDLER_BUCKETS   11

Definition at line 55 of file res_pjsip_session.c.

Referenced by load_module().

◆ STATE_NONE

#define STATE_NONE (   _stream_state)    (_stream_state == AST_STREAM_STATE_END)

Definition at line 1736 of file res_pjsip_session.c.

Referenced by resolve_refresh_media_states().

◆ STATE_REMOVED

#define STATE_REMOVED (   _stream_state)    (_stream_state == AST_STREAM_STATE_REMOVED)

Definition at line 1735 of file res_pjsip_session.c.

Referenced by resolve_refresh_media_states().

◆ STREAM_REMOVED

#define STREAM_REMOVED (   _stream)    (ast_stream_get_state(_stream) == AST_STREAM_STATE_REMOVED)

Definition at line 1734 of file res_pjsip_session.c.

Referenced by is_media_state_valid(), and resolve_refresh_media_states().

Enumeration Type Documentation

◆ delayed_method

Enumerator
DELAYED_METHOD_INVITE 
DELAYED_METHOD_UPDATE 
DELAYED_METHOD_BYE 

Definition at line 1295 of file res_pjsip_session.c.

◆ sip_get_destination_result

Enumerator
SIP_GET_DEST_EXTEN_FOUND 

The extension was successfully found

SIP_GET_DEST_EXTEN_NOT_FOUND 

The extension specified in the RURI was not found

SIP_GET_DEST_EXTEN_PARTIAL 

The extension specified in the RURI was a partial match

SIP_GET_DEST_UNSUPPORTED_URI 

The RURI is of an unsupported scheme

Definition at line 3645 of file res_pjsip_session.c.

3645  {
3646  /*! The extension was successfully found */
3648  /*! The extension specified in the RURI was not found */
3650  /*! The extension specified in the RURI was a partial match */
3652  /*! The RURI is of an unsupported scheme */
3654 };

Function Documentation

◆ __print_debug_details()

static void __print_debug_details ( const char *  function,
pjsip_inv_session *  inv,
pjsip_transaction *  tsx,
pjsip_event *  e 
)
static

Definition at line 4347 of file res_pjsip_session.c.

References ast_channel_name(), ast_log, ast_sorcery_object_get_id(), ast_sip_session::channel, DEBUG_ATLEAST, ast_sip_session::endpoint, LOG_DEBUG, and NULL.

4348 {
4349  int id = session_module.id;
4350  struct ast_sip_session *session = NULL;
4351 
4352  if (!DEBUG_ATLEAST(5)) {
4353  /* Debug not spamy enough */
4354  return;
4355  }
4356 
4357  ast_log(LOG_DEBUG, "Function %s called on event %s\n",
4358  function, pjsip_event_str(e->type));
4359  if (!inv) {
4360  ast_log(LOG_DEBUG, "Transaction %p does not belong to an inv_session?\n", tsx);
4361  ast_log(LOG_DEBUG, "The transaction state is %s\n",
4362  pjsip_tsx_state_str(tsx->state));
4363  return;
4364  }
4365  if (id > -1) {
4366  session = inv->mod_data[session_module.id];
4367  }
4368  if (!session) {
4369  ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv);
4370  } else {
4371  ast_log(LOG_DEBUG, "The state change pertains to the endpoint '%s(%s)'\n",
4373  session->channel ? ast_channel_name(session->channel) : "");
4374  }
4375  if (inv->invite_tsx) {
4376  ast_log(LOG_DEBUG, "The inv session still has an invite_tsx (%p)\n",
4377  inv->invite_tsx);
4378  } else {
4379  ast_log(LOG_DEBUG, "The inv session does NOT have an invite_tsx\n");
4380  }
4381  if (tsx) {
4382  ast_log(LOG_DEBUG, "The %s %.*s transaction involved in this state change is %p\n",
4383  pjsip_role_name(tsx->role),
4384  (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4385  tsx);
4386  ast_log(LOG_DEBUG, "The current transaction state is %s\n",
4387  pjsip_tsx_state_str(tsx->state));
4388  ast_log(LOG_DEBUG, "The transaction state change event is %s\n",
4389  pjsip_event_str(e->body.tsx_state.type));
4390  } else {
4391  ast_log(LOG_DEBUG, "There is no transaction involved in this state change\n");
4392  }
4393  ast_log(LOG_DEBUG, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
4394 }
struct ast_sip_endpoint * endpoint
#define NULL
Definition: resample.c:96
#define LOG_DEBUG
Definition: logger.h:241
A structure describing a SIP session.
#define ast_log
Definition: astobj2.c:42
static struct ast_mansession session
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_channel * channel
static pjsip_module session_module
const char * ast_channel_name(const struct ast_channel *chan)
#define DEBUG_ATLEAST(level)
Definition: logger.h:441

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 6128 of file res_pjsip_session.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 6128 of file res_pjsip_session.c.

◆ add_bundle_groups()

static int add_bundle_groups ( struct ast_sip_session session,
pj_pool_t *  pool,
pjmedia_sdp_session *  answer 
)
static

Definition at line 5011 of file res_pjsip_session.c.

References ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), AST_VECTOR_GET, AST_VECTOR_SIZE, sip_session_media_bundle_group::attr_string, ast_sip_endpoint_media_configuration::bundle, ast_sip_session_media::bundle_group, ast_sip_session::endpoint, ast_sip_endpoint::media, ast_sip_session_media::mid, sip_session_media_bundle_group::mids, ast_sip_session::pending_media_state, and ast_sip_endpoint_media_configuration::webrtc.

Referenced by create_local_sdp().

5012 {
5013  pj_str_t stmp;
5014  pjmedia_sdp_attr *attr;
5015  struct sip_session_media_bundle_group bundle_groups[PJMEDIA_MAX_SDP_MEDIA];
5016  int index, mid_id;
5017  struct sip_session_media_bundle_group *bundle_group;
5018 
5019  if (session->endpoint->media.webrtc) {
5020  attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
5021  pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5022  }
5023 
5024  if (!session->endpoint->media.bundle) {
5025  return 0;
5026  }
5027 
5028  memset(bundle_groups, 0, sizeof(bundle_groups));
5029 
5030  /* Build the bundle group layout so we can then add it to the SDP */
5031  for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
5032  struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
5033 
5034  /* If this stream is not part of a bundle group we can't add it */
5035  if (session_media->bundle_group == -1) {
5036  continue;
5037  }
5038 
5039  bundle_group = &bundle_groups[session_media->bundle_group];
5040 
5041  /* If this is the first mid then we need to allocate the attribute string and place BUNDLE in front */
5042  if (!bundle_group->mids[0]) {
5043  bundle_group->mids[0] = session_media->mid;
5044  bundle_group->attr_string = ast_str_create(64);
5045  if (!bundle_group->attr_string) {
5046  continue;
5047  }
5048 
5049  ast_str_set(&bundle_group->attr_string, 0, "BUNDLE %s", session_media->mid);
5050  continue;
5051  }
5052 
5053  for (mid_id = 1; mid_id < PJMEDIA_MAX_SDP_MEDIA; ++mid_id) {
5054  if (!bundle_group->mids[mid_id]) {
5055  bundle_group->mids[mid_id] = session_media->mid;
5056  ast_str_append(&bundle_group->attr_string, 0, " %s", session_media->mid);
5057  break;
5058  } else if (!strcmp(bundle_group->mids[mid_id], session_media->mid)) {
5059  break;
5060  }
5061  }
5062  }
5063 
5064  /* Add all bundle groups that have mids to the SDP */
5065  for (index = 0; index < PJMEDIA_MAX_SDP_MEDIA; ++index) {
5066  bundle_group = &bundle_groups[index];
5067 
5068  if (!bundle_group->attr_string) {
5069  continue;
5070  }
5071 
5072  attr = pjmedia_sdp_attr_create(pool, "group", pj_cstr(&stmp, ast_str_buffer(bundle_group->attr_string)));
5073  pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5074 
5075  ast_free(bundle_group->attr_string);
5076  }
5077 
5078  return 0;
5079 }
struct ast_sip_endpoint * endpoint
Bundle group building structure.
struct ast_sip_session_media_state * pending_media_state
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
char * mid
Media identifier for this stream (may be shared across multiple streams)
static pj_pool_t * pool
Global memory pool for configuration and timers.
struct ast_str * attr_string
SDP attribute string.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
static int answer(void *data)
Definition: chan_pjsip.c:682
char * mids[PJMEDIA_MAX_SDP_MEDIA]
The media identifiers in this bundle group.
#define ast_free(a)
Definition: astmm.h:182
int bundle_group
The bundle group the stream belongs to.
A structure containing SIP session media information.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ add_sdp_streams()

static int add_sdp_streams ( struct ast_sip_session_media session_media,
struct ast_sip_session session,
pjmedia_sdp_session *  answer,
const struct pjmedia_sdp_session *  remote,
struct ast_stream stream 
)
static

Definition at line 4957 of file res_pjsip_session.c.

References ao2_cleanup, ao2_find, ast_codec_media_type2str(), AST_LIST_TRAVERSE, ast_sip_session_get_name(), ast_str_tmp, ast_stream_to_str(), ast_sip_session_sdp_handler::create_outgoing_sdp_stream, handler(), ast_sip_session_media::handler, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session_media_set_handler(), and ast_sip_session_media::type.

Referenced by create_local_sdp().

4961 {
4962  struct ast_sip_session_sdp_handler *handler = session_media->handler;
4963  RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
4964  int res = 0;
4965  SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
4966  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
4967 
4968  if (handler) {
4969  /* if an already assigned handler reports a catastrophic error, fail */
4970  res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
4971  if (res < 0) {
4972  SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
4973  }
4974  SCOPE_EXIT_RTN_VALUE(0, "Had handler\n");
4975  }
4976 
4977  handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY);
4978  if (!handler_list) {
4979  SCOPE_EXIT_RTN_VALUE(0, "No handlers\n");
4980  }
4981 
4982  /* no handler for this stream type and we have a list to search */
4983  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
4984  if (handler == session_media->handler) {
4985  continue;
4986  }
4987  res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
4988  if (res < 0) {
4989  /* catastrophic error */
4990  SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
4991  }
4992  if (res > 0) {
4993  /* Handled by this handler. Move to the next stream */
4994  session_media_set_handler(session_media, handler);
4995  SCOPE_EXIT_RTN_VALUE(0, "Handled\n");
4996  }
4997  }
4998 
4999  /* streams that weren't handled won't be included in generated outbound SDP */
5000  SCOPE_EXIT_RTN_VALUE(0, "Not handled\n");
5001 }
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition: stream.c:337
#define OBJ_KEY
Definition: astobj2.h:1155
A handler for SDPs in SIP sessions.
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
#define NULL
Definition: resample.c:96
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
struct ast_sip_session_sdp_handler * next
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static void session_media_set_handler(struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
Set an SDP stream handler for a corresponding session media.
static int answer(void *data)
Definition: chan_pjsip.c:682
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
enum ast_media_type type
Media type of this session media.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
int(* create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
Create an SDP media stream and add it to the outgoing SDP offer or answer.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 6128 of file res_pjsip_session.c.

◆ ast_sip_channel_pvt_alloc()

struct ast_sip_channel_pvt* ast_sip_channel_pvt_alloc ( void *  pvt,
struct ast_sip_session session 
)

Allocate a new SIP channel pvt structure.

Parameters
pvtPointer to channel specific information
sessionPointer to SIP session
Return values
non-NULLsuccess
NULLfailure

Definition at line 2974 of file res_pjsip_session.c.

References ao2_alloc, ao2_ref, NULL, ast_sip_channel_pvt::pvt, session, ast_sip_channel_pvt::session, and sip_channel_destroy().

Referenced by chan_pjsip_new().

2975 {
2976  struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
2977 
2978  if (!channel) {
2979  return NULL;
2980  }
2981 
2982  ao2_ref(pvt, +1);
2983  channel->pvt = pvt;
2984  ao2_ref(session, +1);
2985  channel->session = session;
2986 
2987  return channel;
2988 }
void * pvt
Pointer to channel specific implementation information, must be ao2 object.
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Definition: muted.c:95
#define NULL
Definition: resample.c:96
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void sip_channel_destroy(void *obj)
Destructor for SIP channel.

◆ ast_sip_dialog_get_session()

struct ast_sip_session* ast_sip_dialog_get_session ( pjsip_dialog *  dlg)

Retrieves a session from a dialog.

Parameters
dlgThe dialog to retrieve the session from
Return values
non-NULLif session exists
NULLif no session
Note
The reference count of the session is increased when returned
This function must be called with the dialog locked

Definition at line 3630 of file res_pjsip_session.c.

References ao2_ref, ast_sip_session::inv_session, NULL, and session.

Referenced by assign_uuid(), refer_incoming_attended_request(), refer_incoming_invite_request(), session_outgoing_nat_hook(), and session_reinvite_on_rx_request().

3631 {
3632  pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3633  struct ast_sip_session *session;
3634 
3635  if (!inv_session ||
3636  !(session = inv_session->mod_data[session_module.id])) {
3637  return NULL;
3638  }
3639 
3640  ao2_ref(session, +1);
3641 
3642  return session;
3643 }
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static pjsip_module session_module

◆ ast_sip_session_add_datastore()

int ast_sip_session_add_datastore ( struct ast_sip_session session,
struct ast_datastore datastore 
)

Add a datastore to a SIP session.

Note that SIP uses reference counted datastores. The datastore passed into this function must have been allocated using ao2_alloc() or there will be serious problems.

Parameters
sessionThe session to add the datastore to
datastoreThe datastore to be added to the session
Return values
0Success
-1Failure

Definition at line 1273 of file res_pjsip_session.c.

References ao2_link, ast_assert, ast_strlen_zero, ast_sip_session::datastores, ast_datastore::info, NULL, and ast_datastore::uid.

Referenced by add_header(), chan_pjsip_incoming_request(), chan_pjsip_session_begin(), handle_incoming_request(), incoming_request(), session_refresh_state_get_or_alloc(), and t38_state_get_or_alloc().

1274 {
1275  ast_assert(datastore != NULL);
1276  ast_assert(datastore->info != NULL);
1277  ast_assert(ast_strlen_zero(datastore->uid) == 0);
1278 
1279  if (!ao2_link(session->datastores, datastore)) {
1280  return -1;
1281  }
1282  return 0;
1283 }
struct ao2_container * datastores
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
const char * uid
Definition: datastore.h:69
#define ast_strlen_zero(foo)
Definition: strings.h:52
const struct ast_datastore_info * info
Definition: datastore.h:71
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ ast_sip_session_alloc()

struct ast_sip_session* ast_sip_session_alloc ( struct ast_sip_endpoint endpoint,
struct ast_sip_contact contact,
pjsip_inv_session *  inv,
pjsip_rx_data *  rdata 
)

Allocate a new SIP session.

This will take care of allocating the datastores container on the session as well as placing all registered supplements onto the session.

The endpoint that is passed in will have its reference count increased by one since the session will be keeping a reference to the endpoint. The session will relinquish this reference when the session is destroyed.

Parameters
endpointThe endpoint that this session communicates with
contactThe contact associated with this session
inv_sessionThe PJSIP INVITE session data
rdataINVITE request received (NULL if for outgoing allocation)

Definition at line 2990 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_bump, ao2_cleanup, ao2_container_alloc_hash, ao2_ref, ast_dsp_new(), ast_dsp_set_features(), ast_format_cap_alloc, AST_FORMAT_CAP_FLAG_DEFAULT, AST_LIST_HEAD_INIT, AST_LIST_HEAD_INIT_NOLOCK, ast_log, ast_party_id_init(), ast_sip_create_serializer(), ast_sip_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), AST_SIP_DTMF_AUTO, AST_SIP_DTMF_INBAND, ast_sip_get_distributor_serializer(), ast_sip_session_add_supplements(), ast_sip_session_media_state_alloc(), ast_sorcery_object_get_id(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, AST_VECTOR_INIT, ast_sip_session::authentication_challenge_count, ast_sip_session::contact, DATASTORE_BUCKETS, datastore_cmp(), datastore_hash(), ast_sip_session::datastores, ast_sip_session::delayed_requests, ast_sip_session::direct_media_cap, ast_sip_session::dsp, DSP_FEATURE_DIGIT_DETECT, DSP_FEATURE_FAX_DETECT, ast_sip_session::dtmf, ast_sip_endpoint::dtmf, ast_sip_session::endpoint, ast_sip_endpoint::faxdetect, handle_session_begin(), ast_sip_session::id, ast_sip_session::inv_session, LOG_ERROR, ast_sip_session::moh_passthrough, ast_sip_endpoint::moh_passthrough, NULL, ast_sip_session::pending_media_state, RAII_VAR, ast_sip_session::serializer, session, session_destructor(), and ast_sip_session::supplements.

Referenced by ast_sip_session_create_outgoing(), and handle_new_invite_request().

2992 {
2994  struct ast_sip_session *ret_session;
2995  int dsp_features = 0;
2996 
2998  if (!session) {
2999  return NULL;
3000  }
3001 
3002  AST_LIST_HEAD_INIT(&session->supplements);
3003  AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
3004  ast_party_id_init(&session->id);
3005 
3007  if (!session->direct_media_cap) {
3008  return NULL;
3009  }
3012  if (!session->datastores) {
3013  return NULL;
3014  }
3015  session->active_media_state = ast_sip_session_media_state_alloc();
3016  if (!session->active_media_state) {
3017  return NULL;
3018  }
3019  session->pending_media_state = ast_sip_session_media_state_alloc();
3020  if (!session->pending_media_state) {
3021  return NULL;
3022  }
3023  if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
3024  return NULL;
3025  }
3026 
3027  if (endpoint->dtmf == AST_SIP_DTMF_INBAND || endpoint->dtmf == AST_SIP_DTMF_AUTO) {
3028  dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3029  }
3030  if (endpoint->faxdetect) {
3031  dsp_features |= DSP_FEATURE_FAX_DETECT;
3032  }
3033  if (dsp_features) {
3034  session->dsp = ast_dsp_new();
3035  if (!session->dsp) {
3036  return NULL;
3037  }
3038 
3039  ast_dsp_set_features(session->dsp, dsp_features);
3040  }
3041 
3042  session->endpoint = ao2_bump(endpoint);
3043 
3044  if (rdata) {
3045  /*
3046  * We must continue using the serializer that the original
3047  * INVITE came in on for the dialog. There may be
3048  * retransmissions already enqueued in the original
3049  * serializer that can result in reentrancy and message
3050  * sequencing problems.
3051  */
3052  session->serializer = ast_sip_get_distributor_serializer(rdata);
3053  } else {
3054  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
3055 
3056  /* Create name with seq number appended. */
3057  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outsess/%s",
3058  ast_sorcery_object_get_id(endpoint));
3059 
3060  session->serializer = ast_sip_create_serializer(tps_name);
3061  }
3062  if (!session->serializer) {
3063  return NULL;
3064  }
3066  ast_sip_dialog_set_endpoint(inv_session->dlg, endpoint);
3067 
3068  /* When a PJSIP INVITE session is created it is created with a reference
3069  * count of 1, with that reference being managed by the underlying state
3070  * of the INVITE session itself. When the INVITE session transitions to
3071  * a DISCONNECTED state that reference is released. This means we can not
3072  * rely on that reference to ensure the INVITE session remains for the
3073  * lifetime of our session. To ensure it does we add our own reference
3074  * and release it when our own session goes away, ensuring that the INVITE
3075  * session remains for the lifetime of session.
3076  */
3077 
3078 #ifdef HAVE_PJSIP_INV_SESSION_REF
3079  if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
3080  ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3081  return NULL;
3082  }
3083 #endif
3084 
3085  pjsip_dlg_inc_session(inv_session->dlg, &session_module);
3086  inv_session->mod_data[session_module.id] = ao2_bump(session);
3087  session->contact = ao2_bump(contact);
3088  session->inv_session = inv_session;
3089 
3090  session->dtmf = endpoint->dtmf;
3091  session->moh_passthrough = endpoint->moh_passthrough;
3092 
3094  /* Release the ref held by session->inv_session */
3095  ao2_ref(session, -1);
3096  return NULL;
3097  }
3098 
3099  session->authentication_challenge_count = 0;
3100 
3101  /* Fire seesion begin handlers */
3103 
3104  /* Avoid unnecessary ref manipulation to return a session */
3105  ret_session = session;
3106  session = NULL;
3107  return ret_session;
3108 }
enum ast_sip_dtmf_mode dtmf
Definition: res_pjsip.h:857
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1745
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
#define NULL
Definition: resample.c:96
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:60
struct pjsip_inv_session * inv_session
A structure describing a SIP session.
#define DATASTORE_BUCKETS
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_log
Definition: astobj2.c:42
static void session_destructor(void *obj)
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define DSP_FEATURE_FAX_DETECT
Definition: dsp.h:29
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static pjsip_module session_module
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
static int datastore_hash(const void *obj, int flags)
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int datastore_cmp(void *obj, void *arg, int flags)
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:5133
unsigned int faxdetect
Definition: res_pjsip.h:869
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1755
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
unsigned int moh_passthrough
Definition: res_pjsip.h:879
static void handle_session_begin(struct ast_sip_session *session)
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
Definition: channel.c:1757
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_sip_session_add_supplements(struct ast_sip_session *session)
Add supplements to a SIP session.
Definition: pjsip_session.c:90
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.

◆ ast_sip_session_alloc_datastore()

struct ast_datastore* ast_sip_session_alloc_datastore ( const struct ast_datastore_info info,
const char *  uid 
)

Alternative for ast_datastore_alloc()

There are two major differences between this and ast_datastore_alloc() 1) This allocates a refcounted object 2) This will fill in a uid if one is not provided

DO NOT call ast_datastore_free() on a datastore allocated in this way since that function will attempt to free the datastore rather than play nicely with its refcount.

Parameters
infoCallbacks for datastore
uidIdentifier for datastore
Return values
NULLFailed to allocate datastore
non-NULLNewly allocated datastore

Definition at line 1243 of file res_pjsip_session.c.

References ao2_alloc, ao2_cleanup, ao2_ref, ast_strdup, ast_strlen_zero, ast_uuid_generate_str(), AST_UUID_STR_LEN, sip_to_pjsip::info(), NULL, RAII_VAR, session_datastore_destroy(), and ast_datastore::uid.

Referenced by add_header(), chan_pjsip_incoming_request(), chan_pjsip_session_begin(), handle_incoming_request(), incoming_request(), session_refresh_state_get_or_alloc(), and t38_state_get_or_alloc().

1244 {
1245  RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
1246  char uuid_buf[AST_UUID_STR_LEN];
1247  const char *uid_ptr = uid;
1248 
1249  if (!info) {
1250  return NULL;
1251  }
1252 
1253  datastore = ao2_alloc(sizeof(*datastore), session_datastore_destroy);
1254  if (!datastore) {
1255  return NULL;
1256  }
1257 
1258  datastore->info = info;
1259  if (ast_strlen_zero(uid)) {
1260  /* They didn't provide an ID so we'll provide one ourself */
1261  uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
1262  }
1263 
1264  datastore->uid = ast_strdup(uid_ptr);
1265  if (!datastore->uid) {
1266  return NULL;
1267  }
1268 
1269  ao2_ref(datastore, +1);
1270  return datastore;
1271 }
#define AST_UUID_STR_LEN
Definition: uuid.h:27
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
#define NULL
Definition: resample.c:96
static void session_datastore_destroy(void *obj)
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ao2_ref(o, delta)
Definition: astobj2.h:464
def info(msg)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:143
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ ast_sip_session_create_invite()

int ast_sip_session_create_invite ( struct ast_sip_session session,
pjsip_tx_data **  tdata 
)

Creates an INVITE request.

Parameters
sessionStarting session for the INVITE
tdataThe created request.

Definition at line 2847 of file res_pjsip_session.c.

References ast_sip_session_get_name(), create_local_sdp(), ast_sip_session::endpoint, ast_sip_session::inv_session, NULL, ast_sip_endpoint::preferred_codec_only, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and set_from_header().

Referenced by call().

2848 {
2849  pjmedia_sdp_session *offer;
2850  SCOPE_ENTER(1, "%s\n", ast_sip_session_get_name(session));
2851 
2852  if (!(offer = create_local_sdp(session->inv_session, session, NULL))) {
2853  pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
2854  SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create offer\n");
2855  }
2856 
2857  pjsip_inv_set_local_sdp(session->inv_session, offer);
2858  pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
2859 #ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
2860  if (!session->endpoint->preferred_codec_only) {
2861  pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
2862  }
2863 #endif
2864 
2865  /*
2866  * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the
2867  * From in the initial INVITE will be wrong but the rest of the messages will be OK.
2868  */
2869  set_from_header(session);
2870 
2871  if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
2872  SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
2873  }
2874 
2876 }
struct ast_sip_endpoint * endpoint
static void set_from_header(struct ast_sip_session *session)
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
unsigned int preferred_codec_only
Definition: res_pjsip.h:889
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)

◆ ast_sip_session_create_outgoing()

struct ast_sip_session* ast_sip_session_create_outgoing ( struct ast_sip_endpoint endpoint,
struct ast_sip_contact contact,
const char *  location,
const char *  request_user,
struct ast_stream_topology req_topology 
)

Create a new outgoing SIP session.

The endpoint that is passed in will have its reference count increased by one since the session will be keeping a reference to the endpoint. The session will relinquish this reference when the session is destroyed.

Parameters
endpointThe endpoint that this session uses for settings
contactThe contact that this session will communicate with
locationName of the location to call, be it named location or explicit URI. Overrides contact if present.
request_userOptional request user to place in the request URI if permitted
req_topologyThe requested capabilities

Definition at line 3317 of file res_pjsip_session.c.

References ao2_bump, ao2_cleanup, ao2_ref, ast_sip_session::aor, ast_sip_endpoint::aors, ast_log, ast_party_id_copy(), AST_SIP_CONTACT_FILTER_REACHABLE, ast_sip_create_dialog_uac(), ast_sip_location_retrieve_contact_and_aor_from_list_filtered(), ast_sip_session_alloc(), ast_sip_session_create_joint_call_stream(), AST_SIP_SESSION_OUTGOING_CALL, ast_sorcery_object_get_id(), ast_str_tmp, ast_stream_free(), ast_stream_get_format_count(), ast_stream_get_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_alloc(), ast_stream_topology_append_stream(), ast_stream_topology_clone(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_to_str(), ast_strlen_zero, ast_sip_session::call_direction, ast_sip_endpoint::extensions, ast_sip_endpoint_extensions::flags, ast_sip_session::id, ast_sip_endpoint::id, LOG_ERROR, ast_sip_endpoint::media, ast_sip_timer_options::min_se, NULL, ast_sip_session::pending_media_state, RAII_VAR, S_OR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, ast_sip_endpoint_id_configuration::self, ast_sip_timer_options::sess_expires, session, session_end(), session_end_completion(), setup_outbound_invite_auth(), timer, ast_sip_endpoint_extensions::timer, ast_sip_session_media_state::topology, ast_sip_endpoint_media_configuration::topology, and ast_sip_contact::uri.

Referenced by request().

3320 {
3321  const char *uri = NULL;
3322  RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup);
3323  RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
3324  pjsip_timer_setting timer;
3325  pjsip_dialog *dlg;
3326  struct pjsip_inv_session *inv_session;
3328  struct ast_sip_session *ret_session;
3329  SCOPE_ENTER(1, "%s %s Topology: %s\n", ast_sorcery_object_get_id(endpoint), request_user,
3330  ast_str_tmp(256, ast_stream_topology_to_str(req_topology, &STR_TMP)));
3331 
3332  /* If no location has been provided use the AOR list from the endpoint itself */
3333  if (location || !contact) {
3334  location = S_OR(location, endpoint->aors);
3335 
3337  &found_aor, &found_contact);
3338  if (!found_contact || ast_strlen_zero(found_contact->uri)) {
3339  uri = location;
3340  } else {
3341  uri = found_contact->uri;
3342  }
3343  } else {
3344  uri = contact->uri;
3345  }
3346 
3347  /* If we still have no URI to dial fail to create the session */
3348  if (ast_strlen_zero(uri)) {
3349  ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
3350  ast_sorcery_object_get_id(endpoint));
3351  SCOPE_EXIT_RTN_VALUE(NULL, "No URI\n");
3352  }
3353 
3354  if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
3355  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create dialog\n");
3356  }
3357 
3358  if (setup_outbound_invite_auth(dlg)) {
3359  pjsip_dlg_terminate(dlg);
3360  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't setup auth\n");
3361  }
3362 
3363  if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
3364  pjsip_dlg_terminate(dlg);
3365  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create uac\n");
3366  }
3367 #if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3368  inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3369 #endif
3370 
3371  pjsip_timer_setting_default(&timer);
3372  timer.min_se = endpoint->extensions.timer.min_se;
3373  timer.sess_expires = endpoint->extensions.timer.sess_expires;
3374  pjsip_timer_init_session(inv_session, &timer);
3375 
3376  session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact,
3377  inv_session, NULL);
3378  if (!session) {
3379  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3380  return NULL;
3381  }
3382  session->aor = ao2_bump(found_aor);
3383  session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;
3384 
3385  ast_party_id_copy(&session->id, &endpoint->id.self);
3386 
3387  if (ast_stream_topology_get_count(req_topology) > 0) {
3388  /* get joint caps between req_topology and endpoint topology */
3389  int i;
3390 
3391  for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {
3392  struct ast_stream *req_stream;
3393  struct ast_stream *clone_stream;
3394 
3395  req_stream = ast_stream_topology_get_stream(req_topology, i);
3396 
3397  if (ast_stream_get_state(req_stream) == AST_STREAM_STATE_REMOVED) {
3398  continue;
3399  }
3400 
3401  clone_stream = ast_sip_session_create_joint_call_stream(session, req_stream);
3402  if (!clone_stream || ast_stream_get_format_count(clone_stream) == 0) {
3403  ast_stream_free(clone_stream);
3404  continue;
3405  }
3406 
3407  if (!session->pending_media_state->topology) {
3408  session->pending_media_state->topology = ast_stream_topology_alloc();
3409  if (!session->pending_media_state->topology) {
3410  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3411  ao2_ref(session, -1);
3412  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create topology\n");
3413  }
3414  }
3415 
3416  if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) {
3417  ast_stream_free(clone_stream);
3418  continue;
3419  }
3420  }
3421  }
3422 
3423  if (!session->pending_media_state->topology) {
3424  /* Use the configured topology on the endpoint as the pending one */
3425  session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology);
3426  if (!session->pending_media_state->topology) {
3427  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3428  ao2_ref(session, -1);
3429  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't clone topology\n");
3430  }
3431  }
3432 
3433  if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3434  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3435  /* Since we are not notifying ourselves that the INVITE session is being terminated
3436  * we need to manually drop its reference to session
3437  */
3438  ao2_ref(session, -1);
3439  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't add usage\n");
3440  }
3441 
3442  /* Avoid unnecessary ref manipulation to return a session */
3443  ret_session = session;
3444  session = NULL;
3445  SCOPE_EXIT_RTN_VALUE(ret_session);
3446 }
struct ast_sip_session * ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata)
Allocate a new SIP session.
unsigned int sess_expires
Definition: res_pjsip.h:567
A SIP address of record.
Definition: res_pjsip.h:361
static int setup_outbound_invite_auth(pjsip_dialog *dlg)
void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
Copy the source party id information to the destination party id.
Definition: channel.c:1765
Set when the stream has been removed/declined.
Definition: stream.h:78
int ast_stream_get_format_count(const struct ast_stream *stream)
Get the count of the current negotiated formats of a stream.
Definition: stream.c:358
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
A structure describing a SIP session.
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
#define ao2_bump(obj)
Definition: astobj2.h:491
unsigned int min_se
Definition: res_pjsip.h:565
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
#define ast_log
Definition: astobj2.c:42
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static pjsip_module session_module
void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags, struct ast_sip_aor **aor, struct ast_sip_contact **contact)
Retrieve the first bound contact AND the AOR chosen from a list of AORs and filter based on flags...
Definition: location.c:272
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:847
#define LOG_ERROR
Definition: logger.h:285
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct ast_sip_timer_options timer
Definition: res_pjsip.h:580
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
struct ast_stream_topology * topology
Definition: res_pjsip.h:772
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_party_id self
Definition: res_pjsip.h:629
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
struct ast_sip_endpoint_extensions extensions
Definition: res_pjsip.h:839
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
Definition: res_pjsip.c:4028
Return only reachable or unknown contacts.
Definition: res_pjsip.h:1009
const ast_string_field aors
Definition: res_pjsip.h:821
const ast_string_field uri
Definition: res_pjsip.h:303
static struct ast_timer * timer
Definition: chan_iax2.c:360
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
struct ast_stream * ast_sip_session_create_joint_call_stream(const struct ast_sip_session *session, struct ast_stream *remote)
Create a new stream of joint capabilities.

◆ ast_sip_session_defer_termination()

int ast_sip_session_defer_termination ( struct ast_sip_session session)

Defer local termination of a session until remote side terminates, or an amount of time passes.

Parameters
sessionThe session to defer termination on
Return values
0Success
-1Failure

Definition at line 3554 of file res_pjsip_session.c.

References ao2_ref, ast_assert, ast_sip_get_pjsip_endpoint(), ast_sip_session::defer_end, ast_sip_session::defer_terminate, ast_sip_session::ended_while_deferred, ast_sip_session::scheduled_termination, and session_termination_cb().

Referenced by refer_incoming_attended_request(), and refer_incoming_blind_request().

3555 {
3556  pj_time_val delay = { .sec = 60, };
3557  int res;
3558 
3559  /* The session should not have an active deferred termination request. */
3560  ast_assert(!session->defer_terminate);
3561 
3562  session->defer_terminate = 1;
3563 
3564  session->defer_end = 1;
3565  session->ended_while_deferred = 0;
3566 
3567  ao2_ref(session, +1);
3568  pj_timer_entry_init(&session->scheduled_termination, 0, session, session_termination_cb);
3569 
3570  res = (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
3571  &session->scheduled_termination, &delay) != PJ_SUCCESS) ? -1 : 0;
3572  if (res) {
3573  session->defer_terminate = 0;
3574  ao2_ref(session, -1);
3575  }
3576  return res;
3577 }
unsigned int defer_end
unsigned int defer_terminate
unsigned int ended_while_deferred
static void session_termination_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
#define ast_assert(a)
Definition: utils.h:695
#define ao2_ref(o, delta)
Definition: astobj2.h:464
pj_timer_entry scheduled_termination
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718

◆ ast_sip_session_defer_termination_cancel()

void ast_sip_session_defer_termination_cancel ( struct ast_sip_session session)

Cancel a pending deferred termination.

Parameters
sessionThe session to cancel a deferred termination on.

Definition at line 3596 of file res_pjsip_session.c.

References ast_sip_session_terminate(), ast_sip_session::defer_terminate, sip_session_defer_termination_stop_timer(), and ast_sip_session::terminate_while_deferred.

Referenced by defer_termination_cancel_task(), refer_incoming_attended_request(), and refer_incoming_blind_request().

3597 {
3598  if (!session->defer_terminate) {
3599  /* Already canceled or timer fired. */
3600  return;
3601  }
3602 
3603  session->defer_terminate = 0;
3604 
3605  if (session->terminate_while_deferred) {
3606  /* Complete the termination started by the upper layer. */
3607  ast_sip_session_terminate(session, 0);
3608  }
3609 
3610  /* Stop the termination timer if it is still running. */
3612 }
unsigned int defer_terminate
unsigned int terminate_while_deferred
static void sip_session_defer_termination_stop_timer(struct ast_sip_session *session)
void ast_sip_session_terminate(struct ast_sip_session *session, int response)
Terminate a session and, if possible, send the provided response code.

◆ ast_sip_session_end_if_deferred()

void ast_sip_session_end_if_deferred ( struct ast_sip_session session)

End the session if it had been previously deferred.

Parameters
sessionThe session to end if it had been deferred

Definition at line 3614 of file res_pjsip_session.c.

References ast_debug, ast_sip_session_get_name(), ast_sip_session::defer_end, ast_sip_session::ended_while_deferred, and session_end().

Referenced by defer_termination_cancel_task(), refer_attended_task(), refer_incoming_attended_request(), refer_incoming_blind_request(), and session_end_if_deferred_task().

3615 {
3616  if (!session->defer_end) {
3617  return;
3618  }
3619 
3620  session->defer_end = 0;
3621 
3622  if (session->ended_while_deferred) {
3623  /* Complete the session end started by the remote hangup. */
3624  ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3625  session->ended_while_deferred = 0;
3626  session_end(session);
3627  }
3628 }
unsigned int defer_end
unsigned int ended_while_deferred
static int session_end(void *vsession)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.

◆ ast_sip_session_get_datastore()

struct ast_datastore* ast_sip_session_get_datastore ( struct ast_sip_session session,
const char *  name 
)

Retrieve a session datastore.

The datastore retrieved will have its reference count incremented. When the caller is done with the datastore, the reference counted needs to be decremented using ao2_ref().

Parameters
sessionThe session from which to retrieve the datastore
nameThe name of the datastore to retrieve
Return values
NULLFailed to find the specified datastore
non-NULLThe specified datastore

Definition at line 1285 of file res_pjsip_session.c.

References ao2_find, ast_sip_session::datastores, and OBJ_KEY.

Referenced by add_header(), chan_pjsip_get_rtp_peer(), channel_read_pjsip(), direct_media_mitigate_glare(), handle_outgoing_response(), incoming_request(), outgoing_request(), read_header(), remove_header(), session_refresh_state_get_or_alloc(), t38_automatic_reject(), t38_state_get_or_alloc(), and update_header().

1286 {
1287  return ao2_find(session->datastores, name, OBJ_KEY);
1288 }
#define OBJ_KEY
Definition: astobj2.h:1155
struct ao2_container * datastores
static const char name[]
Definition: cdr_mysql.c:74
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ ast_sip_session_get_name()

const char* ast_sip_session_get_name ( const struct ast_sip_session session)

Get the channel or endpoint name associated with the session.

Since
18.0.0
Parameters
session
Return values
Channelname or endpoint name or "unknown"

Definition at line 115 of file res_pjsip_session.c.

References ast_channel_name(), ast_sorcery_object_get_id(), ast_sip_session::channel, and ast_sip_session::endpoint.

Referenced by add_sdp_streams(), answer(), apply_negotiated_sdp_stream(), ast_sip_session_create_invite(), ast_sip_session_end_if_deferred(), ast_sip_session_media_state_add(), ast_sip_session_regenerate_answer(), ast_sip_session_terminate(), call(), chan_pjsip_call(), chan_pjsip_incoming_ack(), chan_pjsip_incoming_request(), chan_pjsip_incoming_response(), chan_pjsip_incoming_response_update_cause(), chan_pjsip_new(), chan_pjsip_session_begin(), chan_pjsip_session_end(), create_local_sdp(), create_outgoing_sdp_stream(), delay_request(), generate_session_refresh_sdp(), get_codecs(), get_destination(), handle_incoming_before_media(), handle_incoming_request(), handle_incoming_response(), handle_incoming_sdp(), handle_negotiated_sdp(), handle_negotiated_sdp_session_media(), handle_new_invite_request(), handle_outgoing_request(), handle_outgoing_response(), invite_collision_timeout(), invite_proceeding(), invite_terminated(), negotiate_incoming_sdp_stream(), new_invite(), on_topology_change_response(), outbound_invite_auth(), pbx_start_incoming_request(), reschedule_reinvite(), resend_reinvite(), sdp_requires_deferral(), send_delayed_request(), send_topology_change_refresh(), session_destructor(), session_inv_on_media_update(), session_inv_on_rx_offer(), session_inv_on_state_changed(), session_inv_on_tsx_state_changed(), session_on_rx_request(), session_on_rx_response(), session_on_tsx_state(), session_outgoing_nat_hook(), set_caps(), set_from_header(), set_incoming_call_offer_cap(), and sip_session_refresh().

116 {
117  if (!session) {
118  return "(null session)";
119  }
120  if (session->channel) {
121  return ast_channel_name(session->channel);
122  } else if (session->endpoint) {
123  return ast_sorcery_object_get_id(session->endpoint);
124  } else {
125  return "unknown";
126  }
127 }
struct ast_sip_endpoint * endpoint
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_channel * channel
const char * ast_channel_name(const struct ast_channel *chan)

◆ ast_sip_session_is_pending_stream_default()

int ast_sip_session_is_pending_stream_default ( const struct ast_sip_session session,
const struct ast_stream stream 
)

Determines if a provided pending stream will be the default stream or not.

Since
15.0.0
Parameters
sessionThe session to check against
streamThe pending stream
Return values
1if stream will be default
0if stream will NOT be the default

Definition at line 359 of file res_pjsip_session.c.

References ast_channel_name(), ast_log, ast_stream_get_state(), ast_stream_get_type(), AST_STREAM_STATE_REMOVED, ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_sip_session::channel, LOG_WARNING, ast_sip_session::pending_media_state, and ast_sip_session_media_state::topology.

Referenced by create_outgoing_sdp_stream(), handle_incoming_sdp(), handle_negotiated_sdp_session_media(), negotiate_incoming_sdp_stream(), sdp_requires_deferral(), and set_caps().

360 {
361  int index;
362 
363  if (!session->pending_media_state->topology) {
364  ast_log(LOG_WARNING, "Pending topology was NULL for channel '%s'\n",
365  session->channel ? ast_channel_name(session->channel) : "unknown");
366  return 0;
367  }
368 
370  return 0;
371  }
372 
373  for (index = 0; index < ast_stream_topology_get_count(session->pending_media_state->topology); ++index) {
375  ast_stream_get_type(stream)) {
376  continue;
377  }
378 
379  return ast_stream_topology_get_stream(session->pending_media_state->topology, index) == stream ? 1 : 0;
380  }
381 
382  return 0;
383 }
struct ast_sip_session_media_state * pending_media_state
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
#define LOG_WARNING
Definition: logger.h:274
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define ast_log
Definition: astobj2.c:42
struct ast_channel * channel
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
struct ast_stream_topology * topology
The media stream topology.
const char * ast_channel_name(const struct ast_channel *chan)
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373

◆ ast_sip_session_media_add_read_callback()

int ast_sip_session_media_add_read_callback ( struct ast_sip_session session,
struct ast_sip_session_media session_media,
int  fd,
ast_sip_session_media_read_cb  callback 
)

Set a read callback for a media session with a specific file descriptor.

Since
15.0.0
Parameters
sessionThe session
session_mediaThe media session
fdThe file descriptor
callbackThe read callback
Return values
0the read callback was successfully added
-1the read callback could not be added
Note
This operations on the pending media state

Definition at line 385 of file res_pjsip_session.c.

References AST_VECTOR_APPEND, ast_sip_session_media_read_callback_state::fd, and ast_sip_session::pending_media_state.

Referenced by apply_negotiated_sdp_stream().

387 {
388  struct ast_sip_session_media_read_callback_state callback_state = {
389  .fd = fd,
390  .read_callback = callback,
391  .session = session_media,
392  };
393 
394  /* The contents of the vector are whole structs and not pointers */
395  return AST_VECTOR_APPEND(&session->pending_media_state->read_callbacks, callback_state);
396 }
struct ast_sip_session_media_state * pending_media_state
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
Structure which contains read callback information.
int fd
The file descriptor itself.

◆ ast_sip_session_media_get_transport()

struct ast_sip_session_media* ast_sip_session_media_get_transport ( struct ast_sip_session session,
struct ast_sip_session_media session_media 
)

Retrieve the underlying media session that is acting as transport for a media session.

Since
15.0.0
Parameters
sessionThe session
session_mediaThe media session to retrieve the transport for
Note
This operates on the pending media state
This function is guaranteed to return non-NULL

Definition at line 414 of file res_pjsip_session.c.

References ast_strlen_zero, AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_endpoint_media_configuration::bundle, ast_sip_session_media::bundle_group, ast_sip_session::endpoint, ast_sip_endpoint::media, ast_sip_session_media::mid, and ast_sip_session::pending_media_state.

Referenced by apply_negotiated_sdp_stream(), create_outgoing_sdp_stream(), and negotiate_incoming_sdp_stream().

415 {
416  int index;
417 
418  if (!session->endpoint->media.bundle || ast_strlen_zero(session_media->mid)) {
419  return session_media;
420  }
421 
422  for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
423  struct ast_sip_session_media *bundle_group_session_media;
424 
425  bundle_group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
426 
427  /* The first session which is in the bundle group is considered the authoritative session for transport */
428  if (bundle_group_session_media->bundle_group == session_media->bundle_group) {
429  return bundle_group_session_media;
430  }
431  }
432 
433  return session_media;
434 }
struct ast_sip_endpoint * endpoint
struct ast_sip_session_media_state * pending_media_state
char * mid
Media identifier for this stream (may be shared across multiple streams)
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
int bundle_group
The bundle group the stream belongs to.
A structure containing SIP session media information.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ ast_sip_session_media_set_write_callback()

int ast_sip_session_media_set_write_callback ( struct ast_sip_session session,
struct ast_sip_session_media session_media,
ast_sip_session_media_write_cb  callback 
)

Set a write callback for a media session.

Since
15.0.0
Parameters
sessionThe session
session_mediaThe media session
callbackThe write callback
Return values
0the write callback was successfully add
-1the write callback is already set to something different
Note
This operates on the pending media state

Definition at line 398 of file res_pjsip_session.c.

References ast_sip_session_media::write_callback.

Referenced by apply_negotiated_sdp_stream().

400 {
401  if (session_media->write_callback) {
402  if (session_media->write_callback == callback) {
403  return 0;
404  }
405 
406  return -1;
407  }
408 
409  session_media->write_callback = callback;
410 
411  return 0;
412 }
ast_sip_session_media_write_cb write_callback
The write callback when writing frames.

◆ ast_sip_session_media_state_add()

struct ast_sip_session_media* ast_sip_session_media_state_add ( struct ast_sip_session session,
struct ast_sip_session_media_state media_state,
enum ast_media_type  type,
int  position 
)

Allocate an ast_session_media and add it to the media state's vector.

Since
15.0.0

This allocates a session media of the specified type. The position argument determines where in the vector that the new session media will be inserted.

Note
The returned ast_session_media is the reference held by the vector. Callers of this function must NOT decrement the refcount of the session media.
Parameters
sessionSession on which to query active media state for
media_stateMedia state to place the session media into
typeThe type of the session media
positionPosition at which to insert the new session media.
Note
The active media state will be queried and if a media session already exists at the given position for the same type it will be reused instead of allocating a new one.
Return values
non-NULLsuccess
NULLfailure

Definition at line 490 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_cleanup, ao2_ref, ast_asprintf, ast_codec_media_type2str(), ast_free, ast_sip_session_get_name(), ast_strdup, ast_stream_get_name(), ast_stream_get_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_get_stream(), ast_trace, AST_VECTOR_GET, AST_VECTOR_REPLACE, AST_VECTOR_SIZE, ast_sip_endpoint_media_configuration::bundle, ast_sip_session_media::bundle_group, ast_sip_session_media::bundled, ast_sip_session_media_state::default_session, ast_sip_session_media::encryption, ast_sip_media_rtp_configuration::encryption, ast_sip_session::endpoint, ast_sip_media_rtp_configuration::ice_support, ast_sip_session_media::keepalive_sched_id, ast_sip_endpoint::media, ast_sip_session_media::mid, NULL, ast_sip_session_media::remote_ice, ast_sip_session_media::remote_rtcp_mux, ast_sip_endpoint_media_configuration::rtcp_mux, ast_sip_endpoint_media_configuration::rtp, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session_media_dtor(), ast_sip_session_media::stream_name, ast_sip_session_media::stream_num, ast_sip_session_media::timeout_sched_id, ast_sip_session_media_state::topology, ast_sip_session_media::type, type, and ast_sip_endpoint_media_configuration::webrtc.

Referenced by create_local_sdp(), handle_incoming_sdp(), sdp_requires_deferral(), and t38_create_media_state().

492 {
493  struct ast_sip_session_media *session_media = NULL;
494  struct ast_sip_session_media *current_session_media = NULL;
495  SCOPE_ENTER(1, "%s Adding position %d\n", ast_sip_session_get_name(session), position);
496 
497  /* It is possible for this media state to already contain a session for the stream. If this
498  * is the case we simply return it.
499  */
500  if (position < AST_VECTOR_SIZE(&media_state->sessions)) {
501  current_session_media = AST_VECTOR_GET(&media_state->sessions, position);
502  if (current_session_media && current_session_media->type == type) {
503  SCOPE_EXIT_RTN_VALUE(current_session_media, "Using existing media_session\n");
504  }
505  }
506 
507  /* Determine if we can reuse the session media from the active media state if present */
508  if (position < AST_VECTOR_SIZE(&session->active_media_state->sessions)) {
509  session_media = AST_VECTOR_GET(&session->active_media_state->sessions, position);
510  /* A stream can never exist without an accompanying media session */
511  if (session_media->type == type) {
512  ao2_ref(session_media, +1);
513  ast_trace(1, "Reusing existing media session\n");
514  /*
515  * If this session_media was previously removed, its bundle group was probably reset
516  * to -1 so if bundling is enabled on the endpoint, we need to reset it to 0, set
517  * the bundled flag and reset its mid.
518  */
519  if (session->endpoint->media.bundle && session_media->bundle_group == -1) {
520  session_media->bundled = session->endpoint->media.webrtc;
521  session_media->bundle_group = 0;
522  ast_free(session_media->mid);
523  if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {
524  ao2_ref(session_media, -1);
525  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");
526  }
527  }
528  } else {
529  ast_trace(1, "Can't reuse existing media session because the types are different. %s <> %s\n",
531  session_media = NULL;
532  }
533  }
534 
535  if (!session_media) {
536  /* No existing media session we can use so create a new one */
537  session_media = ao2_alloc_options(sizeof(*session_media), session_media_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
538  if (!session_media) {
539  return NULL;
540  }
541  ast_trace(1, "Creating new media session\n");
542 
543  session_media->encryption = session->endpoint->media.rtp.encryption;
544  session_media->remote_ice = session->endpoint->media.rtp.ice_support;
545  session_media->remote_rtcp_mux = session->endpoint->media.rtcp_mux;
546  session_media->keepalive_sched_id = -1;
547  session_media->timeout_sched_id = -1;
548  session_media->type = type;
549  session_media->stream_num = position;
550 
551  if (session->endpoint->media.bundle) {
552  /* This is a new stream so create a new mid based on media type and position, which makes it unique.
553  * If this is the result of an offer the mid will just end up getting replaced.
554  */
555  if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {
556  ao2_ref(session_media, -1);
557  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");
558  }
559  session_media->bundle_group = 0;
560 
561  /* Some WebRTC clients can't handle an offer to bundle media streams. Instead they expect them to
562  * already be bundled. Every client handles this scenario though so if WebRTC is enabled just go
563  * ahead and treat the streams as having already been bundled.
564  */
565  session_media->bundled = session->endpoint->media.webrtc;
566  } else {
567  session_media->bundle_group = -1;
568  }
569  }
570 
571  ast_free(session_media->stream_name);
572  session_media->stream_name = ast_strdup(ast_stream_get_name(ast_stream_topology_get_stream(media_state->topology, position)));
573 
574  if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {
575  ao2_ref(session_media, -1);
576 
577  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't replace media_session\n");
578  }
579 
580  ao2_cleanup(current_session_media);
581 
582  /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */
584  ast_trace(1, "Setting media session as default for %s\n", ast_codec_media_type2str(session_media->type));
585 
586  media_state->default_session[type] = session_media;
587  }
588 
589  SCOPE_EXIT_RTN_VALUE(session_media, "Done\n");
590 }
static const char type[]
Definition: chan_ooh323.c:109
struct ast_sip_endpoint * endpoint
char * mid
Media identifier for this stream (may be shared across multiple streams)
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
enum ast_sip_session_media_encryption encryption
What type of encryption is in use on this stream.
unsigned int bundled
Whether this stream is currently bundled or not.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
struct ast_sip_session_media_state * active_media_state
char * stream_name
Stream name.
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
struct ast_sip_media_rtp_configuration rtp
Definition: res_pjsip.h:764
#define ao2_ref(o, delta)
Definition: astobj2.h:464
enum ast_sip_session_media_encryption encryption
Definition: res_pjsip.h:711
int stream_num
The stream number to place into any resulting frames.
static void session_media_dtor(void *obj)
int timeout_sched_id
Scheduler ID for RTP timeout.
#define ast_free(a)
Definition: astmm.h:182
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
int bundle_group
The bundle group the stream belongs to.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
int keepalive_sched_id
Scheduler ID for RTP keepalive.
A structure containing SIP session media information.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
enum ast_media_type type
Media type of this session media.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream_topology * topology
The media stream topology.
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:284
unsigned int remote_rtcp_mux
Does remote support rtcp_mux.
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
unsigned int remote_ice
Does remote support ice.

◆ ast_sip_session_media_state_alloc()

struct ast_sip_session_media_state* ast_sip_session_media_state_alloc ( void  )

Allocate a session media state structure.

Since
15.0.0
Return values
non-NULLsuccess
NULLfailure

Definition at line 238 of file res_pjsip_session.c.

References DEFAULT_NUM_SESSION_MEDIA, and internal_sip_session_media_state_alloc().

Referenced by ast_sip_session_alloc(), session_refresh_state_get_or_alloc(), t38_create_media_state(), and topology_change_refresh_data_alloc().

239 {
242 }
#define DEFAULT_NUM_SESSION_MEDIA
static struct ast_sip_session_media_state * internal_sip_session_media_state_alloc(size_t sessions, size_t read_callbacks)

◆ ast_sip_session_media_state_clone()

struct ast_sip_session_media_state* ast_sip_session_media_state_clone ( const struct ast_sip_session_media_state media_state)

Clone a media state.

Since
15.0.0
Parameters
media_stateThe media state to clone
Return values
non-NULLsuccess
NULLfailure

Definition at line 297 of file res_pjsip_session.c.

References ao2_bump, ao2_cleanup, ast_sip_session_media_state_free(), ast_stream_get_state(), ast_stream_get_type(), AST_STREAM_STATE_REMOVED, ast_stream_topology_clone(), ast_stream_topology_get_stream(), AST_VECTOR_GET, AST_VECTOR_GET_ADDR, AST_VECTOR_REPLACE, AST_VECTOR_SIZE, ast_sip_session_media_state::default_session, internal_sip_session_media_state_alloc(), NULL, ast_sip_session_media_read_callback_state::read_callback, ast_sip_session_media_state::topology, and type.

Referenced by handle_negotiated_sdp(), reschedule_reinvite(), resolve_refresh_media_states(), sip_session_refresh(), and t38_reinvite_sdp_cb().

298 {
299  struct ast_sip_session_media_state *cloned;
300  int index;
301 
302  if (!media_state) {
303  return NULL;
304  }
305 
307  AST_VECTOR_SIZE(&media_state->sessions),
308  AST_VECTOR_SIZE(&media_state->read_callbacks));
309  if (!cloned) {
310  return NULL;
311  }
312 
313  if (media_state->topology) {
314  cloned->topology = ast_stream_topology_clone(media_state->topology);
315  if (!cloned->topology) {
317  return NULL;
318  }
319  }
320 
321  for (index = 0; index < AST_VECTOR_SIZE(&media_state->sessions); ++index) {
322  struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index);
324 
325  ao2_bump(session_media);
326  if (AST_VECTOR_REPLACE(&cloned->sessions, index, session_media)) {
327  ao2_cleanup(session_media);
328  }
330  !cloned->default_session[type]) {
331  cloned->default_session[type] = session_media;
332  }
333  }
334 
335  for (index = 0; index < AST_VECTOR_SIZE(&media_state->read_callbacks); ++index) {
336  struct ast_sip_session_media_read_callback_state *read_callback = AST_VECTOR_GET_ADDR(&media_state->read_callbacks, index);
337 
338  AST_VECTOR_REPLACE(&cloned->read_callbacks, index, *read_callback);
339  }
340 
341  return cloned;
342 }
static const char type[]
Definition: chan_ooh323.c:109
Structure which contains media state information (streams, sessions)
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:670
static struct ast_sip_session_media_state * internal_sip_session_media_state_alloc(size_t sessions, size_t read_callbacks)
ast_sip_session_media_read_cb read_callback
The callback to invoke.
Structure which contains read callback information.
A structure containing SIP session media information.
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream_topology * topology
The media stream topology.
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:284
ast_media_type
Types of media.
Definition: codec.h:30
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ ast_sip_session_media_state_free()

void ast_sip_session_media_state_free ( struct ast_sip_session_media_state media_state)

Free a session media state structure.

Since
15.0.0

Definition at line 344 of file res_pjsip_session.c.

References ast_free, ast_sip_session_media_state_reset(), and AST_VECTOR_FREE.

Referenced by ast_sip_session_media_state_clone(), delay_request(), delayed_request_free(), handle_negotiated_sdp(), reschedule_reinvite(), resolve_refresh_media_states(), session_destructor(), session_refresh_state_destroy(), sip_session_refresh(), t38_create_media_state(), t38_reinvite_response_cb(), t38_state_destroy(), and topology_change_refresh_data_free().

345 {
346  if (!media_state) {
347  return;
348  }
349 
350  /* This will reset the internal state so we only have to free persistent things */
352 
353  AST_VECTOR_FREE(&media_state->sessions);
354  AST_VECTOR_FREE(&media_state->read_callbacks);
355 
356  ast_free(media_state);
357 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define ast_free(a)
Definition: astmm.h:182
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.

◆ ast_sip_session_media_state_reset()

void ast_sip_session_media_state_reset ( struct ast_sip_session_media_state media_state)

Reset a media state to a clean state.

Since
15.0.0
Parameters
media_stateThe media state to reset

Definition at line 278 of file res_pjsip_session.c.

References ao2_cleanup, AST_MEDIA_TYPE_END, ast_stream_topology_free(), AST_VECTOR_ELEM_CLEANUP_NOOP, AST_VECTOR_RESET, ast_sip_session_media_state::default_session, NULL, and ast_sip_session_media_state::topology.

Referenced by ast_sip_session_media_state_free(), ast_sip_session_terminate(), handle_negotiated_sdp(), on_topology_change_response(), session_inv_on_media_update(), session_inv_on_rx_offer(), session_reinvite_on_rx_request(), sip_session_refresh(), and t38_reinvite_response_cb().

279 {
280  int index;
281 
282  if (!media_state) {
283  return;
284  }
285 
286  AST_VECTOR_RESET(&media_state->sessions, ao2_cleanup);
287  AST_VECTOR_RESET(&media_state->read_callbacks, AST_VECTOR_ELEM_CLEANUP_NOOP);
288 
289  for (index = 0; index < AST_MEDIA_TYPE_END; ++index) {
290  media_state->default_session[index] = NULL;
291  }
292 
293  ast_stream_topology_free(media_state->topology);
294  media_state->topology = NULL;
295 }
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
#define NULL
Definition: resample.c:96
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:573
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:627
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream_topology * topology
The media stream topology.
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743

◆ ast_sip_session_media_stats_save()

void ast_sip_session_media_stats_save ( struct ast_sip_session sip_session,
struct ast_sip_session_media_state media_state 
)

Save a media stats.

Parameters
media_stateThe media state to save

Definition at line 244 of file res_pjsip_session.c.

References ast_calloc, ast_free, ast_rtp_instance_get_stats(), AST_RTP_INSTANCE_STAT_ALL, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_REMOVE_CMP_UNORDERED, AST_VECTOR_SIZE, media_stats_local_ssrc_cmp(), NULL, and ast_sip_session_media::rtp.

Referenced by ast_sip_session_terminate(), and handle_negotiated_sdp().

245 {
246  int i;
247  int ret;
248 
249  if (!media_state || !sip_session) {
250  return;
251  }
252 
253  for (i = 0; i < AST_VECTOR_SIZE(&media_state->sessions); i++) {
254  struct ast_rtp_instance_stats *stats_tmp = NULL;
255  struct ast_sip_session_media *media = AST_VECTOR_GET(&media_state->sessions, i);
256  if (!media || !media->rtp) {
257  continue;
258  }
259 
260  stats_tmp = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
261  if (!stats_tmp) {
262  return;
263  }
264 
265  ret = ast_rtp_instance_get_stats(media->rtp, stats_tmp, AST_RTP_INSTANCE_STAT_ALL);
266  if (ret) {
267  ast_free(stats_tmp);
268  continue;
269  }
270 
271  /* remove all the duplicated stats if exist */
272  AST_VECTOR_REMOVE_CMP_UNORDERED(&sip_session->media_stats, stats_tmp, media_stats_local_ssrc_cmp, ast_free);
273 
274  AST_VECTOR_APPEND(&sip_session->media_stats, stats_tmp);
275  }
276 }
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
Retrieve statistics about an RTP instance.
Definition: rtp_engine.c:2446
#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition: vector.h:488
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define NULL
Definition: resample.c:96
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
A structure containing SIP session media information.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
struct ast_rtp_instance * rtp
RTP instance itself.
static int media_stats_local_ssrc_cmp(const struct ast_rtp_instance_stats *vec_elem, const struct ast_rtp_instance_stats *srch)
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ ast_sip_session_refresh()

int ast_sip_session_refresh ( struct ast_sip_session session,
ast_sip_session_request_creation_cb  on_request_creation,
ast_sip_session_sdp_creation_cb  on_sdp_creation,
ast_sip_session_response_cb  on_response,
enum ast_sip_session_refresh_method  method,
int  generate_new_sdp,
struct ast_sip_session_media_state media_state 
)

Send a reinvite or UPDATE on a session.

This method will inspect the session in order to construct an appropriate session refresh request. As with any outgoing request in res_pjsip_session, this will call into registered supplements in case they wish to add anything.

Note: The on_request_creation callback may or may not be called in the same thread where this function is called. Request creation may need to be delayed due to the current INVITE transaction state.

Parameters
sessionThe session on which the reinvite will be sent
on_request_creationCallback called when request is created
on_sdp_creationCallback called when SDP is created
on_responseCallback called when response for request is received
methodThe method that should be used when constructing the session refresh
generate_new_sdpBoolean to indicate if a new SDP should be created
media_stateOptional requested media state for the SDP
Return values
0Successfully sent refresh
-1Failure to send refresh
Note
If a media_state is passed in ownership will be taken in all cases

Definition at line 2524 of file res_pjsip_session.c.

References NULL, and sip_session_refresh().

Referenced by dtmf_mode_refresh_cb(), refresh_write_cb(), remote_send_hold_refresh(), send_direct_media_request(), send_topology_change_refresh(), t38_interpret_parameters(), and update_connected_line_information().

2530 {
2531  return sip_session_refresh(session, on_request_creation, on_sdp_creation,
2532  on_response, method, generate_new_sdp, media_state, NULL, 0);
2533 }
#define NULL
Definition: resample.c:96
static int sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queued)
const char * method
Definition: res_pjsip.c:4335

◆ ast_sip_session_regenerate_answer()

int ast_sip_session_regenerate_answer ( struct ast_sip_session session,
ast_sip_session_sdp_creation_cb  on_sdp_creation 
)

Regenerate SDP Answer.

This method is used when an SDP offer has been received but an SDP answer has not been sent yet. It requests that a new local SDP be created and set as the SDP answer. As with any outgoing request in res_pjsip_session, this will call into registered supplements in case they wish to add anything.

Parameters
sessionThe session on which the answer will be updated
on_sdp_creationCallback called when SDP is created
generate_new_sdpBoolean to indicate if a new SDP should be created
Return values
0Successfully updated the SDP answer
-1Failure to updated the SDP answer

Definition at line 2535 of file res_pjsip_session.c.

References ast_channel_name(), ast_log, ast_sip_session_get_name(), ast_sip_session::channel, create_local_sdp(), ast_sip_session::inv_session, LOG_WARNING, NULL, SCOPE_ENTER, and SCOPE_EXIT_RTN_VALUE.

Referenced by dtmf_mode_refresh_cb().

2537 {
2538  pjsip_inv_session *inv_session = session->inv_session;
2539  pjmedia_sdp_session *new_answer = NULL;
2540  const pjmedia_sdp_session *previous_offer = NULL;
2541  SCOPE_ENTER(1, "%s\n", ast_sip_session_get_name(session));
2542 
2543  /* The SDP answer can only be regenerated if it is still pending to be sent */
2544  if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER &&
2545  pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) {
2546  ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n",
2547  ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg)));
2548  SCOPE_EXIT_RTN_VALUE(-1, "Bad negotiation state\n");
2549  }
2550 
2551  pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer);
2552  if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2553  /* Transition the SDP negotiator back to when it received the remote offer */
2554  pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0);
2555  pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer);
2556  }
2557 
2558  new_answer = create_local_sdp(inv_session, session, previous_offer);
2559  if (!new_answer) {
2560  ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n",
2561  ast_channel_name(session->channel));
2562  SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create new SDP\n");
2563  }
2564 
2565  if (on_sdp_creation) {
2566  if (on_sdp_creation(session, new_answer)) {
2567  SCOPE_EXIT_RTN_VALUE(-1, "Callback failed\n");
2568  }
2569  }
2570 
2571  pjsip_inv_set_sdp_answer(inv_session, new_answer);
2572 
2574 }
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
#define ast_log
Definition: astobj2.c:42
struct ast_channel * channel
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
const char * ast_channel_name(const struct ast_channel *chan)

◆ ast_sip_session_register_sdp_handler()

int ast_sip_session_register_sdp_handler ( struct ast_sip_session_sdp_handler handler,
const char *  stream_type 
)

Register an SDP handler.

An SDP handler is responsible for parsing incoming SDP streams and ensuring that Asterisk can cope with the contents. Similarly, the SDP handler will be responsible for constructing outgoing SDP streams.

Multiple handlers for the same stream type may be registered. They will be visited in the order they were registered. Handlers will be visited for each stream type until one claims to have handled the stream.

Parameters
handlerThe SDP handler to register
stream_typeThe type of media stream for which to call the handler
Return values
0Success
-1Failure

Definition at line 138 of file res_pjsip_session.c.

References ao2_alloc, ao2_cleanup, ao2_find, ao2_link, ast_debug, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log, ast_sip_session_sdp_handler::id, lock, LOG_WARNING, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, and SCOPED_AO2LOCK.

Referenced by load_module().

139 {
140  RAII_VAR(struct sdp_handler_list *, handler_list,
141  ao2_find(sdp_handlers, stream_type, OBJ_KEY), ao2_cleanup);
143 
144  if (handler_list) {
145  struct ast_sip_session_sdp_handler *iter;
146  /* Check if this handler is already registered for this stream type */
147  AST_LIST_TRAVERSE(&handler_list->list, iter, next) {
148  if (!strcmp(iter->id, handler->id)) {
149  ast_log(LOG_WARNING, "Handler '%s' already registered for stream type '%s'.\n", handler->id, stream_type);
150  return -1;
151  }
152  }
153  AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
154  ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
155 
156  return 0;
157  }
158 
159  /* No stream of this type has been registered yet, so we need to create a new list */
160  handler_list = ao2_alloc(sizeof(*handler_list) + strlen(stream_type), NULL);
161  if (!handler_list) {
162  return -1;
163  }
164  /* Safe use of strcpy */
165  strcpy(handler_list->stream_type, stream_type);
166  AST_LIST_HEAD_INIT_NOLOCK(&handler_list->list);
167  AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
168  if (!ao2_link(sdp_handlers, handler_list)) {
169  return -1;
170  }
171  ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
172 
173  return 0;
174 }
#define OBJ_KEY
Definition: astobj2.h:1155
#define LOG_WARNING
Definition: logger.h:274
A handler for SDPs in SIP sessions.
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_sip_session_sdp_handler * next
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
ast_mutex_t lock
Definition: app_meetme.c:1091
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ ast_sip_session_remove_datastore()

void ast_sip_session_remove_datastore ( struct ast_sip_session session,
const char *  name 
)

Remove a session datastore from the session.

This operation may cause the datastore's free() callback to be called if the reference count reaches zero.

Parameters
sessionThe session to remove the datastore from
nameThe name of the datastore to remove

Definition at line 1290 of file res_pjsip_session.c.

References ao2_callback, ast_sip_session::datastores, NULL, OBJ_KEY, OBJ_NODATA, and OBJ_UNLINK.

Referenced by direct_media_mitigate_glare(), handle_outgoing_response(), outgoing_request(), refresh_write_cb(), and session_refresh_state_get_or_alloc().

1291 {
1292  ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
1293 }
#define OBJ_KEY
Definition: astobj2.h:1155
struct ao2_container * datastores
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define NULL
Definition: resample.c:96
static const char name[]
Definition: cdr_mysql.c:74

◆ ast_sip_session_resume_reinvite()

void ast_sip_session_resume_reinvite ( struct ast_sip_session session)

Resumes processing of a deferred incoming re-invite.

Parameters
sessionThe session which has a pending incoming re-invite
Note
When resuming a re-invite it is given to the pjsip stack as if it had just been received from a transport, this means that the deferral callback will be called again.

Definition at line 2798 of file res_pjsip_session.c.

References ast_sip_get_pjsip_endpoint(), ast_sip_session::channel, ast_sip_session::deferred_reinvite, and NULL.

Referenced by t38_automatic_reject(), and t38_interpret_parameters().

2799 {
2800  if (!session->deferred_reinvite) {
2801  return;
2802  }
2803 
2804  if (session->channel) {
2805  pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(),
2806  session->deferred_reinvite, NULL, NULL);
2807  }
2808  pjsip_rx_data_free_cloned(session->deferred_reinvite);
2809  session->deferred_reinvite = NULL;
2810 }
#define NULL
Definition: resample.c:96
pjsip_rx_data * deferred_reinvite
struct ast_channel * channel
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718

◆ ast_sip_session_send_request()

void ast_sip_session_send_request ( struct ast_sip_session session,
pjsip_tx_data *  tdata 
)

Send a SIP request.

This will send the SIP request specified in tdata and call into any registered supplements' outgoing_request callback.

Parameters
sessionThe session to which to send the request
tdataThe request to send

Definition at line 2842 of file res_pjsip_session.c.

References ast_sip_session_send_request_with_cb(), and NULL.

Referenced by ast_sip_session_terminate(), call(), check_request_status(), handle_incoming_before_media(), outbound_invite_auth(), session_inv_on_tsx_state_changed(), transmit_info_dtmf(), and transmit_info_with_vidupdate().

2843 {
2844  ast_sip_session_send_request_with_cb(session, tdata, NULL);
2845 }
#define NULL
Definition: resample.c:96
void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response)
Send a SIP request and get called back when a response is received.

◆ ast_sip_session_send_request_with_cb()

void ast_sip_session_send_request_with_cb ( struct ast_sip_session session,
pjsip_tx_data *  tdata,
ast_sip_session_response_cb  on_response 
)

Send a SIP request and get called back when a response is received.

This will send the request out exactly the same as ast_sip_send_request() does. The difference is that when a response arrives, the specified callback will be called into

Parameters
sessionThe session on which to send the request
tdataThe request to send
on_responseCallback to be called when a response is received

Definition at line 2818 of file res_pjsip_session.c.

References ast_sip_mod_data_set, handle_outgoing_request(), ast_sip_session::inv_session, and MOD_DATA_ON_RESPONSE.

Referenced by ast_sip_session_send_request(), session_inv_on_tsx_state_changed(), and sip_session_refresh().

2820 {
2821  pjsip_inv_session *inv_session = session->inv_session;
2822 
2823  /* For every request except BYE we disallow sending of the message when
2824  * the session has been disconnected. A BYE request is special though
2825  * because it can be sent again after the session is disconnected except
2826  * with credentials.
2827  */
2828  if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED &&
2829  tdata->msg->line.req.method.id != PJSIP_BYE_METHOD) {
2830  return;
2831  }
2832 
2833  ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id,
2834  MOD_DATA_ON_RESPONSE, on_response);
2835 
2836  handle_outgoing_request(session, tdata);
2837  pjsip_inv_send_msg(session->inv_session, tdata);
2838 
2839  return;
2840 }
#define MOD_DATA_ON_RESPONSE
struct pjsip_inv_session * inv_session
#define ast_sip_mod_data_set(pool, mod_data, id, key, val)
Utilizing a mod_data array for a given id, set the value associated with the given key...
Definition: res_pjsip.h:2670
static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
static pjsip_module session_module

◆ ast_sip_session_send_response()

void ast_sip_session_send_response ( struct ast_sip_session session,
pjsip_tx_data *  tdata 
)

Send a SIP response.

This will send the SIP response specified in tdata and call into any registered supplements' outgoing_response callback.

Parameters
sessionThe session on which to send the response.
tdataThe response to send

Definition at line 2576 of file res_pjsip_session.c.

References handle_outgoing_response(), ast_sip_session::inv_session, session_on_rx_request(), session_on_rx_response(), and session_on_tsx_state().

Referenced by answer(), ast_sip_session_terminate(), chan_pjsip_incoming_request(), indicate(), new_invite(), refer_incoming_invite_request(), transfer_redirect(), and update_connected_line_information().

2577 {
2578  handle_outgoing_response(session, tdata);
2579  pjsip_inv_send_msg(session->inv_session, tdata);
2580  return;
2581 }
struct pjsip_inv_session * inv_session
static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)

◆ ast_sip_session_suspend()

void ast_sip_session_suspend ( struct ast_sip_session session)

Request and wait for the session serializer to be suspended.

Since
12.7.0
Parameters
sessionWhich session to suspend the serializer.
Note
No channel locks can be held while calling without risk of deadlock.
Returns
Nothing

Definition at line 3155 of file res_pjsip_session.c.

References ao2_alloc, ao2_lock, ao2_object_get_lockaddr(), ao2_ref, ao2_unlock, ast_assert, ast_cond_init, ast_cond_wait, ast_sip_push_task(), ast_taskprocessor_is_suspended(), ast_taskprocessor_is_task(), ast_taskprocessor_suspend(), ast_sip_session_suspender::cond_complete, ast_sip_session_suspender::cond_suspended, NULL, ast_sip_session::serializer, sip_session_suspend_task(), sip_session_suspender_dtor(), ast_sip_session::suspended, and ast_sip_session_suspender::suspended.

Referenced by chan_pjsip_indicate().

3156 {
3157  struct ast_sip_session_suspender *suspender;
3158  int res;
3159 
3160  ast_assert(session->suspended == NULL);
3161 
3162  if (ast_taskprocessor_is_task(session->serializer)) {
3163  /* I am the session's serializer thread so I cannot suspend. */
3164  return;
3165  }
3166 
3168  /* The serializer already suspended. */
3169  return;
3170  }
3171 
3172  suspender = ao2_alloc(sizeof(*suspender), sip_session_suspender_dtor);
3173  if (!suspender) {
3174  /* We will just have to hope that the system does not deadlock */
3175  return;
3176  }
3177  ast_cond_init(&suspender->cond_suspended, NULL);
3178  ast_cond_init(&suspender->cond_complete, NULL);
3179 
3180  ao2_ref(suspender, +1);
3181  res = ast_sip_push_task(session->serializer, sip_session_suspend_task, suspender);
3182  if (res) {
3183  /* We will just have to hope that the system does not deadlock */
3184  ao2_ref(suspender, -2);
3185  return;
3186  }
3187 
3188  session->suspended = suspender;
3189 
3190  /* Wait for the serializer to get suspended. */
3191  ao2_lock(suspender);
3192  while (!suspender->suspended) {
3193  ast_cond_wait(&suspender->cond_suspended, ao2_object_get_lockaddr(suspender));
3194  }
3195  ao2_unlock(suspender);
3196 
3198 }
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
#define ast_cond_init(cond, attr)
Definition: lock.h:199
#define ast_assert(a)
Definition: utils.h:695
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
int ast_taskprocessor_suspend(struct ast_taskprocessor *tps)
Indicate the taskprocessor is suspended.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_taskprocessor * serializer
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
Am I the given taskprocessor&#39;s current task.
struct controlling the suspension of the session&#39;s serializer.
int ast_taskprocessor_is_suspended(struct ast_taskprocessor *tps)
Get the task processor suspend status.
struct ast_sip_session_suspender * suspended
static void sip_session_suspender_dtor(void *vdoomed)
static int sip_session_suspend_task(void *data)

◆ ast_sip_session_terminate()

void ast_sip_session_terminate ( struct ast_sip_session session,
int  response 
)

Terminate a session and, if possible, send the provided response code.

Parameters
sessionThe session to terminate
responseThe response code to use for termination if possible
Warning
Calling this function MAY cause the last session reference to be released and the session destructor to be called. If you need to do something with session after this call, be sure to bump the ref count before calling terminate.

Definition at line 3451 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ast_debug, AST_LIST_REMOVE_HEAD, ast_sip_session_get_name(), ast_sip_session_media_state_reset(), ast_sip_session_media_stats_save(), ast_sip_session_send_request(), ast_sip_session_send_response(), ast_sip_session::defer_terminate, delay_request(), DELAYED_METHOD_BYE, delayed_request_free(), ast_sip_session::delayed_requests, ast_sip_session::inv_session, ast_sip_session_delayed_request::next, NULL, ast_sip_session::pending_media_state, SCOPE_ENTER, SCOPE_EXIT_RTN, session_end(), session_end_completion(), status, SWAP, and ast_sip_session::terminate_while_deferred.

Referenced by ast_sip_session_defer_termination_cancel(), chan_pjsip_incoming_request(), hangup(), send_delayed_request(), and session_termination_task().

3452 {
3453  pj_status_t status;
3454  pjsip_tx_data *packet = NULL;
3455  SCOPE_ENTER(1, "%s Response %d\n", ast_sip_session_get_name(session), response);
3456 
3457  if (session->defer_terminate) {
3458  session->terminate_while_deferred = 1;
3459  SCOPE_EXIT_RTN("Deferred\n");
3460  }
3461 
3462  if (!response) {
3463  response = 603;
3464  }
3465 
3466  /* The media sessions need to exist for the lifetime of the underlying channel
3467  * to ensure that anything (such as bridge_native_rtp) has access to them as
3468  * appropriate. Since ast_sip_session_terminate is called by chan_pjsip and other
3469  * places when the session is to be terminated we terminate any existing
3470  * media sessions here.
3471  */
3473  SWAP(session->active_media_state, session->pending_media_state);
3475 
3476  switch (session->inv_session->state) {
3477  case PJSIP_INV_STATE_NULL:
3478  if (!session->inv_session->invite_tsx) {
3479  /*
3480  * Normally, it's pjproject's transaction cleanup that ultimately causes the
3481  * final session reference to be released but if both STATE and invite_tsx are NULL,
3482  * we never created a transaction in the first place. In this case, we need to
3483  * do the cleanup ourselves.
3484  */
3485  /* Transfer the inv_session session reference to the session_end_task */
3486  session->inv_session->mod_data[session_module.id] = NULL;
3487  pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3488  session_end(session);
3489  /*
3490  * session_end_completion will cleanup the final session reference unless
3491  * ast_sip_session_terminate's caller is holding one.
3492  */
3493  session_end_completion(session);
3494  } else {
3495  pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3496  }
3497  break;
3498  case PJSIP_INV_STATE_CONFIRMED:
3499  if (session->inv_session->invite_tsx) {
3500  ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",
3501  ast_sip_session_get_name(session));
3502  /* If this is delayed the only thing that will happen is a BYE request so we don't
3503  * actually need to store the response code for when it happens.
3504  */
3505  delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE, NULL, NULL, 1);
3506  break;
3507  }
3508  /* Fall through */
3509  default:
3510  status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet);
3511  if (status == PJ_SUCCESS && packet) {
3512  struct ast_sip_session_delayed_request *delay;
3513 
3514  /* Flush any delayed requests so they cannot overlap this transaction. */
3515  while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
3516  delayed_request_free(delay);
3517  }
3518 
3519  if (packet->msg->type == PJSIP_RESPONSE_MSG) {
3520  ast_sip_session_send_response(session, packet);
3521  } else {
3522  ast_sip_session_send_request(session, packet);
3523  }
3524  }
3525  break;
3526  }
3527  SCOPE_EXIT_RTN();
3528 }
struct ast_sip_session_media_state * pending_media_state
static int session_end_completion(void *vsession)
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
unsigned int defer_terminate
unsigned int terminate_while_deferred
static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, enum delayed_method method, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queue_head)
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)
#define SWAP(a, b)
Definition: utils.h:230
struct ast_sip_session_delayed_request * next
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
struct ast_sip_session_media_state * active_media_state
static int session_end(void *vsession)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
static pjsip_module session_module
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
void ast_sip_session_media_stats_save(struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
Save a media stats.
Structure used for sending delayed requests.
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_sip_session::@309 delayed_requests
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.
jack_status_t status
Definition: app_jack.c:146

◆ ast_sip_session_unregister_sdp_handler()

void ast_sip_session_unregister_sdp_handler ( struct ast_sip_session_sdp_handler handler,
const char *  stream_type 
)

Unregister an SDP handler.

Parameters
handlerThe SDP handler to unregister
stream_typeStream type for which the SDP handler was registered

Definition at line 199 of file res_pjsip_session.c.

References ao2_callback_data, OBJ_KEY, OBJ_NODATA, OBJ_UNLINK, and remove_handler().

Referenced by unload_module().

200 {
201  ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
202 }
#define OBJ_KEY
Definition: astobj2.h:1155
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1743
static int remove_handler(void *obj, void *arg, void *data, int flags)
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.

◆ ast_sip_session_unsuspend()

void ast_sip_session_unsuspend ( struct ast_sip_session session)

Request the session serializer be unsuspended.

Since
12.7.0
Parameters
sessionWhich session to unsuspend the serializer.
Returns
Nothing

Definition at line 3200 of file res_pjsip_session.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_cond_signal, ast_taskprocessor_unsuspend(), ast_sip_session_suspender::complete, ast_sip_session_suspender::cond_complete, NULL, ast_sip_session::serializer, and ast_sip_session::suspended.

Referenced by chan_pjsip_indicate().

3201 {
3202  struct ast_sip_session_suspender *suspender = session->suspended;
3203 
3204  if (!suspender) {
3205  /* Nothing to do */
3206  return;
3207  }
3208  session->suspended = NULL;
3209 
3210  /* Signal that the serializer task suspension is now complete. */
3211  ao2_lock(suspender);
3212  suspender->complete = 1;
3213  ast_cond_signal(&suspender->cond_complete);
3214  ao2_unlock(suspender);
3215 
3216  ao2_ref(suspender, -1);
3217 
3219 }
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
int ast_taskprocessor_unsuspend(struct ast_taskprocessor *tps)
Indicate the taskprocessor is unsuspended.
struct ast_taskprocessor * serializer
struct controlling the suspension of the session&#39;s serializer.
struct ast_sip_session_suspender * suspended

◆ AST_TEST_DEFINE()

AST_TEST_DEFINE ( test_resolve_refresh_media_states  )

Definition at line 5660 of file res_pjsip_session.c.

References AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, AST_STREAM_STATE_SENDONLY, AST_STREAM_STATE_SENDRECV, AST_TEST_NOT_RUN, AST_TEST_PASS, CHECKER, sip_to_pjsip::info(), NULL, RESET_STATE, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, TEST_EXECUTE, TEST_INIT, and test_media_add().

5661 {
5662 #define FREE_STATE() \
5663 ({ \
5664  ast_sip_session_media_state_free(new_pending_state); \
5665  new_pending_state = NULL; \
5666  ast_sip_session_media_state_free(delayed_pending_state); \
5667  delayed_pending_state = NULL; \
5668  ast_sip_session_media_state_free(delayed_active_state); \
5669  delayed_active_state = NULL; \
5670  ast_sip_session_media_state_free(current_active_state); \
5671  current_active_state = NULL; \
5672  ast_sip_session_media_state_free(expected_pending_state); \
5673  expected_pending_state = NULL; \
5674 })
5675 
5676 #define RESET_STATE(__num) \
5677 ({ \
5678  testnum=__num; \
5679  ast_trace(-1, "Test %d\n", testnum); \
5680  test_failed = 0; \
5681  delayed_pending_state = ast_sip_session_media_state_alloc(); \
5682  delayed_pending_state->topology = ast_stream_topology_alloc(); \
5683  delayed_active_state = ast_sip_session_media_state_alloc(); \
5684  delayed_active_state->topology = ast_stream_topology_alloc(); \
5685  current_active_state = ast_sip_session_media_state_alloc(); \
5686  current_active_state->topology = ast_stream_topology_alloc(); \
5687  expected_pending_state = ast_sip_session_media_state_alloc(); \
5688  expected_pending_state->topology = ast_stream_topology_alloc(); \
5689 })
5690 
5691 #define CHECKER() \
5692 ({ \
5693  new_pending_state = resolve_refresh_media_states("unittest", delayed_pending_state, delayed_active_state, current_active_state, 1); \
5694  if (!test_is_media_state_equal(new_pending_state, expected_pending_state, 0)) { \
5695  res = AST_TEST_FAIL; \
5696  test_failed = 1; \
5697  ast_test_status_update(test, "da: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(delayed_active_state->topology, &STR_TMP))); \
5698  ast_test_status_update(test, "dp: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(delayed_pending_state->topology, &STR_TMP))); \
5699  ast_test_status_update(test, "ca: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(current_active_state->topology, &STR_TMP))); \
5700  ast_test_status_update(test, "ep: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(expected_pending_state->topology, &STR_TMP))); \
5701  ast_test_status_update(test, "np: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(new_pending_state->topology, &STR_TMP))); \
5702  } \
5703  ast_test_status_update(test, "Test %d %s\n", testnum, test_failed ? "FAILED" : "passed"); \
5704  ast_trace(-1, "Test %d %s\n", testnum, test_failed ? "FAILED" : "passed"); \
5705  test_failed = 0; \
5706  FREE_STATE(); \
5707 })
5708 
5709 
5710  struct ast_sip_session_media_state * delayed_pending_state = NULL;
5711  struct ast_sip_session_media_state * delayed_active_state = NULL;
5712  struct ast_sip_session_media_state * current_active_state = NULL;
5713  struct ast_sip_session_media_state * new_pending_state = NULL;
5714  struct ast_sip_session_media_state * expected_pending_state = NULL;
5716  int test_failed = 0;
5717  int testnum = 0;
5718  SCOPE_ENTER(1);
5719 
5720  switch (cmd) {
5721  case TEST_INIT:
5722  info->name = "merge_refresh_topologies";
5723  info->category = "/res/res_pjsip_session/";
5724  info->summary = "Test merging of delayed request topologies";
5725  info->description = "Test merging of delayed request topologies";
5727  case TEST_EXECUTE:
5728  break;
5729  }
5730 
5731  RESET_STATE(1);
5732  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5733  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5734  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5735 
5736  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5737  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5738  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5739  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5740 
5741  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5742  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5743  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5744 
5745  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5746  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5747  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5748  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5749  CHECKER();
5750 
5751  RESET_STATE(2);
5752  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5753  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5754  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5755 
5756  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5757  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5758  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5759  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5760 
5761  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5762  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5763  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5764 
5765  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5766  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5767  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5768  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5769  CHECKER();
5770 
5771  RESET_STATE(3);
5772  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5773  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5774  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5775 
5776  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5777  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5778  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5779  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5780 
5781  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5782  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5783  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5784  test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5785  test_media_add(current_active_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5786 
5787  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5788  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5789  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5790  test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5791  test_media_add(expected_pending_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5792  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5793  CHECKER();
5794 
5795  RESET_STATE(4);
5796  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5797  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5798  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5799 
5800  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5801  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5802  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5803  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5804 
5805  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5806  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5807  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5808 
5809  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5810  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5811  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5812  CHECKER();
5813 
5814  RESET_STATE(5);
5815  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5816  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5817  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5818 
5819  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5820  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5821  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5822 
5823  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5824  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5825  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5826 
5827  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5828  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5829  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5830  CHECKER();
5831 
5832  RESET_STATE(6);
5833  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5834  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5835  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5836 
5837  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5838  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5839  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5840  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5841 
5842  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5843  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5844  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5845  test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5846 
5847  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5848  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5849  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5850  test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5851  CHECKER();
5852 
5853  RESET_STATE(7);
5854  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5855  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5856  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5857 
5858  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5859  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5860  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5861  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5862  test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5863 
5864  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5865  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5866  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5867  test_media_add(current_active_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5868  test_media_add(current_active_state, "myvideo6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5869 
5870  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5871  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5872  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5873  test_media_add(expected_pending_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5874  test_media_add(expected_pending_state, "myvideo6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5875  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5876  test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5877  CHECKER();
5878 
5879  RESET_STATE(8);
5880  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5881  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5882  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5883 
5884  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5885  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5886  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5887  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5888  test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5889 
5890  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5891  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5892  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5893 
5894  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5895  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5896  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5897  test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5898  CHECKER();
5899 
5900  RESET_STATE(9);
5901  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5902  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5903  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5904 
5905  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5906  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5907  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5908  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5909  test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5910 
5911  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5912  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5913  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5914 
5915  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5916  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5917  test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5918  CHECKER();
5919 
5920  RESET_STATE(10);
5921  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5922  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5923  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5924 
5925  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5926  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5927  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5928 
5929  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5930  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5931  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5932  test_media_add(current_active_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5933 
5934  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5935  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5936  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5937  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5938  CHECKER();
5939 
5940  RESET_STATE(11);
5941  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5942  test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5943  test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5944  test_media_add(delayed_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5945 
5946  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5947  test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5948  test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5949  test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5950 
5951  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5952  test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5953  test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5954  test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5955 
5956  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5957  test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5958  test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5959  test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5960  test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5961  CHECKER();
5962 
5963  RESET_STATE(12);
5964  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5965  test_media_add(delayed_active_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5966  test_media_add(delayed_active_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5967 
5968  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5969  test_media_add(delayed_pending_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5970  test_media_add(delayed_pending_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5971  test_media_add(delayed_pending_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5972  test_media_add(delayed_pending_state, "294-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5973 
5974  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5975  test_media_add(current_active_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5976  test_media_add(current_active_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5977  test_media_add(current_active_state, "290-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5978  test_media_add(current_active_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5979 
5980  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5981  test_media_add(expected_pending_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5982  test_media_add(expected_pending_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5983  test_media_add(expected_pending_state, "290-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5984  test_media_add(expected_pending_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5985  test_media_add(expected_pending_state, "294-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5986  CHECKER();
5987 
5988  RESET_STATE(13);
5989  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5990  test_media_add(delayed_active_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5991  test_media_add(delayed_active_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5992  test_media_add(delayed_active_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5993  test_media_add(delayed_active_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5994  test_media_add(delayed_active_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5995 
5996  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5997  test_media_add(delayed_pending_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5998  test_media_add(delayed_pending_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5999  test_media_add(delayed_pending_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6000  test_media_add(delayed_pending_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6001  test_media_add(delayed_pending_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6002  test_media_add(delayed_pending_state, "298-7", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6003 
6004  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6005  test_media_add(current_active_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6006  test_media_add(current_active_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6007  test_media_add(current_active_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6008  test_media_add(current_active_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6009  test_media_add(current_active_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6010  test_media_add(current_active_state, "290-6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6011 
6012  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6013  test_media_add(expected_pending_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6014  test_media_add(expected_pending_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6015  test_media_add(expected_pending_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6016  test_media_add(expected_pending_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6017  test_media_add(expected_pending_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6018  test_media_add(expected_pending_state, "290-6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6019  test_media_add(expected_pending_state, "298-7", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6020  CHECKER();
6021 
6022  RESET_STATE(14);
6023  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6024  test_media_add(delayed_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6025  test_media_add(delayed_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6026 
6027  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6028  test_media_add(delayed_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6029  test_media_add(delayed_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6030  test_media_add(delayed_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6031 
6032  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6033  test_media_add(current_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6034  test_media_add(current_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6035  test_media_add(current_active_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6036  test_media_add(current_active_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6037 
6038  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6039  test_media_add(expected_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6040  test_media_add(expected_pending_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6041  test_media_add(expected_pending_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6042  test_media_add(expected_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6043  test_media_add(expected_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6044  CHECKER();
6045 
6046  RESET_STATE(15);
6047  test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6048  test_media_add(delayed_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6049  test_media_add(delayed_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6050 
6051  test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6052  test_media_add(delayed_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDONLY, -1);
6053  test_media_add(delayed_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6054  test_media_add(delayed_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6055 
6056  test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6057  test_media_add(current_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6058  test_media_add(current_active_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6059  test_media_add(current_active_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6060  test_media_add(current_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6061 
6062  test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
6063  test_media_add(expected_pending_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6064  test_media_add(expected_pending_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6065  test_media_add(expected_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6066  test_media_add(expected_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDONLY, -1);
6067  test_media_add(expected_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
6068  CHECKER();
6069 
6070  SCOPE_EXIT_RTN_VALUE(res);
6071 }
Structure which contains media state information (streams, sessions)
#define RESET_STATE(__num)
Set when the stream has been removed/declined.
Definition: stream.h:78
static struct ast_sip_session_media * test_media_add(struct ast_sip_session_media_state *media_state, const char *name, enum ast_media_type type, enum ast_stream_state state, int position)
#define NULL
Definition: resample.c:96
Set when the stream is sending and receiving media.
Definition: stream.h:82
def info(msg)
Set when the stream is sending media only.
Definition: stream.h:86
#define CHECKER()
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
ast_test_result_state
Definition: test.h:200

◆ check_content_disposition()

static int check_content_disposition ( pjsip_rx_data *  rdata)
static

if there is required media we don't understand, return 1

Definition at line 3891 of file res_pjsip_session.c.

References check_content_disposition_in_multipart(), and NULL.

Referenced by new_invite().

3892 {
3893  pjsip_msg_body *body = rdata->msg_info.msg->body;
3894  pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3895 
3896  if (body && ctype_hdr &&
3897  !pj_stricmp2(&ctype_hdr->media.type, "multipart") &&
3898  (!pj_stricmp2(&ctype_hdr->media.subtype, "mixed") ||
3899  !pj_stricmp2(&ctype_hdr->media.subtype, "alternative"))) {
3900  pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3901  while (part != NULL) {
3903  return 1;
3904  }
3905  part = pjsip_multipart_get_next_part(body, part);
3906  }
3907  }
3908  return 0;
3909 }
static int check_content_disposition_in_multipart(pjsip_multipart_part *part)
#define NULL
Definition: resample.c:96

◆ check_content_disposition_in_multipart()

static int check_content_disposition_in_multipart ( pjsip_multipart_part *  part)
static

Definition at line 3867 of file res_pjsip_session.c.

References check_sdp_content_type_supported().

Referenced by check_content_disposition().

3868 {
3869  pjsip_hdr *hdr = part->hdr.next;
3870  static const pj_str_t str_handling_required = {"handling=required", 16};
3871 
3872  while (hdr != &part->hdr) {
3873  if (hdr->type == PJSIP_H_OTHER) {
3874  pjsip_generic_string_hdr *generic_hdr = (pjsip_generic_string_hdr*)hdr;
3875 
3876  if (!pj_stricmp2(&hdr->name, "Content-Disposition") &&
3877  pj_stristr(&generic_hdr->hvalue, &str_handling_required) &&
3878  !check_sdp_content_type_supported(&part->body->content_type)) {
3879  return 1;
3880  }
3881  }
3882  hdr = hdr->next;
3883  }
3884 
3885  return 0;
3886 }
static int check_sdp_content_type_supported(pjsip_media_type *content_type)

◆ check_delayed_requests()

static void check_delayed_requests ( struct ast_sip_session session,
int(*)(void *vsession)  cb 
)
static

Definition at line 1582 of file res_pjsip_session.c.

References ao2_ref, ast_sip_push_task(), and ast_sip_session::serializer.

Referenced by session_inv_on_tsx_state_changed().

1584 {
1585  ao2_ref(session, +1);
1586  if (ast_sip_push_task(session->serializer, cb, session)) {
1587  ao2_ref(session, -1);
1588  }
1589 }
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_taskprocessor * serializer
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138

◆ check_request_status()

static int check_request_status ( pjsip_inv_session *  inv,
pjsip_event *  e 
)
static

Definition at line 4560 of file res_pjsip_session.c.

References ast_sip_failover_request(), and ast_sip_session_send_request().

Referenced by session_inv_on_state_changed().

4561 {
4562  struct ast_sip_session *session = inv->mod_data[session_module.id];
4563  pjsip_transaction *tsx = e->body.tsx_state.tsx;
4564 
4565  if (tsx->status_code != 503 && tsx->status_code != 408) {
4566  return 0;
4567  }
4568 
4569  if (!ast_sip_failover_request(tsx->last_tx)) {
4570  return 0;
4571  }
4572 
4573  pjsip_inv_uac_restart(inv, PJ_FALSE);
4574  /*
4575  * Bump the ref since it will be on a new transaction and
4576  * we don't want it to go away along with the old transaction.
4577  */
4578  pjsip_tx_data_add_ref(tsx->last_tx);
4579  ast_sip_session_send_request(session, tsx->last_tx);
4580  return 1;
4581 }
A structure describing a SIP session.
int ast_sip_failover_request(pjsip_tx_data *tdata)
Set a request to use the next value in the list of resolved addresses.
Definition: res_pjsip.c:4871
static struct ast_mansession session
static pjsip_module session_module
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.

◆ check_sdp_content_type_supported()

static int check_sdp_content_type_supported ( pjsip_media_type *  content_type)
static

Definition at line 3855 of file res_pjsip_session.c.

Referenced by check_content_disposition_in_multipart().

3856 {
3857  pjsip_media_type app_sdp;
3858  pjsip_media_type_init2(&app_sdp, "application", "sdp");
3859 
3860  if (!pjsip_media_type_cmp(content_type, &app_sdp, 0)) {
3861  return 1;
3862  }
3863 
3864  return 0;
3865 }

◆ create_local_sdp()

static struct pjmedia_sdp_session * create_local_sdp ( pjsip_inv_session *  inv,
struct ast_sip_session session,
const pjmedia_sdp_session *  offer 
)
static

Definition at line 5081 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, add_bundle_groups(), add_sdp_streams(), ast_sip_endpoint_media_configuration::address, ast_random(), ast_sip_get_host_ip_string(), ast_sip_session_get_name(), ast_sip_session_media_state_add(), ast_str_tmp, ast_stream_get_type(), ast_stream_to_str(), ast_stream_topology_clone(), ast_stream_topology_free(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_strlen_zero, ast_trace, end, ast_sip_session::endpoint, ast_sip_media_rtp_configuration::ipv6, LOG_ERROR, ast_sip_endpoint::media, ast_sip_session_media::mid, NULL, ast_sip_session::pending_media_state, ast_sip_endpoint_media_configuration::rtp, S_COR, S_OR, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG_EXPR, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, ast_sip_endpoint_media_configuration::sdpowner, ast_sip_endpoint_media_configuration::sdpsession, ast_sip_session_media_state::topology, and ast_sip_endpoint_media_configuration::topology.

Referenced by ast_sip_session_create_invite(), ast_sip_session_regenerate_answer(), generate_session_refresh_sdp(), new_invite(), session_inv_on_create_offer(), and session_inv_on_rx_offer().

5082 {
5083  static const pj_str_t STR_IN = { "IN", 2 };
5084  static const pj_str_t STR_IP4 = { "IP4", 3 };
5085  static const pj_str_t STR_IP6 = { "IP6", 3 };
5086  pjmedia_sdp_session *local;
5087  int i;
5088  int stream;
5089  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
5090 
5091  if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
5092  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Failed to create session SDP. Session has been already disconnected\n",
5093  ast_sip_session_get_name(session));
5094  }
5095 
5096  if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
5097  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Pool allocation failure\n", ast_sip_session_get_name(session));
5098  }
5099 
5100  if (!offer) {
5101  local->origin.version = local->origin.id = (pj_uint32_t)(ast_random());
5102  } else {
5103  local->origin.version = offer->origin.version + 1;
5104  local->origin.id = offer->origin.id;
5105  }
5106 
5107  pj_strdup2(inv->pool_prov, &local->origin.user, session->endpoint->media.sdpowner);
5108  pj_strdup2(inv->pool_prov, &local->name, session->endpoint->media.sdpsession);
5109 
5111  /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication
5112  * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation
5113  * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the endpoint.
5114  */
5116  if (session->active_media_state->topology) {
5118  } else {
5120  }
5121  if (!session->pending_media_state->topology) {
5122  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: No pending media state topology\n", ast_sip_session_get_name(session));
5123  }
5124  }
5125 
5126  ast_trace(-1, "%s: Processing streams\n", ast_sip_session_get_name(session));
5127 
5128  for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) {
5129  struct ast_sip_session_media *session_media;
5131  unsigned int streams = local->media_count;
5132  SCOPE_ENTER(4, "%s: Processing stream %s\n", ast_sip_session_get_name(session),
5133  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5134 
5135  /* This code does not enforce any maximum stream count limitations as that is done on either
5136  * the handling of an incoming SDP offer or on the handling of a session refresh.
5137  */
5138 
5139  session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i);
5140  if (!session_media) {
5141  local = NULL;
5142  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc/add session media for stream %s\n",
5143  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5144  }
5145 
5146  if (add_sdp_streams(session_media, session, local, offer, stream)) {
5147  local = NULL;
5148  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't add sdp streams for stream %s\n",
5149  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5150  }
5151 
5152  /* If a stream was actually added then add any additional details */
5153  if (streams != local->media_count) {
5154  pjmedia_sdp_media *media = local->media[streams];
5155  pj_str_t stmp;
5156  pjmedia_sdp_attr *attr;
5157 
5158  /* Add the media identifier if present */
5159  if (!ast_strlen_zero(session_media->mid)) {
5160  attr = pjmedia_sdp_attr_create(inv->pool_prov, "mid", pj_cstr(&stmp, session_media->mid));
5161  pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
5162  }
5163 
5164  ast_trace(-1, "%s: Stream %s added%s%s\n", ast_sip_session_get_name(session),
5165  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5166  S_COR(!ast_strlen_zero(session_media->mid), " with mid ", ""), S_OR(session_media->mid, ""));
5167 
5168  }
5169 
5170  /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */
5171  if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) {
5172  SCOPE_EXIT_EXPR(break, "%s: Stream %s exceeded max pjmedia count of %d\n",
5173  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5174  PJMEDIA_MAX_SDP_MEDIA);
5175  }
5176 
5177  SCOPE_EXIT("%s: Done with %s\n", ast_sip_session_get_name(session),
5178  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5179 
5180  }
5181 
5182  /* Add any bundle groups that are present on the media state */
5183  ast_trace(-1, "%s: Adding bundle groups (if available)\n", ast_sip_session_get_name(session));
5184  if (add_bundle_groups(session, inv->pool_prov, local)) {
5185  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't add bundle groups\n", ast_sip_session_get_name(session));
5186  }
5187 
5188  /* Use the connection details of an available media if possible for SDP level */
5189  ast_trace(-1, "%s: Copying connection details\n", ast_sip_session_get_name(session));
5190 
5191  for (stream = 0; stream < local->media_count; stream++) {
5192  SCOPE_ENTER(4, "%s: Processing media %d\n", ast_sip_session_get_name(session), stream);
5193  if (!local->media[stream]->conn) {
5194  SCOPE_EXIT_EXPR(continue, "%s: Media %d has no connection info\n", ast_sip_session_get_name(session), stream);
5195  }
5196 
5197  if (local->conn) {
5198  if (!pj_strcmp(&local->conn->net_type, &local->media[stream]->conn->net_type) &&
5199  !pj_strcmp(&local->conn->addr_type, &local->media[stream]->conn->addr_type) &&
5200  !pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) {
5201  local->media[stream]->conn = NULL;
5202  }
5203  SCOPE_EXIT_EXPR(continue, "%s: Media %d has good existing connection info\n", ast_sip_session_get_name(session), stream);
5204  }
5205 
5206  /* This stream's connection info will serve as the connection details for SDP level */
5207  local->conn = local->media[stream]->conn;
5208  local->media[stream]->conn = NULL;
5209 
5210  SCOPE_EXIT_EXPR(continue, "%s: Media %d reset\n", ast_sip_session_get_name(session), stream);
5211  }
5212 
5213  /* If no SDP level connection details are present then create some */
5214  if (!local->conn) {
5215  ast_trace(-1, "%s: Creating connection details\n", ast_sip_session_get_name(session));
5216 
5217  local->conn = pj_pool_zalloc(inv->pool_prov, sizeof(struct pjmedia_sdp_conn));
5218  local->conn->net_type = STR_IN;
5219  local->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
5220 
5221  if (!ast_strlen_zero(session->endpoint->media.address)) {
5222  pj_strdup2(inv->pool_prov, &local->conn->addr, session->endpoint->media.address);
5223  } else {
5224  pj_strdup2(inv->pool_prov, &local->conn->addr, ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET()));
5225  }
5226  }
5227 
5228  pj_strassign(&local->origin.net_type, &local->conn->net_type);
5229  pj_strassign(&local->origin.addr_type, &local->conn->addr_type);
5230  pj_strassign(&local->origin.addr, &local->conn->addr);
5231 
5232 end:
5233  SCOPE_EXIT_RTN_VALUE(local, "%s\n", ast_sip_session_get_name(session));
5234 }
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
Definition: logger.h:940
struct ast_sip_endpoint * endpoint
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition: stream.c:337
struct ast_sip_session_media_state * pending_media_state
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
char * mid
Media identifier for this stream (may be shared across multiple streams)
const ast_string_field sdpsession
Definition: res_pjsip.h:762
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
const ast_string_field address
Definition: res_pjsip.h:758
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
#define SCOPE_EXIT_LOG_EXPR(__expr, __log_level,...)
Definition: logger.h:946
char * end
Definition: eagi_proxy.c:73
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_sip_session_media_state * active_media_state
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
Definition: res_pjsip.c:5473
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
const ast_string_field sdpowner
Definition: res_pjsip.h:760
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
struct ast_sip_media_rtp_configuration rtp
Definition: res_pjsip.h:764
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
long int ast_random(void)
Definition: main/utils.c:2064
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define SCOPE_EXIT_EXPR(__expr,...)
Definition: logger.h:834
static int add_sdp_streams(struct ast_sip_session_media *session_media, struct ast_sip_session *session, pjmedia_sdp_session *answer, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
#define LOG_ERROR
Definition: logger.h:285
struct ast_sip_session_media * ast_sip_session_media_state_add(struct ast_sip_session *session, struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
Allocate an ast_session_media and add it to the media state&#39;s vector.
static int add_bundle_groups(struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer)
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
struct ast_stream_topology * topology
Definition: res_pjsip.h:772
struct ast_stream_topology * topology
The media stream topology.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743

◆ datastore_cmp()

static int datastore_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 2888 of file res_pjsip_session.c.

References ast_assert, CMP_MATCH, CMP_STOP, NULL, OBJ_KEY, and ast_datastore::uid.

Referenced by ast_sip_session_alloc().

2889 {
2890  const struct ast_datastore *datastore1 = obj;
2891  const struct ast_datastore *datastore2 = arg;
2892  const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
2893 
2894  ast_assert(datastore1->uid != NULL);
2895  ast_assert(uid2 != NULL);
2896 
2897  return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
2898 }
#define OBJ_KEY
Definition: astobj2.h:1155
#define ast_assert(a)
Definition: utils.h:695
Structure for a data store object.
Definition: datastore.h:68
#define NULL
Definition: resample.c:96
const char * uid
Definition: datastore.h:69

◆ datastore_hash()

static int datastore_hash ( const void *  obj,
int  flags 
)
static

Definition at line 2878 of file res_pjsip_session.c.

References ast_assert, ast_str_hash(), NULL, OBJ_KEY, and ast_datastore::uid.

Referenced by ast_sip_session_alloc().

2879 {
2880  const struct ast_datastore *datastore = obj;
2881  const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
2882 
2883  ast_assert(uid != NULL);
2884 
2885  return ast_str_hash(uid);
2886 }
#define OBJ_KEY
Definition: astobj2.h:1155
#define ast_assert(a)
Definition: utils.h:695
Structure for a data store object.
Definition: datastore.h:68
#define NULL
Definition: resample.c:96
const char * uid
Definition: datastore.h:69
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206

◆ delay_request()

static int delay_request ( struct ast_sip_session session,
ast_sip_session_request_creation_cb  on_request,
ast_sip_session_sdp_creation_cb  on_sdp_creation,
ast_sip_session_response_cb  on_response,
int  generate_new_sdp,
enum delayed_method  method,
struct ast_sip_session_media_state pending_media_state,
struct ast_sip_session_media_state active_media_state,
int  queue_head 
)
static

Definition at line 1591 of file res_pjsip_session.c.

References AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, ast_sip_session_get_name(), ast_sip_session_media_state_free(), DELAYED_METHOD_BYE, delayed_request_alloc(), ast_sip_session::delayed_requests, LOG_ERROR, ast_sip_session_delayed_request::next, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, and SCOPE_EXIT_RTN_VALUE.

Referenced by ast_sip_session_terminate(), reschedule_reinvite(), and sip_session_refresh().

1600 {
1602  on_request, on_sdp_creation, on_response, generate_new_sdp, pending_media_state,
1603  active_media_state);
1604  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
1605 
1606  if (!delay) {
1607  ast_sip_session_media_state_free(pending_media_state);
1608  ast_sip_session_media_state_free(active_media_state);
1609  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1610  }
1611 
1612  if (method == DELAYED_METHOD_BYE || queue_head) {
1613  /* Send BYE as early as possible */
1614  AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1615  } else {
1616  AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1617  }
1619 }
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
Definition: logger.h:940
ast_sip_session_sdp_creation_cb on_sdp_creation
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
struct ast_sip_session_delayed_request * next
const char * method
Definition: res_pjsip.c:4335
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
static struct ast_sip_session_delayed_request * delayed_request_alloc(enum delayed_method method, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state)
Structure used for sending delayed requests.
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
ast_sip_session_response_cb on_response
struct ast_sip_session::@309 delayed_requests
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875

◆ delayed_method2str()

static const char* delayed_method2str ( enum delayed_method  method)
static

Definition at line 1310 of file res_pjsip_session.c.

References DELAYED_METHOD_BYE, DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, and str.

Referenced by invite_proceeding(), invite_terminated(), and send_delayed_request().

1311 {
1312  const char *str = "<unknown>";
1313 
1314  switch (method) {
1315  case DELAYED_METHOD_INVITE:
1316  str = "INVITE";
1317  break;
1318  case DELAYED_METHOD_UPDATE:
1319  str = "UPDATE";
1320  break;
1321  case DELAYED_METHOD_BYE:
1322  str = "BYE";
1323  break;
1324  }
1325 
1326  return str;
1327 }
const char * str
Definition: app_jack.c:147
const char * method
Definition: res_pjsip.c:4335

◆ delayed_request_alloc()

static struct ast_sip_session_delayed_request* delayed_request_alloc ( enum delayed_method  method,
ast_sip_session_request_creation_cb  on_request_creation,
ast_sip_session_sdp_creation_cb  on_sdp_creation,
ast_sip_session_response_cb  on_response,
int  generate_new_sdp,
struct ast_sip_session_media_state pending_media_state,
struct ast_sip_session_media_state active_media_state 
)
static

Definition at line 1355 of file res_pjsip_session.c.

References ast_sip_session_delayed_request::active_media_state, ast_calloc, ast_sip_session_delayed_request::generate_new_sdp, ast_sip_session_delayed_request::method, method, NULL, ast_sip_session_delayed_request::on_request_creation, ast_sip_session_delayed_request::on_response, ast_sip_session_delayed_request::on_sdp_creation, and ast_sip_session_delayed_request::pending_media_state.

Referenced by delay_request().

1363 {
1364  struct ast_sip_session_delayed_request *delay = ast_calloc(1, sizeof(*delay));
1365 
1366  if (!delay) {
1367  return NULL;
1368  }
1369  delay->method = method;
1372  delay->on_response = on_response;
1376  return delay;
1377 }
ast_sip_session_sdp_creation_cb on_sdp_creation
struct ast_sip_session_media_state * pending_media_state
ast_sip_session_request_creation_cb on_request_creation
#define NULL
Definition: resample.c:96
struct ast_sip_session_media_state * active_media_state
const char * method
Definition: res_pjsip.c:4335
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
Structure used for sending delayed requests.
ast_sip_session_response_cb on_response

◆ delayed_request_free()

static void delayed_request_free ( struct ast_sip_session_delayed_request delay)
static

Definition at line 1379 of file res_pjsip_session.c.

References ast_sip_session_delayed_request::active_media_state, ast_free, ast_sip_session_media_state_free(), and ast_sip_session_delayed_request::pending_media_state.

Referenced by ast_sip_session_terminate(), invite_proceeding(), invite_terminated(), and session_destructor().

1380 {
1383  ast_free(delay);
1384 }
struct ast_sip_session_media_state * pending_media_state
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
struct ast_sip_session_media_state * active_media_state
#define ast_free(a)
Definition: astmm.h:182

◆ does_method_match()

static pj_bool_t does_method_match ( const pj_str_t *  message_method,
const char *  supplement_method 
)
static

Definition at line 4129 of file res_pjsip_session.c.

References ast_strlen_zero, and method.

Referenced by handle_incoming_request(), handle_incoming_response(), handle_outgoing_request(), handle_outgoing_response(), and has_supplement().

4130 {
4131  pj_str_t method;
4132 
4133  if (ast_strlen_zero(supplement_method)) {
4134  return PJ_TRUE;
4135  }
4136 
4137  pj_cstr(&method, supplement_method);
4138 
4139  return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
4140 }
static const pjsip_method message_method
Definition: res_pjsip.c:4332
#define ast_strlen_zero(foo)
Definition: strings.h:52
const char * method
Definition: res_pjsip.c:4335

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session* generate_session_refresh_sdp ( struct ast_sip_session session)
static

Definition at line 1621 of file res_pjsip_session.c.

References ast_sip_session_get_name(), create_local_sdp(), ast_sip_session::inv_session, NULL, SCOPE_ENTER, and SCOPE_EXIT_RTN_VALUE.

Referenced by sip_session_refresh().

1622 {
1623  pjsip_inv_session *inv_session = session->inv_session;
1624  const pjmedia_sdp_session *previous_sdp = NULL;
1625  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
1626 
1627  if (inv_session->neg) {
1628  if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
1629  pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
1630  } else {
1631  pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
1632  }
1633  }
1634  SCOPE_EXIT_RTN_VALUE(create_local_sdp(inv_session, session, previous_sdp));
1635 }
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)

◆ get_destination()

static enum sip_get_destination_result get_destination ( struct ast_sip_session session,
pjsip_rx_data *  rdata 
)
static

Determine where in the dialplan a call should go.

This uses the username in the request URI to try to match an extension in the endpoint's configured context in order to route the call.

Parameters
sessionThe inbound SIP session
rdataThe SIP INVITE

Definition at line 3666 of file res_pjsip_session.c.

References ast_sip_endpoint::allow_overlap, ao2_ref, ast_canmatch_extension(), ast_copy_pj_str(), ast_exists_extension(), ast_get_chan_features_pickup_config(), ast_log, ast_sip_session_get_name(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_strdupa, ast_sip_endpoint::context, ast_sip_session::endpoint, ast_sip_session::exten, ast_sip_session::inv_session, LOG_ERROR, NULL, ast_features_pickup_config::pickupexten, ast_sip_session::request_uri, SIP_GET_DEST_EXTEN_FOUND, SIP_GET_DEST_EXTEN_NOT_FOUND, SIP_GET_DEST_EXTEN_PARTIAL, and SIP_GET_DEST_UNSUPPORTED_URI.

Referenced by new_invite().

3667 {
3668  pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
3669  pjsip_sip_uri *sip_ruri;
3670  struct ast_features_pickup_config *pickup_cfg;
3671  const char *pickupexten;
3672 
3673  if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
3675  }
3676 
3677  sip_ruri = pjsip_uri_get_uri(ruri);
3678  ast_copy_pj_str(session->exten, &sip_ruri->user, sizeof(session->exten));
3679 
3680  /*
3681  * We may want to match in the dialplan without any user
3682  * options getting in the way.
3683  */
3685 
3686  pickup_cfg = ast_get_chan_features_pickup_config(NULL); /* session->channel doesn't exist yet, using NULL */
3687  if (!pickup_cfg) {
3688  ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",
3689  ast_sip_session_get_name(session));
3690  pickupexten = "";
3691  } else {
3692  pickupexten = ast_strdupa(pickup_cfg->pickupexten);
3693  ao2_ref(pickup_cfg, -1);
3694  }
3695 
3696  if (!strcmp(session->exten, pickupexten) ||
3697  ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
3698  /*
3699  * Save off the INVITE Request-URI in case it is
3700  * needed: CHANNEL(pjsip,request_uri)
3701  */
3702  session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri);
3703 
3704  return SIP_GET_DEST_EXTEN_FOUND;
3705  }
3706 
3707  /*
3708  * Check for partial match via overlap dialling (if enabled)
3709  */
3710  if (session->endpoint->allow_overlap && (
3711  !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
3712  ast_canmatch_extension(NULL, session->endpoint->context, session->exten, 1, NULL))) {
3713  /* Overlap partial match */
3715  }
3716 
3718 }
struct ast_sip_endpoint * endpoint
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
struct ast_features_pickup_config * ast_get_chan_features_pickup_config(struct ast_channel *chan)
Get the pickup configuration options for a channel.
pjsip_uri * request_uri
const ast_string_field context
Definition: res_pjsip.h:815
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
char exten[AST_MAX_EXTENSION]
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4194
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
#define LOG_ERROR
Definition: logger.h:285
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
unsigned int allow_overlap
Definition: res_pjsip.h:893
Configuration relating to call pickup.

◆ get_mid_bundle_group()

static int get_mid_bundle_group ( const pjmedia_sdp_session *  sdp,
const char *  mid 
)
static

Definition at line 612 of file res_pjsip_session.c.

References ast_copy_pj_str(), ast_sip_session_media::bundle_group, strsep(), and value.

Referenced by set_mid_and_bundle_group().

613 {
614  int bundle_group = 0;
615  int index;
616 
617  for (index = 0; index < sdp->attr_count; ++index) {
618  pjmedia_sdp_attr *attr = sdp->attr[index];
619  char value[pj_strlen(&attr->value) + 1], *mids = value, *attr_mid;
620 
621  if (pj_strcmp2(&attr->name, "group") || pj_strncmp2(&attr->value, "BUNDLE", 6)) {
622  continue;
623  }
624 
625  ast_copy_pj_str(value, &attr->value, sizeof(value));
626 
627  /* Skip the BUNDLE at the front */
628  mids += 7;
629 
630  while ((attr_mid = strsep(&mids, " "))) {
631  if (!strcmp(attr_mid, mid)) {
632  /* The ordering of attributes determines our internal identification of the bundle group based on number,
633  * with -1 being not in a bundle group. Since this is only exposed internally for response purposes it's
634  * actually even fine if things move around.
635  */
636  return bundle_group;
637  }
638  }
639 
640  bundle_group++;
641  }
642 
643  return -1;
644 }
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
int value
Definition: syslog.c:37
char * strsep(char **str, const char *delims)

◆ handle_incoming()

static int handle_incoming ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
enum ast_sip_session_response_priority  response_priority 
)
static

Definition at line 4469 of file res_pjsip_session.c.

References handle_incoming_request(), and handle_incoming_response().

Referenced by handle_incoming_before_media(), session_inv_on_redirected(), and session_inv_on_tsx_state_changed().

4471 {
4472  if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
4473  handle_incoming_request(session, rdata);
4474  } else {
4475  handle_incoming_response(session, rdata, response_priority);
4476  }
4477 
4478  return 0;
4479 }
static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)

◆ handle_incoming_before_media()

static void handle_incoming_before_media ( pjsip_inv_session *  inv,
struct ast_sip_session session,
pjsip_rx_data *  rdata 
)
static

Definition at line 4583 of file res_pjsip_session.c.

References ast_debug, AST_SIP_SESSION_BEFORE_MEDIA, ast_sip_session_get_name(), ast_sip_session_send_request(), handle_incoming(), and NULL.

Referenced by session_inv_on_state_changed().

4585 {
4586  pjsip_msg *msg;
4587  ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4588  "request" : "response");
4589 
4590 
4592  msg = rdata->msg_info.msg;
4593  if (msg->type == PJSIP_REQUEST_MSG
4594  && msg->line.req.method.id == PJSIP_ACK_METHOD
4595  && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
4596  pjsip_tx_data *tdata;
4597 
4598  /*
4599  * SDP negotiation failed on an incoming call that delayed
4600  * negotiation and then gave us an invalid SDP answer. We
4601  * need to send a BYE to end the call because of the invalid
4602  * SDP answer.
4603  */
4604  ast_debug(1,
4605  "%s: Ending session due to incomplete SDP negotiation. %s\n",
4606  ast_sip_session_get_name(session),
4607  pjsip_rx_data_get_info(rdata));
4608  if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
4609  && tdata) {
4610  ast_sip_session_send_request(session, tdata);
4611  }
4612  }
4613 }
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.

◆ handle_incoming_request()

static void handle_incoming_request ( struct ast_sip_session session,
pjsip_rx_data *  rdata 
)
static

Definition at line 4398 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_session_get_name(), does_method_match(), ast_sip_session_supplement::incoming_request, ast_sip_session_supplement::method, SCOPE_ENTER, SCOPE_EXIT, and ast_sip_session::supplements.

Referenced by handle_incoming(), and new_invite().

4399 {
4400  struct ast_sip_session_supplement *supplement;
4401  struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4402  SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session), (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4403 
4404  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4405  if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
4406  if (supplement->incoming_request(session, rdata)) {
4407  break;
4408  }
4409  }
4410  }
4411 
4412  SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
4413 }
int(* incoming_request)(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Called on incoming SIP request This method can indicate a failure in processing in its return...
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_sip_session::@308 supplements
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
A supplement to SIP message processing.
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)

◆ handle_incoming_response()

static void handle_incoming_response ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
enum ast_sip_session_response_priority  response_priority 
)
static

Definition at line 4449 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_session_get_name(), does_method_match(), ast_sip_session_supplement::incoming_response, ast_sip_session_supplement::method, ast_sip_session_supplement::response_priority, SCOPE_ENTER, SCOPE_EXIT, and ast_sip_session::supplements.

Referenced by handle_incoming().

4451 {
4452  struct ast_sip_session_supplement *supplement;
4453  struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4454  SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4455  status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4456 
4457  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4458  if (!(supplement->response_priority & response_priority)) {
4459  continue;
4460  }
4461  if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4462  supplement->incoming_response(session, rdata);
4463  }
4464  }
4465 
4466  SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
4467 }
enum ast_sip_session_response_priority response_priority
void(* incoming_response)(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Called on an incoming SIP response This method is always called from a SIP servant thread...
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_sip_session::@308 supplements
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
A supplement to SIP message processing.
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
jack_status_t status
Definition: app_jack.c:146

◆ handle_incoming_sdp()

static int handle_incoming_sdp ( struct ast_sip_session session,
const pjmedia_sdp_session *  sdp 
)
static

Definition at line 764 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ao2_cleanup, ao2_find, ast_asprintf, ast_codec_media_type2str(), ast_copy_pj_str(), ast_free, AST_LIST_TRAVERSE, AST_MEDIA_TYPE_END, ast_media_type_from_str(), ast_sip_session_get_name(), ast_sip_session_is_pending_stream_default(), ast_sip_session_media_state_add(), ast_str_tmp, ast_stream_alloc(), ast_stream_free(), ast_stream_get_metadata(), ast_stream_get_name(), ast_stream_get_state(), ast_stream_set_metadata(), ast_stream_set_state(), AST_STREAM_STATE_INACTIVE, AST_STREAM_STATE_RECVONLY, AST_STREAM_STATE_REMOVED, AST_STREAM_STATE_SENDONLY, AST_STREAM_STATE_SENDRECV, ast_stream_to_str(), ast_stream_topology_alloc(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_set_stream(), ast_strlen_zero, ast_trace, end, ast_sip_session::endpoint, handler(), ast_sip_session_media::handler, ast_sip_session_sdp_handler::id, ast_sip_session::inv_session, is_stream_limitation_reached(), LOG_ERROR, ast_sip_session_sdp_handler::negotiate_incoming_sdp_stream, NULL, OBJ_KEY, ast_sip_session::pending_media_state, RAII_VAR, remove_stream_from_bundle(), SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG_EXPR, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, session_media_set_handler(), set_mid_and_bundle_group(), set_remote_mslabel_and_stream_group(), ast_sip_session_media_state::topology, and type.

Referenced by new_invite(), and session_inv_on_rx_offer().

765 {
766  int i;
767  int handled = 0;
768  int type_streams[AST_MEDIA_TYPE_END] = {0};
769  SCOPE_ENTER(3, "%s: Media count: %d\n", ast_sip_session_get_name(session), sdp->media_count);
770 
771  if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
772  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to handle incoming SDP. Session has been already disconnected\n",
773  ast_sip_session_get_name(session));
774  }
775 
776  /* It is possible for SDP deferral to have already created a pending topology */
777  if (!session->pending_media_state->topology) {
779  if (!session->pending_media_state->topology) {
780  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc pending topology\n",
781  ast_sip_session_get_name(session));
782  }
783  }
784 
785  for (i = 0; i < sdp->media_count; ++i) {
786  /* See if there are registered handlers for this media stream type */
787  char media[20];
789  RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
790  struct ast_sip_session_media *session_media = NULL;
791  int res;
792  enum ast_media_type type;
793  struct ast_stream *stream = NULL;
794  pjmedia_sdp_media *remote_stream = sdp->media[i];
795  SCOPE_ENTER(4, "%s: Processing stream %d\n", ast_sip_session_get_name(session), i);
796 
797  /* We need a null-terminated version of the media string */
798  ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
799  type = ast_media_type_from_str(media);
800 
801  /* See if we have an already existing stream, which can occur from SDP deferral checking */
804  ast_trace(-1, "%s: Using existing pending stream %s\n", ast_sip_session_get_name(session),
805  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
806  }
807  if (!stream) {
808  struct ast_stream *existing_stream = NULL;
809  char *stream_name = NULL, *stream_name_allocated = NULL;
810  const char *stream_label = NULL;
811 
812  if (session->active_media_state->topology &&
814  existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
815  ast_trace(-1, "%s: Found existing active stream %s\n", ast_sip_session_get_name(session),
816  ast_str_tmp(128, ast_stream_to_str(existing_stream, &STR_TMP)));
817 
818  if (ast_stream_get_state(existing_stream) != AST_STREAM_STATE_REMOVED) {
819  stream_name = (char *)ast_stream_get_name(existing_stream);
820  stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
821  }
822  }
823 
824  if (ast_strlen_zero(stream_name)) {
825  if (ast_asprintf(&stream_name_allocated, "%s-%d", ast_codec_media_type2str(type), i) < 0) {
826  handled = 0;
827  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream name\n",
828  ast_sip_session_get_name(session));
829 
830  }
831  stream_name = stream_name_allocated;
832  ast_trace(-1, "%s: Using %s for new stream name\n", ast_sip_session_get_name(session),
833  stream_name);
834  }
835 
836  stream = ast_stream_alloc(stream_name, type);
837  ast_free(stream_name_allocated);
838  if (!stream) {
839  handled = 0;
840  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream\n",
841  ast_sip_session_get_name(session));
842  }
843 
844  if (!ast_strlen_zero(stream_label)) {
845  ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
846  ast_trace(-1, "%s: Using %s for new stream label\n", ast_sip_session_get_name(session),
847  stream_label);
848 
849  }
850 
851  if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
852  ast_stream_free(stream);
853  handled = 0;
854  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't set stream in topology\n",
855  ast_sip_session_get_name(session));
856  }
857 
858  /* For backwards compatibility with the core the default audio stream is always sendrecv */
859  if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
860  if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
861  /* Stream state reflects our state of a stream, so in the case of
862  * sendonly and recvonly we store the opposite since that is what ours
863  * is.
864  */
866  } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
868  } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
870  } else {
872  }
873  } else {
875  }
876  ast_trace(-1, "%s: Using new stream %s\n", ast_sip_session_get_name(session),
877  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
878  }
879 
880  session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
881  if (!session_media) {
882  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc session media\n",
883  ast_sip_session_get_name(session));
884  }
885 
886  /* If this stream is already declined mark it as such, or mark it as such if we've reached the limit */
887  if (!remote_stream->desc.port || is_stream_limitation_reached(type, session->endpoint, type_streams)) {
888  remove_stream_from_bundle(session_media, stream);
889  SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s'\n",
890  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
891  }
892 
893  set_mid_and_bundle_group(session, session_media, sdp, remote_stream);
894  set_remote_mslabel_and_stream_group(session, session_media, sdp, remote_stream, stream);
895 
896  if (session_media->handler) {
897  handler = session_media->handler;
898  ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
899  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
900  session_media->handler->id);
901  res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
902  if (res < 0) {
903  /* Catastrophic failure. Abort! */
904  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
905  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
906  } else if (res == 0) {
907  remove_stream_from_bundle(session_media, stream);
908  SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s\n",
909  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
910  } else if (res > 0) {
911  handled = 1;
912  ++type_streams[type];
913  /* Handled by this handler. Move to the next stream */
914  SCOPE_EXIT_EXPR(continue, "%s: Media stream %s handled by %s\n",
915  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
916  session_media->handler->id);
917  }
918  }
919 
920  handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
921  if (!handler_list) {
922  SCOPE_EXIT_EXPR(continue, "%s: Media stream %s has no registered handlers\n",
923  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
924  }
925  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
926  if (handler == session_media->handler) {
927  continue;
928  }
929  ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
930  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
931  handler->id);
932 
933  res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
934  if (res < 0) {
935  /* Catastrophic failure. Abort! */
936  handled = 0;
937  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
938  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
939  } else if (res == 0) {
940  remove_stream_from_bundle(session_media, stream);
941  ast_trace(-1, "%s: Declining incoming SDP media stream %s\n",
942  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
943  continue;
944  } else if (res > 0) {
945  session_media_set_handler(session_media, handler);
946  handled = 1;
947  ++type_streams[type];
948  ast_trace(-1, "%s: Media stream %s handled by %s\n",
949  ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
950  session_media->handler->id);
951  break;
952  }
953  }
954 
955  SCOPE_EXIT("%s: Done with stream %s\n", ast_sip_session_get_name(session),
956  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
957  }
958 
959 end:
960  SCOPE_EXIT_RTN_VALUE(handled ? 0 : -1, "%s: Handled? %s\n", ast_sip_session_get_name(session),
961  handled ? "yes" : "no");
962 }
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
Definition: logger.h:940
static const char type[]
Definition: chan_ooh323.c:109
static int set_mid_and_bundle_group(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
struct ast_sip_endpoint * endpoint
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition: stream.c:337
struct ast_sip_session_media_state * pending_media_state
#define OBJ_KEY
Definition: astobj2.h:1155
static int is_stream_limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)
A handler for SDPs in SIP sessions.
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
enum ast_media_type ast_media_type_from_str(const char *media_type_str)
Conversion function to take a media string and convert it to a media type.
Definition: codec.c:363
Set when the stream has been removed/declined.
Definition: stream.h:78
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
#define SCOPE_EXIT_LOG_EXPR(__expr, __log_level,...)
Definition: logger.h:946
char * end
Definition: eagi_proxy.c:73
struct pjsip_inv_session * inv_session
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
#define ast_strlen_zero(foo)
Definition: strings.h:52
int(* negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, int index, struct ast_stream *asterisk_stream)
Set session details based on a stream in an incoming SDP offer or answer.
struct ast_sip_session_media_state * active_media_state
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *session, const struct ast_stream *stream)
Determines if a provided pending stream will be the default stream or not.
static void session_media_set_handler(struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
Set an SDP stream handler for a corresponding session media.
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define SCOPE_EXIT_EXPR(__expr,...)
Definition: logger.h:834
static void remove_stream_from_bundle(struct ast_sip_session_media *session_media, struct ast_stream *stream)
Set when the stream is sending and receiving media.
Definition: stream.h:82
#define LOG_ERROR
Definition: logger.h:285
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
struct ast_sip_session_media * ast_sip_session_media_state_add(struct ast_sip_session *session, struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
Allocate an ast_session_media and add it to the media state&#39;s vector.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Set when the stream is sending media only.
Definition: stream.h:86
#define ast_free(a)
Definition: astmm.h:182
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
static void set_remote_mslabel_and_stream_group(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream, struct ast_stream *asterisk_stream)
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
Definition: stream.c:460
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition: stream.c:423
ast_media_type
Types of media.
Definition: codec.h:30
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
Set when the stream is receiving media only.
Definition: stream.h:90
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373

◆ handle_negotiated_sdp()

static int handle_negotiated_sdp ( struct ast_sip_session session,
const pjmedia_sdp_session *  local,
const pjmedia_sdp_session *  remote 
)
static

Definition at line 1063 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ast_channel_internal_fd_clear(), ast_channel_internal_fd_set(), ast_channel_lock, ast_channel_set_stream_topology(), ast_channel_stream_topology_changed_externally(), ast_channel_unlock, AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED, AST_EXTENDED_FDS, AST_FRAME_CONTROL, ast_log, AST_MEDIA_TYPE_IMAGE, ast_null_frame, ast_queue_frame(), ast_sip_session_get_name(), ast_sip_session_media_state_clone(), ast_sip_session_media_state_free(), ast_sip_session_media_state_reset(), ast_sip_session_media_stats_save(), ast_stream_get_state(), ast_stream_set_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_clone(), ast_stream_topology_equal(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), AST_VECTOR_GET, AST_VECTOR_GET_ADDR, AST_VECTOR_SIZE, ast_sip_session_media::changed, ast_sip_session::channel, ast_sip_session_media_state::default_session, ast_sip_session_media_read_callback_state::fd, handle_negotiated_sdp_session_media(), ast_sip_session_media::handler, ast_sip_session::inv_session, LOG_WARNING, NULL, ast_sip_session::pending_media_state, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session_media_set_handler(), SWAP, and ast_sip_session_media_state::topology.

Referenced by session_inv_on_media_update().

1064 {
1065  int i;
1066  struct ast_stream_topology *topology;
1067  unsigned int changed = 0; /* 0 = unchanged, 1 = new source, 2 = new topology */
1068  SCOPE_ENTER(1, "%s\n", ast_sip_session_get_name(session));
1069 
1070  if (!session->pending_media_state->topology) {
1071  if (session->active_media_state->topology) {
1072  /*
1073  * This happens when we have negotiated media after receiving a 183,
1074  * and we're now receiving a 200 with a new SDP. In this case, there
1075  * is active_media_state, but the pending_media_state has been reset.
1076  */
1077  struct ast_sip_session_media_state *active_media_state_clone;
1078 
1079  active_media_state_clone =
1081  if (!active_media_state_clone) {
1082  ast_log(LOG_WARNING, "%s: Unable to clone active media state\n",
1083  ast_sip_session_get_name(session));
1084  return -1;
1085  }
1086 
1088  session->pending_media_state = active_media_state_clone;
1089  } else {
1090  ast_log(LOG_WARNING, "%s: No pending or active media state\n",
1091  ast_sip_session_get_name(session));
1092  return -1;
1093  }
1094  }
1095 
1096  /* If we're handling negotiated streams, then we should already have set
1097  * up session media instances (and Asterisk streams) that correspond to
1098  * the local SDP, and there should be the same number of session medias
1099  * and streams as there are local SDP streams
1100  */
1101  if (ast_stream_topology_get_count(session->pending_media_state->topology) != local->media_count
1102  || AST_VECTOR_SIZE(&session->pending_media_state->sessions) != local->media_count) {
1103  ast_log(LOG_WARNING, "%s: Local SDP contains %d media streams while we expected it to contain %u\n",
1104  ast_sip_session_get_name(session),
1105  ast_stream_topology_get_count(session->pending_media_state->topology), local->media_count);
1106  SCOPE_EXIT_RTN_VALUE(-1, "Media stream count mismatch\n");
1107  }
1108 
1109  for (i = 0; i < local->media_count; ++i) {
1110  struct ast_sip_session_media *session_media;
1111  struct ast_stream *stream;
1112 
1113  if (!remote->media[i]) {
1114  continue;
1115  }
1116 
1117  session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i);
1119 
1120  /* Make sure that this stream is in the correct state. If we need to change
1121  * the state to REMOVED, then our work here is done, so go ahead and move on
1122  * to the next stream.
1123  */
1124  if (!remote->media[i]->desc.port) {
1126  continue;
1127  }
1128 
1129  /* If the stream state is REMOVED, nothing needs to be done, so move on to the
1130  * next stream. This can occur if an internal thing has requested it to be
1131  * removed, or if we remove it as a result of the stream limit being reached.
1132  */
1134  /*
1135  * Defer removing the handler until we are ready to activate
1136  * the new topology. The channel's thread may still be using
1137  * the stream and we could crash before we are ready.
1138  */
1139  continue;
1140  }
1141 
1142  if (handle_negotiated_sdp_session_media(session_media, session, local, remote, i, stream)) {
1143  SCOPE_EXIT_RTN_VALUE(-1, "Unable to handle negotiated session media\n");
1144  }
1145 
1146  changed |= session_media->changed;
1147  session_media->changed = 0;
1148  }
1149 
1150  /* Apply the pending media state to the channel and make it active */
1151  ast_channel_lock(session->channel);
1152 
1153  /* Now update the stream handler for any declined/removed streams */
1154  for (i = 0; i < local->media_count; ++i) {
1155  struct ast_sip_session_media *session_media;
1156  struct ast_stream *stream;
1157 
1158  if (!remote->media[i]) {
1159  continue;
1160  }
1161 
1162  session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i);
1164 
1166  && session_media->handler) {
1167  /*
1168  * This stream is no longer being used and the channel's thread
1169  * is held off because we have the channel lock so release any
1170  * resources the handler may have on it.
1171  */
1172  session_media_set_handler(session_media, NULL);
1173  }
1174  }
1175 
1176  /* Update the topology on the channel to match the accepted one */
1178  if (topology) {
1179  ast_channel_set_stream_topology(session->channel, topology);
1180  /* If this is a remotely done renegotiation that has changed the stream topology notify what is
1181  * currently handling this channel. Note that fax uses its own process, so if we are transitioning
1182  * between audio and fax or vice versa we don't notify.
1183  */
1184  if (pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_FALSE &&
1185  session->active_media_state && session->active_media_state->topology &&
1186  !ast_stream_topology_equal(session->active_media_state->topology, topology) &&
1189  changed = 2;
1190  }
1191  }
1192 
1193  /* Remove all current file descriptors from the channel */
1194  for (i = 0; i < AST_VECTOR_SIZE(&session->active_media_state->read_callbacks); ++i) {
1196  }
1197 
1198  /* Add all the file descriptors from the pending media state */
1199  for (i = 0; i < AST_VECTOR_SIZE(&session->pending_media_state->read_callbacks); ++i) {
1200  struct ast_sip_session_media_read_callback_state *callback_state;
1201 
1202  callback_state = AST_VECTOR_GET_ADDR(&session->pending_media_state->read_callbacks, i);
1203  ast_channel_internal_fd_set(session->channel, i + AST_EXTENDED_FDS, callback_state->fd);
1204  }
1205 
1206  /* Active and pending flip flop as needed */
1208  SWAP(session->active_media_state, session->pending_media_state);
1210 
1211  ast_channel_unlock(session->channel);
1212 
1213  if (changed == 1) {
1214  struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED };
1215 
1216  ast_queue_frame(session->channel, &f);
1217  } else if (changed == 2) {
1219  } else {
1221  }
1222 
1224 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Structure which contains media state information (streams, sessions)
void ast_channel_internal_fd_clear(struct ast_channel *chan, int which)
struct ast_sip_session_media_state * pending_media_state
#define LOG_WARNING
Definition: logger.h:274
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
#define SWAP(a, b)
Definition: utils.h:230
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
static int handle_negotiated_sdp_session_media(struct ast_sip_session_media *session_media, struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
struct pjsip_inv_session * inv_session
struct ast_sip_session_media_state * active_media_state
#define ast_log
Definition: astobj2.c:42
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:670
struct ast_channel * channel
static void session_media_set_handler(struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
Set an SDP stream handler for a corresponding session media.
Structure which contains read callback information.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1139
int fd
The file descriptor itself.
#define AST_EXTENDED_FDS
Definition: channel.h:196
struct ast_stream_topology * ast_channel_set_stream_topology(struct ast_channel *chan, struct ast_stream_topology *topology)
Set the topology of streams on a channel.
int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right)
Compare two stream topologies to see if they are equal.
Definition: stream.c:696
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void ast_sip_session_media_stats_save(struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
Save a media stats.
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
struct ast_sip_session_media_state * ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state)
Clone a media state.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
unsigned int changed
The underlying session has been changed in some fashion.
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
Data structure associated with a single frame of data.
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value)
int ast_channel_stream_topology_changed_externally(struct ast_channel *chan)
Provide notice from a channel that the topology has changed on it as a result of the remote party ren...
Definition: channel.c:11209
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ handle_negotiated_sdp_session_media()

static int handle_negotiated_sdp_session_media ( struct ast_sip_session_media session_media,
struct ast_sip_session session,
const pjmedia_sdp_session *  local,
const pjmedia_sdp_session *  remote,
int  index,
struct ast_stream asterisk_stream 
)
static

Definition at line 964 of file res_pjsip_session.c.

References ao2_cleanup, ao2_find, ast_sip_session_sdp_handler::apply_negotiated_sdp_stream, ast_codec_media_type2str(), ast_copy_pj_str(), ast_debug, AST_LIST_TRAVERSE, ast_sip_session_get_name(), ast_sip_session_is_pending_stream_default(), ast_stream_set_state(), AST_STREAM_STATE_INACTIVE, AST_STREAM_STATE_RECVONLY, AST_STREAM_STATE_SENDONLY, AST_STREAM_STATE_SENDRECV, handler(), ast_sip_session_media::handler, ast_sip_session_sdp_handler::id, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session_media_set_handler(), set_mid_and_bundle_group(), set_remote_mslabel_and_stream_group(), ast_sip_session_sdp_handler::stream_stop, and ast_sip_session_media::type.

Referenced by handle_negotiated_sdp().

967 {
968  /* See if there are registered handlers for this media stream type */
969  struct pjmedia_sdp_media *local_stream = local->media[index];
970  char media[20];
972  RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
973  int res;
974  SCOPE_ENTER(1, "%s\n", session ? ast_sip_session_get_name(session) : "unknown");
975 
976  /* We need a null-terminated version of the media string */
977  ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media));
978 
979  /* For backwards compatibility we only reflect the stream state correctly on
980  * the non-default streams and any non-audio streams. This is because the stream
981  * state of the default audio stream is also used for signaling that someone has
982  * placed us on hold. This situation is not handled currently and can result in
983  * the remote side being sorted of placed on hold too.
984  */
985  if (!ast_sip_session_is_pending_stream_default(session, asterisk_stream) || strcmp(media, "audio")) {
986  /* Determine the state of the stream based on our local SDP */
987  if (pjmedia_sdp_media_find_attr2(local_stream, "sendonly", NULL)) {
989  } else if (pjmedia_sdp_media_find_attr2(local_stream, "recvonly", NULL)) {
991  } else if (pjmedia_sdp_media_find_attr2(local_stream, "inactive", NULL)) {
993  } else {
995  }
996  } else {
998  }
999 
1000  set_mid_and_bundle_group(session, session_media, remote, remote->media[index]);
1001  set_remote_mslabel_and_stream_group(session, session_media, remote, remote->media[index], asterisk_stream);
1002 
1003  handler = session_media->handler;
1004  if (handler) {
1005  ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1006  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1007  handler->id);
1008  res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
1009  if (res >= 0) {
1010  ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1011  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1012  handler->id);
1013  SCOPE_EXIT_RTN_VALUE(0, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1014  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1015  handler->id);
1016  }
1017  SCOPE_EXIT_RTN_VALUE(-1, "%s: Failed to apply negotiated SDP media stream '%s' using %s SDP handler\n",
1018  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1019  handler->id);
1020  }
1021 
1022  handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
1023  if (!handler_list) {
1024  ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
1025  return -1;
1026  }
1027  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
1028  if (handler == session_media->handler) {
1029  continue;
1030  }
1031  ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1032  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1033  handler->id);
1034  res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
1035  if (res < 0) {
1036  /* Catastrophic failure. Abort! */
1037  SCOPE_EXIT_RTN_VALUE(-1, "%s: Handler '%s' returned %d\n",
1038  ast_sip_session_get_name(session), handler->id, res);
1039  }
1040  if (res > 0) {
1041  ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1042  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1043  handler->id);
1044  /* Handled by this handler. Move to the next stream */
1045  session_media_set_handler(session_media, handler);
1046  SCOPE_EXIT_RTN_VALUE(0, "%s: Handler '%s' handled this sdp stream\n",
1047  ast_sip_session_get_name(session), handler->id);
1048  }
1049  }
1050 
1051  res = 0;
1052  if (session_media->handler && session_media->handler->stream_stop) {
1053  ast_debug(4, "%s: Stopping SDP media stream '%s' as it is not currently negotiated\n",
1054  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type));
1055  session_media->handler->stream_stop(session_media);
1056  }
1057 
1058  SCOPE_EXIT_RTN_VALUE(0, "%s: Media type '%s' %s\n",
1059  ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
1060  res ? "not negotiated. Stopped" : "handled");
1061 }
static int set_mid_and_bundle_group(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
#define OBJ_KEY
Definition: astobj2.h:1155
A handler for SDPs in SIP sessions.
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_sip_session_sdp_handler * next
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *session, const struct ast_stream *stream)
Determines if a provided pending stream will be the default stream or not.
static void session_media_set_handler(struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
Set an SDP stream handler for a corresponding session media.
Set when the stream is sending and receiving media.
Definition: stream.h:82
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Set when the stream is sending media only.
Definition: stream.h:86
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
static void set_remote_mslabel_and_stream_group(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream, struct ast_stream *asterisk_stream)
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
enum ast_media_type type
Media type of this session media.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
Set when the stream is receiving media only.
Definition: stream.h:90
int(* apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
Apply a negotiated SDP media stream.
void(* stream_stop)(struct ast_sip_session_media *session_media)
Stop a session_media created by this handler but do not destroy resources.

◆ handle_new_invite_request()

static void handle_new_invite_request ( pjsip_rx_data *  rdata)
static

Definition at line 4050 of file res_pjsip_session.c.

References ao2_cleanup, ao2_ref, ast_alloca, ast_assert, ast_pjsip_rdata_get_endpoint(), ast_sip_session_alloc(), ast_sip_session_get_name(), AST_SIP_SESSION_INCOMING_CALL, ast_taskprocessor_is_task(), ast_sip_session::call_direction, ast_sip_session::endpoint, ast_sip_session::inv_session, new_invite(), new_invite_initial_answer(), NULL, pre_session_setup(), RAII_VAR, new_invite::rdata, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_RTN, ast_sip_session::serializer, session, new_invite::session, and TRACE_ATLEAST.

Referenced by session_on_rx_request().

4051 {
4052  RAII_VAR(struct ast_sip_endpoint *, endpoint,
4054  pjsip_inv_session *inv_session = NULL;
4055  struct ast_sip_session *session;
4056  struct new_invite invite;
4057  char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4058  int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4059  SCOPE_ENTER(1, "Request: %s\n", res ? req_uri : "");
4060 
4061  ast_assert(endpoint != NULL);
4062 
4063  inv_session = pre_session_setup(rdata, endpoint);
4064  if (!inv_session) {
4065  /* pre_session_setup() returns a response on failure */
4066  SCOPE_EXIT_RTN("Failure in pre session setup\n");
4067  }
4068 
4069  /*
4070  * Upon a successful pre_session_setup the associated dialog is returned locked
4071  * and with an added reference. Well actually two references. One added when the
4072  * dialog itself was created, and another added when the pjsip invite session was
4073  * created and the dialog was added to it.
4074  *
4075  * In order to ensure the dialog's, and any of its internal attributes, lifetimes
4076  * we'll hold the lock and maintain the reference throughout the entire new invite
4077  * handling process. See ast_sip_create_dialog_uas_locked for more details but,
4078  * basically we do this to make sure a transport failure does not destroy the dialog
4079  * and/or transaction out from underneath us between pjsip calls. Alternatively, we
4080  * could probably release the lock if we needed to, but then we'd have to re-lock and
4081  * check the dialog and transaction prior to every pjsip call.
4082  *
4083  * That means any off nominal/failure paths in this function must remove the associated
4084  * dialog reference added at dialog creation, and remove the lock. As well the
4085  * referenced pjsip invite session must be "cleaned up", which should also then
4086  * remove its reference to the dialog at that time.
4087  *
4088  * Nominally we'll unlock the dialog, and release the reference when all new invite
4089  * process handling has successfully completed.
4090  */
4091 
4092  session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
4093  if (!session) {
4094  /* Dialog's lock and reference are removed in new_invite_initial_answer */
4095  if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4096  /* Terminate the session if it wasn't done in the answer */
4097  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
4098  }
4099  SCOPE_EXIT_RTN("Couldn't create session\n");
4100  }
4102 
4103  /*
4104  * The current thread is supposed be the session serializer to prevent
4105  * any initial INVITE retransmissions from trying to setup the same
4106  * call again.
4107  */
4109 
4110  invite.session = session;
4111  invite.rdata = rdata;
4112  new_invite(&invite);
4113 
4114  /*
4115  * The dialog lock and reference added at dialog creation time must be
4116  * maintained throughout the new invite process. Since we're pretty much
4117  * done at this point with things it's safe to go ahead and remove the lock
4118  * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
4119  *
4120  * Note, any future functionality added that does work using the dialog must
4121  * be done before this.
4122  */
4123  pjsip_dlg_dec_lock(inv_session->dlg);
4124 
4125  SCOPE_EXIT("Request: %s Session: %s\n", req_uri, ast_sip_session_get_name(session));
4126  ao2_ref(session, -1);
4127 }
struct ast_sip_session * ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata)
Allocate a new SIP session.
static pjsip_inv_session * pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
#define ast_assert(a)
Definition: utils.h:695
static int new_invite(struct new_invite *invite)
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
pjsip_rx_data * rdata
INVITE request itself.
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
struct ast_taskprocessor * serializer
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
Am I the given taskprocessor&#39;s current task.
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
#define TRACE_ATLEAST(level)
Definition: logger.h:637
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
enum ast_sip_session_call_direction call_direction
static int new_invite_initial_answer(pjsip_inv_session *inv_session, pjsip_rx_data *rdata, int answer_code, int terminate_code, pj_bool_t notify)

◆ handle_outgoing_request()

static void handle_outgoing_request ( struct ast_sip_session session,
pjsip_tx_data *  tdata 
)
static

Definition at line 4481 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_message_apply_transport(), ast_sip_session_get_name(), does_method_match(), ast_sip_session::endpoint, ast_sip_session_supplement::method, ast_sip_session_supplement::outgoing_request, SCOPE_ENTER, SCOPE_EXIT, ast_sip_session::supplements, and ast_sip_endpoint::transport.

Referenced by ast_sip_session_send_request_with_cb().

4482 {
4483  struct ast_sip_session_supplement *supplement;
4484  struct pjsip_request_line req = tdata->msg->line.req;
4485  SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4486  (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4487 
4489 
4490  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4491  if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
4492  supplement->outgoing_request(session, tdata);
4493  }
4494  }
4495  SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
4496 }
struct ast_sip_endpoint * endpoint
const ast_string_field transport
Definition: res_pjsip.h:817
void(* outgoing_request)(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Called on an outgoing SIP request This method is always called from a SIP servant thread...
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
void ast_sip_message_apply_transport(const char *transport_name, pjsip_tx_data *tdata)
Apply the configuration for a transport to an outgoing message.
struct ast_sip_session::@308 supplements
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
A supplement to SIP message processing.
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)

◆ handle_outgoing_response()

static void handle_outgoing_response ( struct ast_sip_session session,
pjsip_tx_data *  tdata 
)
static

Definition at line 4498 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_message_apply_transport(), ast_sip_session_get_name(), does_method_match(), ast_sip_session::endpoint, LOG_ERROR, ast_sip_session_supplement::method, NULL, ast_sip_session_supplement::outgoing_response, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_LOG_RTN, ast_sip_session::supplements, and ast_sip_endpoint::transport.

Referenced by ast_sip_session_send_response().

4499 {
4500  struct ast_sip_session_supplement *supplement;
4501  struct pjsip_status_line status = tdata->msg->line.status;
4502  pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
4503  SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4504  (int) pj_strlen(&cseq->method.name),
4505  pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
4506  pj_strbuf(&status.reason));
4507 
4508 
4509  if (!cseq) {
4510  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4511  ast_sip_session_get_name(session));
4512  }
4513 
4515 
4516  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4517  if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
4518  supplement->outgoing_response(session, tdata);
4519  }
4520  }
4521 
4522  SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
4523 }
struct ast_sip_endpoint * endpoint
const ast_string_field transport
Definition: res_pjsip.h:817
void(* outgoing_response)(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Called on an outgoing SIP response This method is always called from a SIP servant thread...
#define NULL
Definition: resample.c:96
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
Definition: logger.h:934
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
void ast_sip_message_apply_transport(const char *transport_name, pjsip_tx_data *tdata)
Apply the configuration for a transport to an outgoing message.
struct ast_sip_session::@308 supplements
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
A supplement to SIP message processing.
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
jack_status_t status
Definition: app_jack.c:146

◆ handle_session_begin()

static void handle_session_begin ( struct ast_sip_session session)
static

Definition at line 4415 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_session_supplement::next, ast_sip_session_supplement::session_begin, and ast_sip_session::supplements.

Referenced by ast_sip_session_alloc().

4416 {
4417  struct ast_sip_session_supplement *iter;
4418 
4419  AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4420  if (iter->session_begin) {
4421  iter->session_begin(session);
4422  }
4423  }
4424 }
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_sip_session::@308 supplements
struct ast_sip_session_supplement * next
void(* session_begin)(struct ast_sip_session *session)
Notification that the session has begun This method will always be called from a SIP servant thread...
A supplement to SIP message processing.

◆ handle_session_destroy()

static void handle_session_destroy ( struct ast_sip_session session)
static

Definition at line 4426 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_session_supplement::next, ast_sip_session_supplement::session_destroy, and ast_sip_session::supplements.

Referenced by session_destructor().

4427 {
4428  struct ast_sip_session_supplement *iter;
4429 
4430  AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4431  if (iter->session_destroy) {
4432  iter->session_destroy(session);
4433  }
4434  }
4435 }
void(* session_destroy)(struct ast_sip_session *session)
Notification that the session is being destroyed.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_sip_session::@308 supplements
struct ast_sip_session_supplement * next
A supplement to SIP message processing.

◆ handle_session_end()

static void handle_session_end ( struct ast_sip_session session)
static

Definition at line 4437 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, ast_sip_session_supplement::next, ast_sip_session_supplement::session_end, and ast_sip_session::supplements.

Referenced by session_end().

4438 {
4439  struct ast_sip_session_supplement *iter;
4440 
4441  /* Session is dead. Notify the supplements. */
4442  AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4443  if (iter->session_end) {
4444  iter->session_end(session);
4445  }
4446  }
4447 }
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
void(* session_end)(struct ast_sip_session *session)
Notification that the session has ended.
struct ast_sip_session::@308 supplements
struct ast_sip_session_supplement * next
A supplement to SIP message processing.

◆ has_supplement()

static pj_bool_t has_supplement ( const struct ast_sip_session session,
const pjsip_rx_data *  rdata 
)
static

Definition at line 4142 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, does_method_match(), ast_sip_session_supplement::method, method, and ast_sip_session::supplements.

Referenced by session_on_rx_request().

4143 {
4144  struct ast_sip_session_supplement *supplement;
4145  struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
4146 
4147  if (!session) {
4148  return PJ_FALSE;
4149  }
4150 
4151  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4152  if (does_method_match(&method->name, supplement->method)) {
4153  return PJ_TRUE;
4154  }
4155  }
4156  return PJ_FALSE;
4157 }
const char * method
Definition: res_pjsip.c:4335
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_sip_session::@308 supplements
A supplement to SIP message processing.
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)

◆ internal_sip_session_media_state_alloc()

static struct ast_sip_session_media_state* internal_sip_session_media_state_alloc ( size_t  sessions,
size_t  read_callbacks 
)
static

Definition at line 214 of file res_pjsip_session.c.

References ast_calloc, ast_free, AST_VECTOR_FREE, AST_VECTOR_INIT, and NULL.

Referenced by ast_sip_session_media_state_alloc(), and ast_sip_session_media_state_clone().

216 {
217  struct ast_sip_session_media_state *media_state;
218 
219  media_state = ast_calloc(1, sizeof(*media_state));
220  if (!media_state) {
221  return NULL;
222  }
223 
224  if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) {
225  ast_free(media_state);
226  return NULL;
227  }
228 
229  if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) {
230  AST_VECTOR_FREE(&media_state->sessions);
231  ast_free(media_state);
232  return NULL;
233  }
234 
235  return media_state;
236 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
Structure which contains media state information (streams, sessions)
#define NULL
Definition: resample.c:96
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204

◆ invite_collision_timeout()

static int invite_collision_timeout ( void *  vsession)
static

Definition at line 1538 of file res_pjsip_session.c.

References ao2_ref, ast_sip_session_get_name(), ast_sip_session::inv_session, invite_terminated(), SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and session.

Referenced by resend_reinvite().

1539 {
1540  struct ast_sip_session *session = vsession;
1541  int res;
1542  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
1543 
1544  if (session->inv_session->invite_tsx) {
1545  /*
1546  * INVITE transaction still active. Let it send
1547  * the collision re-INVITE when it terminates.
1548  */
1549  ao2_ref(session, -1);
1550  res = 0;
1551  } else {
1552  res = invite_terminated(session);
1553  }
1554 
1555  SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
1556 }
struct pjsip_inv_session * inv_session
static int invite_terminated(void *vsession)
A structure describing a SIP session.
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875

◆ invite_proceeding()

static int invite_proceeding ( void *  vsession)
static

Definition at line 1440 of file res_pjsip_session.c.

References ao2_ref, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_sip_session_get_name(), ast_trace, delayed_method2str(), DELAYED_METHOD_BYE, DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, delayed_request_free(), ast_sip_session::delayed_requests, ast_sip_session_delayed_request::method, ast_sip_session_delayed_request::next, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, send_delayed_request(), and session.

Referenced by session_inv_on_tsx_state_changed(), and update_completed().

1441 {
1442  struct ast_sip_session *session = vsession;
1443  struct ast_sip_session_delayed_request *delay;
1444  int found = 0;
1445  int res = 0;
1446  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
1447 
1449  switch (delay->method) {
1450  case DELAYED_METHOD_INVITE:
1451  break;
1452  case DELAYED_METHOD_UPDATE:
1454  ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1455  delayed_method2str(delay->method));
1456  res = send_delayed_request(session, delay);
1457  delayed_request_free(delay);
1458  if (!res) {
1459  found = 1;
1460  }
1461  break;
1462  case DELAYED_METHOD_BYE:
1463  /* A BYE is pending so don't bother anymore. */
1464  found = 1;
1465  break;
1466  }
1467  if (found) {
1468  break;
1469  }
1470  }
1472 
1473  ao2_ref(session, -1);
1474  SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
1475 }
static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
static const char * delayed_method2str(enum delayed_method method)
struct ast_sip_session_delayed_request * next
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
A structure describing a SIP session.
static struct ast_mansession session
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure used for sending delayed requests.
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_sip_session::@309 delayed_requests
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528

◆ invite_terminated()

static int invite_terminated ( void *  vsession)
static

Definition at line 1487 of file res_pjsip_session.c.

References ao2_ref, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_sip_session_get_name(), ast_trace, delayed_method2str(), DELAYED_METHOD_BYE, DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, delayed_request_free(), ast_sip_session::delayed_requests, ast_sip_session_delayed_request::method, ast_sip_session_delayed_request::next, ast_sip_session::rescheduled_reinvite, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, send_delayed_request(), and session.

Referenced by invite_collision_timeout(), session_inv_on_tsx_state_changed(), and update_completed().

1488 {
1489  struct ast_sip_session *session = vsession;
1490  struct ast_sip_session_delayed_request *delay;
1491  int found = 0;
1492  int res = 0;
1493  int timer_running;
1494  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
1495 
1496  /* re-INVITE collision timer running? */
1497  timer_running = pj_timer_entry_running(&session->rescheduled_reinvite);
1498 
1500  switch (delay->method) {
1501  case DELAYED_METHOD_INVITE:
1502  if (!timer_running) {
1503  found = 1;
1504  }
1505  break;
1506  case DELAYED_METHOD_UPDATE:
1507  case DELAYED_METHOD_BYE:
1508  found = 1;
1509  break;
1510  }
1511  if (found) {
1513  ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1514  delayed_method2str(delay->method));
1515  res = send_delayed_request(session, delay);
1516  delayed_request_free(delay);
1517  if (!res) {
1518  break;
1519  }
1520  }
1521  }
1523 
1524  ao2_ref(session, -1);
1525  SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
1526 }
static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
static const char * delayed_method2str(enum delayed_method method)
struct ast_sip_session_delayed_request * next
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
A structure describing a SIP session.
static struct ast_mansession session
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ao2_ref(o, delta)
Definition: astobj2.h:464
pj_timer_entry rescheduled_reinvite
Structure used for sending delayed requests.
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_sip_session::@309 delayed_requests
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528

◆ is_media_state_valid()

static int is_media_state_valid ( const char *  session_name,
struct ast_sip_session_media_state state 
)
static

Definition at line 1751 of file res_pjsip_session.c.

References ast_codec_media_type2str(), ast_str_tmp, ast_stream_get_name(), ast_stream_get_type(), ast_stream_to_str(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_to_str(), ast_strings_equal(), ast_strlen_zero, AST_VECTOR_GET, AST_VECTOR_SIZE, end, GET_STREAM_NAME_SAFE, ast_sip_session_media::label, NULL, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_RTN_VALUE, session_count, ast_sip_session_media::stream_num, STREAM_REMOVED, ast_sip_session_media_state::topology, and ast_sip_session_media::type.

Referenced by resolve_refresh_media_states().

1752 {
1753  int stream_count = ast_stream_topology_get_count(state->topology);
1754  int session_count = AST_VECTOR_SIZE(&state->sessions);
1755  int i;
1756  int res = 0;
1757  SCOPE_ENTER(3, "%s: Topology: %s\n", session_name,
1758  ast_str_tmp(256, ast_stream_topology_to_str(state->topology, &STR_TMP)));
1759 
1760  if (session_count != stream_count) {
1761  SCOPE_EXIT_RTN_VALUE(0, "%s: %d media sessions but %d streams\n", session_name,
1762  session_count, stream_count);
1763  }
1764 
1765  for (i = 0; i < stream_count; i++) {
1766  struct ast_sip_session_media *media = NULL;
1767  struct ast_stream *stream = ast_stream_topology_get_stream(state->topology, i);
1768  const char *stream_name = NULL;
1769  int j;
1770  SCOPE_ENTER(4, "%s: Checking stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1771 
1772  if (!stream) {
1773  SCOPE_EXIT_EXPR(goto end, "%s: stream %d is null\n", session_name, i);
1774  }
1775  stream_name = ast_stream_get_name(stream);
1776 
1777  for (j = 0; j < stream_count; j++) {
1778  struct ast_stream *possible_dup = ast_stream_topology_get_stream(state->topology, j);
1779  if (j == i || !possible_dup) {
1780  continue;
1781  }
1782  if (!STREAM_REMOVED(stream) && ast_strings_equal(stream_name, GET_STREAM_NAME_SAFE(possible_dup))) {
1783  SCOPE_EXIT_EXPR(goto end, "%s: stream %i %s is duplicated to %d\n", session_name,
1784  i, stream_name, j);
1785  }
1786  }
1787 
1788  media = AST_VECTOR_GET(&state->sessions, i);
1789  if (!media) {
1790  SCOPE_EXIT_EXPR(continue, "%s: media %d is null\n", session_name, i);
1791  }
1792 
1793  for (j = 0; j < session_count; j++) {
1794  struct ast_sip_session_media *possible_dup = AST_VECTOR_GET(&state->sessions, j);
1795  if (j == i || !possible_dup) {
1796  continue;
1797  }
1798  if (!ast_strlen_zero(media->label) && !ast_strlen_zero(possible_dup->label)
1799  && ast_strings_equal(media->label, possible_dup->label)) {
1800  SCOPE_EXIT_EXPR(goto end, "%s: media %d %s is duplicated to %d\n", session_name,
1801  i, media->label, j);
1802  }
1803  }
1804 
1805  if (media->stream_num != i) {
1806  SCOPE_EXIT_EXPR(goto end, "%s: media %d has stream_num %d\n", session_name,
1807  i, media->stream_num);
1808  }
1809 
1810  if (media->type != ast_stream_get_type(stream)) {
1811  SCOPE_EXIT_EXPR(goto end, "%s: media %d has type %s but stream has type %s\n", stream_name,
1813  }
1814  SCOPE_EXIT("%s: Done with stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1815  }
1816 
1817  res = 1;
1818 end:
1819  SCOPE_EXIT_RTN_VALUE(res, "%s: %s\n", session_name, res ? "Valid" : "NOT Valid");
1820 }
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition: stream.c:337
#define STREAM_REMOVED(_stream)
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define SCOPE_EXIT_EXPR(__expr,...)
Definition: logger.h:834
int stream_num
The stream number to place into any resulting frames.
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:239
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
static int session_count
Definition: http.c:109
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
enum ast_media_type type
Media type of this session media.
struct ast_stream_topology * topology
The media stream topology.
#define GET_STREAM_NAME_SAFE(_stream)
char label[AST_UUID_STR_LEN]
Track label.
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ is_stream_limitation_reached()

static int is_stream_limitation_reached ( enum ast_media_type  type,
const struct ast_sip_endpoint endpoint,
int *  type_streams 
)
static

Definition at line 592 of file res_pjsip_session.c.

References AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_IMAGE, AST_MEDIA_TYPE_TEXT, AST_MEDIA_TYPE_UNKNOWN, AST_MEDIA_TYPE_VIDEO, ast_sip_endpoint_media_configuration::max_audio_streams, ast_sip_endpoint_media_configuration::max_video_streams, ast_sip_endpoint::media, and type.

Referenced by handle_incoming_sdp(), and sip_session_refresh().

593 {
594  switch (type) {
596  return !(type_streams[type] < endpoint->media.max_audio_streams);
598  return !(type_streams[type] < endpoint->media.max_video_streams);
600  /* We don't have an option for image (T.38) streams so cap it to one. */
601  return (type_streams[type] > 0);
603  case AST_MEDIA_TYPE_TEXT:
604  default:
605  /* We don't want any unknown or "other" streams on our endpoint,
606  * so always just say we've reached the limit
607  */
608  return 1;
609  }
610 }
static const char type[]
Definition: chan_ooh323.c:109
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841

◆ load_module()

static int load_module ( void  )
static

Definition at line 6074 of file res_pjsip_session.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_module_shutdown_ref, ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_register_service(), ast_sorcery_alloc(), ast_sorcery_create(), AST_TEST_REGISTER, NULL, ast_sip_nat_hook::outgoing_external_message, SDP_HANDLER_BUCKETS, sdp_handler_list_cmp(), sdp_handler_list_hash(), ast_module_info::self, and session_outgoing_nat_hook().

Referenced by unload_module().

6075 {
6076  pjsip_endpoint *endpt;
6077 
6079  return AST_MODULE_LOAD_DECLINE;
6080  }
6081  if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
6082  return AST_MODULE_LOAD_DECLINE;
6083  }
6088  if (!sdp_handlers) {
6089  return AST_MODULE_LOAD_DECLINE;
6090  }
6091  endpt = ast_sip_get_pjsip_endpoint();
6092  pjsip_inv_usage_init(endpt, &inv_callback);
6093  pjsip_100rel_init_module(endpt);
6094  pjsip_timer_init_module(endpt);
6096  return AST_MODULE_LOAD_DECLINE;
6097  }
6100 
6102 #ifdef TEST_FRAMEWORK
6103  AST_TEST_REGISTER(test_resolve_refresh_media_states);
6104 #endif
6105  return AST_MODULE_LOAD_SUCCESS;
6106 }
static pjsip_module session_reinvite_module
#define SDP_HANDLER_BUCKETS
static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Hook for modifying outgoing messages with SDP to contain the proper address information.
static pjsip_inv_callback inv_callback
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
static int sdp_handler_list_cmp(void *obj, void *arg, int flags)
static struct ast_sip_nat_hook * nat_hook
NAT hook for modifying outgoing messages with SDP.
#define NULL
Definition: resample.c:96
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2057
struct ast_module * self
Definition: module.h:342
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition: res_pjsip.h:275
static pjsip_module session_module
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int sdp_handler_list_hash(const void *obj, int flags)
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
static pjsip_module outbound_invite_auth_module

◆ media_stats_local_ssrc_cmp()

static int media_stats_local_ssrc_cmp ( const struct ast_rtp_instance_stats vec_elem,
const struct ast_rtp_instance_stats srch 
)
static

Definition at line 204 of file res_pjsip_session.c.

References ast_rtp_instance_stats::local_ssrc.

Referenced by ast_sip_session_media_stats_save().

206 {
207  if (vec_elem->local_ssrc == srch->local_ssrc) {
208  return 1;
209  }
210 
211  return 0;
212 }
unsigned int local_ssrc
Definition: rtp_engine.h:422

◆ new_invite()

static int new_invite ( struct new_invite invite)
static

Definition at line 3911 of file res_pjsip_session.c.

References ast_sip_session_get_name(), ast_sip_session_send_response(), AST_SOCKADDR_BUFLEN, ast_trace, ast_trace_log, check_content_disposition(), ast_sip_endpoint::context, create_local_sdp(), end, ast_sip_session::endpoint, ast_sip_session::exten, ast_sip_endpoint::extensions, get_destination(), handle_incoming_request(), handle_incoming_sdp(), ast_sip_session::inv_session, LOG_ERROR, LOG_NOTICE, ast_sip_timer_options::min_se, NULL, ast_sip_endpoint::preferred_codec_only, new_invite::rdata, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, ast_sip_timer_options::sess_expires, new_invite::session, SIP_GET_DEST_EXTEN_FOUND, SIP_GET_DEST_EXTEN_NOT_FOUND, SIP_GET_DEST_EXTEN_PARTIAL, SIP_GET_DEST_UNSUPPORTED_URI, timer, and ast_sip_endpoint_extensions::timer.

Referenced by handle_new_invite_request().

3912 {
3913  pjsip_tx_data *tdata = NULL;
3914  pjsip_timer_setting timer;
3915  pjsip_rdata_sdp_info *sdp_info;
3916  pjmedia_sdp_session *local = NULL;
3917  char buffer[AST_SOCKADDR_BUFLEN];
3918  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(invite->session));
3919 
3920 
3921  /* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
3922  * so that we will be notified so we can destroy the session properly
3923  */
3924 
3925  if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
3926  ast_trace_log(-1, LOG_ERROR, "%s: Session already DISCONNECTED [reason=%d (%s)]\n",
3928  invite->session->inv_session->cause,
3929  pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
3931  }
3932 
3933  switch (get_destination(invite->session, invite->rdata)) {
3935  /* Things worked. Keep going */
3936  break;
3938  ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - unsupported uri\n",
3940  invite->rdata->tp_info.transport->type_name,
3941  pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3942  invite->session->exten);
3943  if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
3944  ast_sip_session_send_response(invite->session, tdata);
3945  } else {
3946  pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
3947  }
3948  goto end;
3950  ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - partial match\n",
3952  invite->rdata->tp_info.transport->type_name,
3953  pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3954  invite->session->exten);
3955 
3956  if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) {
3957  ast_sip_session_send_response(invite->session, tdata);
3958  } else {
3959  pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE);
3960  }
3961  goto end;
3963  default:
3964  ast_trace_log(-1, LOG_NOTICE, "%s: Call (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",
3966  invite->rdata->tp_info.transport->type_name,
3967  pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3968  invite->session->exten,
3969  invite->session->endpoint->context);
3970 
3971  if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) {
3972  ast_sip_session_send_response(invite->session, tdata);
3973  } else {
3974  pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
3975  }
3976  goto end;
3977  };
3978 
3979  if (check_content_disposition(invite->rdata)) {
3980  if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 415, NULL, NULL, &tdata) == PJ_SUCCESS) {
3981  ast_sip_session_send_response(invite->session, tdata);
3982  } else {
3983  pjsip_inv_terminate(invite->session->inv_session, 415, PJ_TRUE);
3984  }
3985  goto end;
3986  }
3987 
3988  pjsip_timer_setting_default(&timer);
3989  timer.min_se = invite->session->endpoint->extensions.timer.min_se;
3990  timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires;
3991  pjsip_timer_init_session(invite->session->inv_session, &timer);
3992 
3993  /*
3994  * At this point, we've verified what we can that won't take awhile,
3995  * so let's go ahead and send a 100 Trying out to stop any
3996  * retransmissions.
3997  */
3998  ast_trace(-1, "%s: Call (%s:%s) to extension '%s' sending 100 Trying\n",
4000  invite->rdata->tp_info.transport->type_name,
4001  pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4002  invite->session->exten);
4003  if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
4004  pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
4005  goto end;
4006  }
4007  ast_sip_session_send_response(invite->session, tdata);
4008 
4009  sdp_info = pjsip_rdata_get_sdp_info(invite->rdata);
4010  if (sdp_info && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
4011  if (handle_incoming_sdp(invite->session, sdp_info->sdp)) {
4012  tdata = NULL;
4013  if (pjsip_inv_end_session(invite->session->inv_session, 488, NULL, &tdata) == PJ_SUCCESS
4014  && tdata) {
4015  ast_sip_session_send_response(invite->session, tdata);
4016  }
4017  goto end;
4018  }
4019  /* We are creating a local SDP which is an answer to their offer */
4020  local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp);
4021  } else {
4022  /* We are creating a local SDP which is an offer */
4023  local = create_local_sdp(invite->session->inv_session, invite->session, NULL);
4024  }
4025 
4026  /* If we were unable to create a local SDP terminate the session early, it won't go anywhere */
4027  if (!local) {
4028  tdata = NULL;
4029  if (pjsip_inv_end_session(invite->session->inv_session, 500, NULL, &tdata) == PJ_SUCCESS
4030  && tdata) {
4031  ast_sip_session_send_response(invite->session, tdata);
4032  }
4033  goto end;
4034  }
4035 
4036  pjsip_inv_set_local_sdp(invite->session->inv_session, local);
4037  pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
4038 #ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
4039  if (!invite->session->endpoint->preferred_codec_only) {
4040  pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE);
4041  }
4042 #endif
4043 
4044  handle_incoming_request(invite->session, invite->rdata);
4045 
4046 end:
4048 }
#define AST_SOCKADDR_BUFLEN
Definition: netsock2.h:46
struct ast_sip_endpoint * endpoint
unsigned int sess_expires
Definition: res_pjsip.h:567
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
static int check_content_disposition(pjsip_rx_data *rdata)
struct ast_sip_session * session
Session created for the new INVITE.
const ast_string_field context
Definition: res_pjsip.h:815
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
static enum sip_get_destination_result get_destination(struct ast_sip_session *session, pjsip_rx_data *rdata)
Determine where in the dialplan a call should go.
char exten[AST_MAX_EXTENSION]
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
struct pjsip_inv_session * inv_session
unsigned int min_se
Definition: res_pjsip.h:565
#define ast_trace_log(__level, __log_level,...)
Definition: logger.h:952
pjsip_rx_data * rdata
INVITE request itself.
#define LOG_ERROR
Definition: logger.h:285
#define LOG_NOTICE
Definition: logger.h:263
unsigned int preferred_codec_only
Definition: res_pjsip.h:889
struct ast_sip_timer_options timer
Definition: res_pjsip.h:580
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
struct ast_sip_endpoint_extensions extensions
Definition: res_pjsip.h:839
static struct ast_timer * timer
Definition: chan_iax2.c:360

◆ new_invite_initial_answer()

static int new_invite_initial_answer ( pjsip_inv_session *  inv_session,
pjsip_rx_data *  rdata,
int  answer_code,
int  terminate_code,
pj_bool_t  notify 
)
static

Definition at line 3742 of file res_pjsip_session.c.

References NULL.

Referenced by handle_new_invite_request(), and pre_session_setup().

3744 {
3745  pjsip_tx_data *tdata = NULL;
3746  int res = 0;
3747 
3748  if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3749  if (pjsip_inv_initial_answer(
3750  inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
3751 
3752  pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
3753  res = -1;
3754  } else {
3755  pjsip_inv_send_msg(inv_session, tdata);
3756  }
3757  }
3758 
3759  if (answer_code >= 300) {
3760  /*
3761  * A session is ending. The dialog has a reference that needs to be
3762  * removed and holds a lock that needs to be unlocked before returning.
3763  */
3764  pjsip_dlg_dec_lock(inv_session->dlg);
3765  }
3766 
3767  return res;
3768 }
#define NULL
Definition: resample.c:96

◆ outbound_invite_auth()

static pj_bool_t outbound_invite_auth ( pjsip_rx_data *  rdata)
static

Definition at line 3231 of file res_pjsip_session.c.

References ast_debug, ast_sip_create_request_with_auth(), ast_sip_session_get_name(), ast_sip_session_send_request(), ast_sip_session::authentication_challenge_count, ast_sip_session::endpoint, MAX_RX_CHALLENGES, ast_sip_endpoint::outbound_auths, and session.

3232 {
3233  pjsip_transaction *tsx;
3234  pjsip_dialog *dlg;
3235  pjsip_inv_session *inv;
3236  pjsip_tx_data *tdata;
3237  struct ast_sip_session *session;
3238 
3239  if (rdata->msg_info.msg->line.status.code != 401
3240  && rdata->msg_info.msg->line.status.code != 407) {
3241  /* Doesn't pertain to us. Move on */
3242  return PJ_FALSE;
3243  }
3244 
3245  tsx = pjsip_rdata_get_tsx(rdata);
3246  dlg = pjsip_rdata_get_dlg(rdata);
3247  if (!dlg || !tsx) {
3248  return PJ_FALSE;
3249  }
3250 
3251  if (tsx->method.id != PJSIP_INVITE_METHOD) {
3252  /* Not an INVITE that needs authentication */
3253  return PJ_FALSE;
3254  }
3255 
3256  inv = pjsip_dlg_get_inv_session(dlg);
3257  session = inv->mod_data[session_module.id];
3258 
3259  if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {
3260  /*
3261  * We cannot handle reINVITE authentication at this
3262  * time because the reINVITE transaction is still in
3263  * progress.
3264  */
3265  ast_debug(3, "%s: A reINVITE is being challenged\n", ast_sip_session_get_name(session));
3266  return PJ_FALSE;
3267  }
3268  ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));
3269 
3271  ast_debug(3, "%s: Initial INVITE reached maximum number of auth attempts.\n", ast_sip_session_get_name(session));
3272  return PJ_FALSE;
3273  }
3274 
3276  tsx->last_tx, &tdata)) {
3277  return PJ_FALSE;
3278  }
3279 
3280  /*
3281  * Restart the outgoing initial INVITE transaction to deal
3282  * with authentication.
3283  */
3284  pjsip_inv_uac_restart(inv, PJ_FALSE);
3285 
3286  ast_sip_session_send_request(session, tdata);
3287  return PJ_TRUE;
3288 }
struct ast_sip_endpoint * endpoint
struct ast_sip_auth_vector outbound_auths
Definition: res_pjsip.h:855
A structure describing a SIP session.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ast_mansession session
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition: res_pjsip.c:3412
static pjsip_module session_module
#define MAX_RX_CHALLENGES
Definition: res_pjsip.h:80
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
unsigned int authentication_challenge_count
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.

◆ pre_session_setup()

static pjsip_inv_session* pre_session_setup ( pjsip_rx_data *  rdata,
const struct ast_sip_endpoint endpoint 
)
static

Definition at line 3789 of file res_pjsip_session.c.

References ast_sip_create_dialog_uas_locked(), ast_sip_get_pjsip_endpoint(), ast_sip_endpoint::extensions, ast_sip_endpoint_extensions::flags, new_invite_initial_answer(), NULL, and options.

Referenced by handle_new_invite_request().

3790 {
3791  pjsip_tx_data *tdata;
3792  pjsip_dialog *dlg;
3793  pjsip_inv_session *inv_session;
3794  unsigned int options = endpoint->extensions.flags;
3795  pj_status_t dlg_status = PJ_EUNKNOWN;
3796 
3797  if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
3798  if (tdata) {
3799  if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
3800  pjsip_tx_data_dec_ref(tdata);
3801  }
3802  } else {
3803  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3804  }
3805  return NULL;
3806  }
3807 
3808  dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, &dlg_status);
3809  if (!dlg) {
3810  if (dlg_status != PJ_EEXISTS) {
3811  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3812  }
3813  return NULL;
3814  }
3815 
3816  /*
3817  * The returned dialog holds a lock and has a reference added. Any paths where the
3818  * dialog invite session is not returned must unlock the dialog and remove its reference.
3819  */
3820 
3821  if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
3822  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3823  /*
3824  * The acquired dialog holds a lock, and a reference. Since the dialog is not
3825  * going to be returned here it must first be unlocked and de-referenced. This
3826  * must be done prior to calling dialog termination.
3827  */
3828  pjsip_dlg_dec_lock(dlg);
3829  pjsip_dlg_terminate(dlg);
3830  return NULL;
3831  }
3832 
3833 #if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3834  inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3835 #endif
3836  if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3837  /* Dialog's lock and a reference are removed in new_invite_initial_answer */
3838  new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE);
3839  /* Remove 2nd reference added at inv_session creation */
3840  pjsip_dlg_dec_session(inv_session->dlg, &session_module);
3841  return NULL;
3842  }
3843 
3844  return inv_session;
3845 }
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
static pjsip_module session_module
pjsip_dialog * ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
General purpose method for creating a UAS dialog with an endpoint.
Definition: res_pjsip.c:4249
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_sip_endpoint_extensions extensions
Definition: res_pjsip.h:839
static struct test_options options
static int new_invite_initial_answer(pjsip_inv_session *inv_session, pjsip_rx_data *rdata, int answer_code, int terminate_code, pj_bool_t notify)

◆ remove_handler()

static int remove_handler ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Definition at line 176 of file res_pjsip_session.c.

References ast_debug, AST_LIST_EMPTY, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, CMP_MATCH, CMP_STOP, handler(), ast_sip_session_sdp_handler::id, sdp_handler_list::list, ast_sip_session_sdp_handler::next, and sdp_handler_list::stream_type.

Referenced by ast_sip_session_unregister_sdp_handler().

177 {
178  struct sdp_handler_list *handler_list = obj;
179  struct ast_sip_session_sdp_handler *handler = data;
180  struct ast_sip_session_sdp_handler *iter;
181  const char *stream_type = arg;
182 
183  AST_LIST_TRAVERSE_SAFE_BEGIN(&handler_list->list, iter, next) {
184  if (!strcmp(iter->id, handler->id)) {
186  ast_debug(1, "Unregistered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
187  }
188  }
190 
191  if (AST_LIST_EMPTY(&handler_list->list)) {
192  ast_debug(3, "No more handlers exist for stream type '%s'\n", stream_type);
193  return CMP_MATCH;
194  } else {
195  return CMP_STOP;
196  }
197 }
A handler for SDPs in SIP sessions.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_sip_session_sdp_handler * next
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
struct sdp_handler_list::@487 list
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528

◆ remove_stream_from_bundle()

static void remove_stream_from_bundle ( struct ast_sip_session_media session_media,
struct ast_stream stream 
)
static

Definition at line 754 of file res_pjsip_session.c.

References ast_free, ast_stream_set_state(), AST_STREAM_STATE_REMOVED, ast_sip_session_media::bundle_group, ast_sip_session_media::bundled, ast_sip_session_media::mid, and NULL.

Referenced by handle_incoming_sdp().

756 {
758  ast_free(session_media->mid);
759  session_media->mid = NULL;
760  session_media->bundle_group = -1;
761  session_media->bundled = 0;
762 }
char * mid
Media identifier for this stream (may be shared across multiple streams)
Set when the stream has been removed/declined.
Definition: stream.h:78
#define NULL
Definition: resample.c:96
unsigned int bundled
Whether this stream is currently bundled or not.
#define ast_free(a)
Definition: astmm.h:182
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
int bundle_group
The bundle group the stream belongs to.

◆ reschedule_reinvite()

static void reschedule_reinvite ( struct ast_sip_session session,
ast_sip_session_response_cb  on_response 
)
static

Definition at line 4269 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ao2_ref, ast_random(), ast_sip_get_pjsip_endpoint(), ast_sip_session_get_name(), ast_sip_session_media_state_clone(), ast_sip_session_media_state_free(), ast_stream_topology_equal(), delay_request(), DELAYED_METHOD_INVITE, ast_sip_session::inv_session, LOG_ERROR, NULL, ast_sip_session::pending_media_state, ast_sip_session::rescheduled_reinvite, resend_reinvite(), SCOPE_ENTER, SCOPE_EXIT_LOG_RTN, SCOPE_EXIT_RTN, and ast_sip_session_media_state::topology.

Referenced by session_inv_on_tsx_state_changed().

4270 {
4271  pjsip_inv_session *inv = session->inv_session;
4272  pj_time_val tv;
4273  struct ast_sip_session_media_state *pending_media_state = NULL;
4274  struct ast_sip_session_media_state *active_media_state = NULL;
4275  const char *session_name = ast_sip_session_get_name(session);
4276  int use_pending = 0;
4277  int use_active = 0;
4278 
4279  SCOPE_ENTER(3, "%s\n", session_name);
4280 
4281  /*
4282  * If the two media state topologies are the same this means that the session refresh request
4283  * did not specify a desired topology, so it does not care. If that is the case we don't even
4284  * pass one in here resulting in the current topology being used. It's possible though that
4285  * either one of the topologies could be NULL so we have to test for that before we check for
4286  * equality.
4287  */
4288 
4289  /* We only want to clone a media state if its topology is not null */
4290  use_pending = session->pending_media_state->topology != NULL;
4291  use_active = session->active_media_state->topology != NULL;
4292 
4293  /*
4294  * If both media states have topologies, we can test for equality. If they're equal we're not going to
4295  * clone either states.
4296  */
4297  if (use_pending && use_active && ast_stream_topology_equal(session->active_media_state->topology, session->pending_media_state->topology)) {
4298  use_pending = 0;
4299  use_active = 0;
4300  }
4301 
4302  if (use_pending) {
4303  pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);
4304  if (!pending_media_state) {
4305  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
4306  }
4307  }
4308 
4309  if (use_active) {
4310  active_media_state = ast_sip_session_media_state_clone(session->active_media_state);
4311  if (!active_media_state) {
4312  ast_sip_session_media_state_free(pending_media_state);
4313  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
4314  }
4315  }
4316 
4317  if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,
4318  active_media_state, 1)) {
4319  ast_sip_session_media_state_free(pending_media_state);
4320  ast_sip_session_media_state_free(active_media_state);
4321  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
4322  }
4323 
4324  if (pj_timer_entry_running(&session->rescheduled_reinvite)) {
4325  /* Timer already running. Something weird is going on. */
4326  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
4327  }
4328 
4329  tv.sec = 0;
4330  if (inv->role == PJSIP_ROLE_UAC) {
4331  tv.msec = 2100 + ast_random() % 2000;
4332  } else {
4333  tv.msec = ast_random() % 2000;
4334  }
4335  pj_timer_entry_init(&session->rescheduled_reinvite, 0, session, resend_reinvite);
4336 
4337  ao2_ref(session, +1);
4338  if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
4339  &session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {
4340  ao2_ref(session, -1);
4341  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
4342  }
4343 
4344  SCOPE_EXIT_RTN();
4345 }
Structure which contains media state information (streams, sessions)
struct ast_sip_session_media_state * pending_media_state
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, enum delayed_method method, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queue_head)
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
struct ast_sip_session_media_state * active_media_state
static void resend_reinvite(pj_timer_heap_t *timer, pj_timer_entry *entry)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
pj_timer_entry rescheduled_reinvite
long int ast_random(void)
Definition: main/utils.c:2064
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
Definition: logger.h:934
#define LOG_ERROR
Definition: logger.h:285
int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right)
Compare two stream topologies to see if they are equal.
Definition: stream.c:696
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
struct ast_sip_session_media_state * ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state)
Clone a media state.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_stream_topology * topology
The media stream topology.

◆ resend_reinvite()

static void resend_reinvite ( pj_timer_heap_t *  timer,
pj_timer_entry *  entry 
)
static

Definition at line 4248 of file res_pjsip_session.c.

References ao2_ref, ast_debug, AST_LIST_EMPTY, ast_sip_push_task(), ast_sip_session_get_name(), ast_sip_session::delayed_requests, invite_collision_timeout(), and ast_sip_session::serializer.

Referenced by reschedule_reinvite().

4249 {
4250  struct ast_sip_session *session = entry->user_data;
4251 
4252  ast_debug(3, "%s: re-INVITE collision timer expired.\n",
4253  ast_sip_session_get_name(session));
4254 
4255  if (AST_LIST_EMPTY(&session->delayed_requests)) {
4256  /* No delayed request pending, so just return */
4257  ao2_ref(session, -1);
4258  return;
4259  }
4260  if (ast_sip_push_task(session->serializer, invite_collision_timeout, session)) {
4261  /*
4262  * Uh oh. We now have nothing in the foreseeable future
4263  * to trigger sending the delayed requests.
4264  */
4265  ao2_ref(session, -1);
4266  }
4267 }
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
A structure describing a SIP session.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_taskprocessor * serializer
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_sip_session::@309 delayed_requests
static int invite_collision_timeout(void *vsession)
Definition: search.h:40

◆ resolve_refresh_media_states()

static struct ast_sip_session_media_state* resolve_refresh_media_states ( const char *  session_name,
struct ast_sip_session_media_state delayed_pending_state,
struct ast_sip_session_media_state delayed_active_state,
struct ast_sip_session_media_state current_active_state,
int  run_post_validation 
)
static

Definition at line 1835 of file res_pjsip_session.c.

References ao2_cleanup, AST_MEDIA_TYPE_END, ast_sip_session_media_state_clone(), ast_sip_session_media_state_free(), ast_str_tmp, ast_stream_clone(), ast_stream_get_name(), ast_stream_get_state(), ast_stream_set_state(), ast_stream_state2str(), AST_STREAM_STATE_END, ast_stream_to_str(), ast_stream_topology_append_stream(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_set_stream(), ast_stream_topology_to_str(), ast_strings_equal(), ast_trace, AST_VECTOR_GET, AST_VECTOR_REPLACE, AST_VECTOR_SIZE, GET_STREAM_NAME_SAFE, GET_STREAM_SAFE, GET_STREAM_STATE_SAFE, is_media_state_valid(), LOG_ERROR, LOG_WARNING, MAX, NULL, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, STATE_NONE, STATE_REMOVED, STREAM_REMOVED, ast_sip_session_media_state::topology, and ast_sip_session_media::type.

Referenced by sip_session_refresh().

1841 {
1843  struct ast_sip_session_media_state *returned_media_state = NULL;
1844  struct ast_stream_topology *delayed_pending = delayed_pending_state->topology;
1845  struct ast_stream_topology *delayed_active = delayed_active_state->topology;
1846  struct ast_stream_topology *current_active = current_active_state->topology;
1847  struct ast_stream_topology *new_pending = NULL;
1848  int i;
1849  int max_stream_count;
1850  int res;
1851  SCOPE_ENTER(2, "%s: DP: %s DA: %s CA: %s\n", session_name,
1852  ast_str_tmp(256, ast_stream_topology_to_str(delayed_pending, &STR_TMP)),
1853  ast_str_tmp(256, ast_stream_topology_to_str(delayed_active, &STR_TMP)),
1854  ast_str_tmp(256, ast_stream_topology_to_str(current_active, &STR_TMP))
1855  );
1856 
1857  max_stream_count = MAX(ast_stream_topology_get_count(delayed_pending),
1858  ast_stream_topology_get_count(delayed_active));
1859  max_stream_count = MAX(max_stream_count, ast_stream_topology_get_count(current_active));
1860 
1861  /*
1862  * The new_pending_state is always based on the currently negotiated state because
1863  * the stream ordering in its topology must be preserved.
1864  */
1865  new_pending_state = ast_sip_session_media_state_clone(current_active_state);
1866  if (!new_pending_state) {
1867  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't clone current_active_state to new_pending_state\n", session_name);
1868  }
1869  new_pending = new_pending_state->topology;
1870 
1871  for (i = 0; i < max_stream_count; i++) {
1872  struct ast_stream *dp_stream = GET_STREAM_SAFE(delayed_pending, i);
1873  struct ast_stream *da_stream = GET_STREAM_SAFE(delayed_active, i);
1874  struct ast_stream *ca_stream = GET_STREAM_SAFE(current_active, i);
1875  struct ast_stream *np_stream = GET_STREAM_SAFE(new_pending, i);
1876  struct ast_stream *found_da_stream = NULL;
1877  struct ast_stream *found_np_stream = NULL;
1878  enum ast_stream_state dp_state = GET_STREAM_STATE_SAFE(dp_stream);
1879  enum ast_stream_state da_state = GET_STREAM_STATE_SAFE(da_stream);
1880  enum ast_stream_state ca_state = GET_STREAM_STATE_SAFE(ca_stream);
1881  enum ast_stream_state np_state = GET_STREAM_STATE_SAFE(np_stream);
1882  enum ast_stream_state found_da_state = AST_STREAM_STATE_END;
1883  enum ast_stream_state found_np_state = AST_STREAM_STATE_END;
1884  const char *da_name = GET_STREAM_NAME_SAFE(da_stream);
1885  const char *dp_name = GET_STREAM_NAME_SAFE(dp_stream);
1886  const char *ca_name = GET_STREAM_NAME_SAFE(ca_stream);
1887  const char *np_name = GET_STREAM_NAME_SAFE(np_stream);
1888  const char *found_da_name __attribute__((unused)) = "";
1889  const char *found_np_name __attribute__((unused)) = "";
1890  int found_da_slot __attribute__((unused)) = -1;
1891  int found_np_slot = -1;
1892  int removed_np_slot = -1;
1893  int j;
1894  SCOPE_ENTER(3, "%s: slot: %d DP: %s DA: %s CA: %s\n", session_name, i,
1895  ast_str_tmp(128, ast_stream_to_str(dp_stream, &STR_TMP)),
1896  ast_str_tmp(128, ast_stream_to_str(da_stream, &STR_TMP)),
1897  ast_str_tmp(128, ast_stream_to_str(ca_stream, &STR_TMP)));
1898 
1899  if (STATE_NONE(da_state) && STATE_NONE(dp_state) && STATE_NONE(ca_state)) {
1900  SCOPE_EXIT_EXPR(break, "%s: All gone\n", session_name);
1901  }
1902 
1903  /*
1904  * Simple cases are handled first to avoid having to search the NP and DA
1905  * topologies for streams with the same name but not in the same position.
1906  */
1907 
1908  if (STATE_NONE(dp_state) && !STATE_NONE(da_state)) {
1909  /*
1910  * The slot in the delayed pending topology can't be empty if the delayed
1911  * active topology has a stream there. Streams can't just go away. They
1912  * can be reused or marked "removed" but they can't go away.
1913  */
1914  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: DP slot is empty but DA is not\n", session_name);
1915  }
1916 
1917  if (STATE_NONE(dp_state)) {
1918  /*
1919  * The current active topology can certainly have streams that weren't
1920  * in existence when the delayed request was queued. In this case,
1921  * no action is needed since we already copied the current active topology
1922  * to the new pending one.
1923  */
1924  SCOPE_EXIT_EXPR(continue, "%s: No DP stream so use CA stream as is\n", session_name);
1925  }
1926 
1927  if (ast_strings_equal(dp_name, da_name) && ast_strings_equal(da_name, ca_name)) {
1928  /*
1929  * The delayed pending stream in this slot matches by name, the streams
1930  * in the same slot in the other two topologies. Easy case.
1931  */
1932  ast_trace(-1, "%s: Same stream in all 3 states\n", session_name);
1933  if (dp_state == da_state && da_state == ca_state) {
1934  /* All the same state, no need to update. */
1935  SCOPE_EXIT_EXPR(continue, "%s: All in the same state so nothing to do\n", session_name);
1936  }
1937  if (da_state != ca_state) {
1938  /*
1939  * Something set the CA state between the time this request was queued
1940  * and now. The CA state wins so we don't do anything.
1941  */
1942  SCOPE_EXIT_EXPR(continue, "%s: Ignoring request to change state from %s to %s\n",
1943  session_name, ast_stream_state2str(ca_state), ast_stream_state2str(dp_state));
1944  }
1945  if (dp_state != da_state) {
1946  /* DP needs to update the state */
1947  ast_stream_set_state(np_stream, dp_state);
1948  SCOPE_EXIT_EXPR(continue, "%s: Changed NP stream state from %s to %s\n",
1949  session_name, ast_stream_state2str(ca_state), ast_stream_state2str(dp_state));
1950  }
1951  }
1952 
1953  /*
1954  * We're done with the simple cases. For the rest, we need to identify if the
1955  * DP stream we're trying to take action on is already in the other topologies
1956  * possibly in a different slot. To do that, if the stream in the DA or CA slots
1957  * doesn't match the current DP stream, we need to iterate over the topology
1958  * looking for a stream with the same name.
1959  */
1960 
1961  /*
1962  * Since we already copied all of the CA streams to the NP topology, we'll use it
1963  * instead of CA because we'll be updating the NP as we go.
1964  */
1965  if (!ast_strings_equal(dp_name, np_name)) {
1966  /*
1967  * The NP stream in this slot doesn't have the same name as the DP stream
1968  * so we need to see if it's in another NP slot. We're not going to stop
1969  * when we find a matching stream because we also want to find the first
1970  * removed removed slot, if any, so we can re-use this slot. We'll break
1971  * early if we find both before we reach the end.
1972  */
1973  ast_trace(-1, "%s: Checking if DP is already in NP somewhere\n", session_name);
1974  for (j = 0; j < ast_stream_topology_get_count(new_pending); j++) {
1975  struct ast_stream *possible_existing = ast_stream_topology_get_stream(new_pending, j);
1976  const char *possible_existing_name = GET_STREAM_NAME_SAFE(possible_existing);
1977 
1978  ast_trace(-1, "%s: Checking %s against %s\n", session_name, dp_name, possible_existing_name);
1979  if (found_np_slot == -1 && ast_strings_equal(dp_name, possible_existing_name)) {
1980  ast_trace(-1, "%s: Pending stream %s slot %d is in NP slot %d\n", session_name,
1981  dp_name, i, j);
1982  found_np_slot = j;
1983  found_np_stream = possible_existing;
1984  found_np_state = ast_stream_get_state(possible_existing);
1985  found_np_name = ast_stream_get_name(possible_existing);
1986  }
1987  if (STREAM_REMOVED(possible_existing) && removed_np_slot == -1) {
1988  removed_np_slot = j;
1989  }
1990  if (removed_np_slot >= 0 && found_np_slot >= 0) {
1991  break;
1992  }
1993  }
1994  } else {
1995  /* Makes the subsequent code easier */
1996  found_np_slot = i;
1997  found_np_stream = np_stream;
1998  found_np_state = np_state;
1999  found_np_name = np_name;
2000  }
2001 
2002  if (!ast_strings_equal(dp_name, da_name)) {
2003  /*
2004  * The DA stream in this slot doesn't have the same name as the DP stream
2005  * so we need to see if it's in another DA slot. In real life, the DA stream
2006  * in this slot could have a different name but there shouldn't be a case
2007  * where the DP stream is another slot in the DA topology. Just in case though.
2008  * We don't care about removed slots in the DA topology.
2009  */
2010  ast_trace(-1, "%s: Checking if DP is already in DA somewhere\n", session_name);
2011  for (j = 0; j < ast_stream_topology_get_count(delayed_active); j++) {
2012  struct ast_stream *possible_existing = ast_stream_topology_get_stream(delayed_active, j);
2013  const char *possible_existing_name = GET_STREAM_NAME_SAFE(possible_existing);
2014 
2015  ast_trace(-1, "%s: Checking %s against %s\n", session_name, dp_name, possible_existing_name);
2016  if (ast_strings_equal(dp_name, possible_existing_name)) {
2017  ast_trace(-1, "%s: Pending stream %s slot %d is already in delayed active slot %d\n",
2018  session_name, dp_name, i, j);
2019  found_da_slot = j;
2020  found_da_stream = possible_existing;
2021  found_da_state = ast_stream_get_state(possible_existing);
2022  found_da_name = ast_stream_get_name(possible_existing);
2023  break;
2024  }
2025  }
2026  } else {
2027  /* Makes the subsequent code easier */
2028  found_da_slot = i;
2029  found_da_stream = da_stream;
2030  found_da_state = da_state;
2031  found_da_name = da_name;
2032  }
2033 
2034  ast_trace(-1, "%s: Found NP slot: %d Found removed NP slot: %d Found DA slot: %d\n",
2035  session_name, found_np_slot, removed_np_slot, found_da_slot);
2036 
2037  /*
2038  * Now we know whether the DP stream is new or changing state and we know if the DP
2039  * stream exists in the other topologies and if so, where in those topologies it exists.
2040  */
2041 
2042  if (!found_da_stream) {
2043  /*
2044  * The DP stream isn't in the DA topology which would imply that the intention of the
2045  * request was to add the stream, not change its state. It's possible though that
2046  * the stream was added by another request between the time this request was queued
2047  * and now so we need to check the CA topology as well.
2048  */
2049  ast_trace(-1, "%s: There was no corresponding DA stream so the request was to add a stream\n", session_name);
2050 
2051  if (found_np_stream) {
2052  /*
2053  * We found it in the CA topology. Since the intention was to add it
2054  * and it's already there, there's nothing to do.
2055  */
2056  SCOPE_EXIT_EXPR(continue, "%s: New stream requested but it's already in CA\n", session_name);
2057  } else {
2058  /* OK, it's not in either which would again imply that the intention of the
2059  * request was to add the stream.
2060  */
2061  ast_trace(-1, "%s: There was no corresponding NP stream\n", session_name);
2062  if (STATE_REMOVED(dp_state)) {
2063  /*
2064  * How can DP request to remove a stream that doesn't seem to exist anythere?
2065  * It's not. It's possible that the stream was already removed and the slot
2066  * reused in the CA topology, but it would still have to exist in the DA
2067  * topology. Bail.
2068  */
2070  "%s: Attempting to remove stream %d:%s but it doesn't exist anywhere.\n", session_name, i, dp_name);
2071  } else {
2072  /*
2073  * We're now sure we want to add the the stream. Since we can re-use
2074  * slots in the CA topology that have streams marked as "removed", we
2075  * use the slot we saved in removed_np_slot if it exists.
2076  */
2077  ast_trace(-1, "%s: Checking for open slot\n", session_name);
2078  if (removed_np_slot >= 0) {
2079  struct ast_sip_session_media *old_media = AST_VECTOR_GET(&new_pending_state->sessions, removed_np_slot);
2080  res = ast_stream_topology_set_stream(new_pending, removed_np_slot, ast_stream_clone(dp_stream, NULL));
2081  if (res != 0) {
2082  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't set stream in new topology\n", session_name);
2083  }
2084  /*
2085  * Since we're reusing the removed_np_slot slot for something else, we need
2086  * to free and remove any session media already in it.
2087  * ast_stream_topology_set_stream() took care of freeing the old stream.
2088  */
2089  res = AST_VECTOR_REPLACE(&new_pending_state->sessions, removed_np_slot, NULL);
2090  if (res != 0) {
2091  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't replace media session\n", session_name);
2092  }
2093 
2094  ao2_cleanup(old_media);
2095  SCOPE_EXIT_EXPR(continue, "%s: Replaced removed stream in slot %d\n",
2096  session_name, removed_np_slot);
2097  } else {
2098  int new_slot = ast_stream_topology_append_stream(new_pending, ast_stream_clone(dp_stream, NULL));
2099  if (new_slot < 0) {
2100  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't append stream in new topology\n", session_name);
2101  }
2102 
2103  res = AST_VECTOR_REPLACE(&new_pending_state->sessions, new_slot, NULL);
2104  if (res != 0) {
2105  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't replace media session\n", session_name);
2106  }
2107  SCOPE_EXIT_EXPR(continue, "%s: Appended new stream to slot %d\n",
2108  session_name, new_slot);
2109  }
2110  }
2111  }
2112  } else {
2113  /*
2114  * The DP stream exists in the DA topology so it's a change of some sort.
2115  */
2116  ast_trace(-1, "%s: There was a corresponding DA stream so the request was to change/remove a stream\n", session_name);
2117  if (dp_state == found_da_state) {
2118  /* No change? Let's see if it's in CA */
2119  if (!found_np_stream) {
2120  /*
2121  * The DP and DA state are the same which would imply that the stream
2122  * already exists but it's not in the CA topology. It's possible that
2123  * between the time this request was queued and now the stream was removed
2124  * from the CA topology and the slot used for something else. Nothing
2125  * we can do here.
2126  */
2127  SCOPE_EXIT_EXPR(continue, "%s: Stream doesn't exist in CA so nothing to do\n", session_name);
2128  } else if (dp_state == found_np_state) {
2129  SCOPE_EXIT_EXPR(continue, "%s: States are the same all around so nothing to do\n", session_name);
2130  } else {
2131  SCOPE_EXIT_EXPR(continue, "%s: Something changed the CA state so we're going to leave it as is\n", session_name);
2132  }
2133  } else {
2134  /* We have a state change. */
2135  ast_trace(-1, "%s: Requesting state change to %s\n", session_name, ast_stream_state2str(dp_state));
2136  if (!found_np_stream) {
2137  SCOPE_EXIT_EXPR(continue, "%s: Stream doesn't exist in CA so nothing to do\n", session_name);
2138  } else if (da_state == found_np_state) {
2139  ast_stream_set_state(found_np_stream, dp_state);
2140  SCOPE_EXIT_EXPR(continue, "%s: Changed NP stream state from %s to %s\n",
2141  session_name, ast_stream_state2str(found_np_state), ast_stream_state2str(dp_state));
2142  } else {
2143  SCOPE_EXIT_EXPR(continue, "%s: Something changed the CA state so we're going to leave it as is\n",
2144  session_name);
2145  }
2146  }
2147  }
2148 
2149  SCOPE_EXIT("%s: Done with slot %d\n", session_name, i);
2150  }
2151 
2152  ast_trace(-1, "%s: Resetting default media states\n", session_name);
2153  for (i = 0; i < AST_MEDIA_TYPE_END; i++) {
2154  int j;
2155  new_pending_state->default_session[i] = NULL;
2156  for (j = 0; j < AST_VECTOR_SIZE(&new_pending_state->sessions); j++) {
2157  struct ast_sip_session_media *media = AST_VECTOR_GET(&new_pending_state->sessions, j);
2158  struct ast_stream *stream = ast_stream_topology_get_stream(new_pending_state->topology, j);
2159 
2160  if (media && media->type == i && !STREAM_REMOVED(stream)) {
2161  new_pending_state->default_session[i] = media;
2162  break;
2163  }
2164  }
2165  }
2166 
2167  if (run_post_validation) {
2168  ast_trace(-1, "%s: Running post-validation\n", session_name);
2169  if (!is_media_state_valid(session_name, new_pending_state)) {
2170  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "State not consistent\n");
2171  }
2172  }
2173 
2174  /*
2175  * We need to move the new pending state to another variable and set new_pending_state to NULL
2176  * so RAII_VAR doesn't free it.
2177  */
2178  returned_media_state = new_pending_state;
2179  new_pending_state = NULL;
2180  SCOPE_EXIT_RTN_VALUE(returned_media_state, "%s: NP: %s\n", session_name,
2181  ast_str_tmp(256, ast_stream_topology_to_str(new_pending, &STR_TMP)));
2182 }
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
Definition: logger.h:940
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition: stream.c:337
Structure which contains media state information (streams, sessions)
static int is_media_state_valid(const char *session_name, struct ast_sip_session_media_state *state)
#define STREAM_REMOVED(_stream)
#define STATE_NONE(_stream_state)
#define LOG_WARNING
Definition: logger.h:274
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
ast_stream_state
States that a stream may be in.
Definition: stream.h:74
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
#define MAX(a, b)
Definition: utils.h:228
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
#define SCOPE_EXIT_EXPR(__expr,...)
Definition: logger.h:834
Sentinel.
Definition: stream.h:98
#define LOG_ERROR
Definition: logger.h:285
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:239
#define GET_STREAM_SAFE(_topology, _i)
#define STATE_REMOVED(_stream_state)
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
struct ast_sip_session_media_state * ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state)
Clone a media state.
#define GET_STREAM_STATE_SAFE(_stream)
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
enum ast_media_type type
Media type of this session media.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream * ast_stream_clone(const struct ast_stream *stream, const char *name)
Create a deep clone of an existing stream.
Definition: stream.c:257
struct ast_stream_topology * topology
The media stream topology.
#define GET_STREAM_NAME_SAFE(_stream)
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
Definition: stream.c:388
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:284
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ sdp_handler_list_cmp()

static int sdp_handler_list_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 129 of file res_pjsip_session.c.

References CMP_MATCH, CMP_STOP, OBJ_KEY, and sdp_handler_list::stream_type.

Referenced by load_module().

130 {
131  struct sdp_handler_list *handler_list1 = obj;
132  struct sdp_handler_list *handler_list2 = arg;
133  const char *stream_type2 = flags & OBJ_KEY ? arg : handler_list2->stream_type;
134 
135  return strcmp(handler_list1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
136 }
#define OBJ_KEY
Definition: astobj2.h:1155

◆ sdp_handler_list_hash()

static int sdp_handler_list_hash ( const void *  obj,
int  flags 
)
static

Definition at line 107 of file res_pjsip_session.c.

References ast_str_hash(), OBJ_KEY, and sdp_handler_list::stream_type.

Referenced by load_module().

108 {
109  const struct sdp_handler_list *handler_list = obj;
110  const char *stream_type = flags & OBJ_KEY ? obj : handler_list->stream_type;
111 
112  return ast_str_hash(stream_type);
113 }
#define OBJ_KEY
Definition: astobj2.h:1155
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206

◆ sdp_requires_deferral()

static int sdp_requires_deferral ( struct ast_sip_session session,
const pjmedia_sdp_session *  sdp 
)
static

Determine whether the SDP provided requires deferral of negotiating or not.

Return values
1re-invite should be deferred and resumed later
0re-invite should not be deferred

Definition at line 2600 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ao2_cleanup, ao2_find, ast_codec_media_type2str(), ast_copy_pj_str(), ast_debug, AST_LIST_TRAVERSE, ast_media_type_from_str(), ast_sip_session_get_name(), ast_sip_session_is_pending_stream_default(), ast_sip_session_media_state_add(), AST_SIP_SESSION_SDP_DEFER_ERROR, AST_SIP_SESSION_SDP_DEFER_NEEDED, AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED, AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED, ast_stream_alloc(), ast_stream_free(), ast_stream_get_metadata(), ast_stream_get_name(), ast_stream_set_metadata(), ast_stream_set_state(), AST_STREAM_STATE_INACTIVE, AST_STREAM_STATE_RECVONLY, AST_STREAM_STATE_SENDONLY, AST_STREAM_STATE_SENDRECV, ast_stream_topology_alloc(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_set_stream(), ast_strlen_zero, ast_sip_session_sdp_handler::defer_incoming_sdp_stream, handler(), ast_sip_session_media::handler, NULL, OBJ_KEY, ast_sip_session::pending_media_state, RAII_VAR, session_media_set_handler(), ast_sip_session_media_state::topology, and type.

Referenced by session_reinvite_on_rx_request().

2601 {
2602  int i;
2603 
2604  if (!session->pending_media_state->topology) {
2606  if (!session->pending_media_state->topology) {
2607  return -1;
2608  }
2609  }
2610 
2611  for (i = 0; i < sdp->media_count; ++i) {
2612  /* See if there are registered handlers for this media stream type */
2613  char media[20];
2615  RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
2616  struct ast_stream *existing_stream = NULL;
2617  struct ast_stream *stream;
2618  enum ast_media_type type;
2619  struct ast_sip_session_media *session_media = NULL;
2621  pjmedia_sdp_media *remote_stream = sdp->media[i];
2622 
2623  /* We need a null-terminated version of the media string */
2624  ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
2625 
2626  if (session->active_media_state->topology &&
2628  existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
2629  }
2630 
2631  type = ast_media_type_from_str(media);
2632  stream = ast_stream_alloc(existing_stream ? ast_stream_get_name(existing_stream) : ast_codec_media_type2str(type), type);
2633  if (!stream) {
2634  return -1;
2635  }
2636 
2637  /* As this is only called on an incoming SDP offer before processing it is not possible
2638  * for streams and their media sessions to exist.
2639  */
2640  if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
2641  ast_stream_free(stream);
2642  return -1;
2643  }
2644 
2645  if (existing_stream) {
2646  const char *stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
2647 
2648  if (!ast_strlen_zero(stream_label)) {
2649  ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
2650  }
2651  }
2652 
2653  session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
2654  if (!session_media) {
2655  return -1;
2656  }
2657 
2658  /* For backwards compatibility with the core the default audio stream is always sendrecv */
2659  if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
2660  if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
2661  /* Stream state reflects our state of a stream, so in the case of
2662  * sendonly and recvonly we store the opposite since that is what ours
2663  * is.
2664  */
2666  } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
2668  } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
2670  } else {
2672  }
2673  } else {
2675  }
2676 
2677  if (session_media->handler) {
2678  handler = session_media->handler;
2679  if (handler->defer_incoming_sdp_stream) {
2680  res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2681  sdp->media[i]);
2682  switch (res) {
2684  break;
2686  return 0;
2688  break;
2690  return 1;
2691  }
2692  }
2693  /* Handled by this handler. Move to the next stream */
2694  continue;
2695  }
2696 
2697  handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
2698  if (!handler_list) {
2699  ast_debug(3, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
2700  continue;
2701  }
2702  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
2703  if (handler == session_media->handler) {
2704  continue;
2705  }
2706  if (!handler->defer_incoming_sdp_stream) {
2707  continue;
2708  }
2709  res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2710  sdp->media[i]);
2711  switch (res) {
2713  continue;
2715  session_media_set_handler(session_media, handler);
2716  return 0;
2718  /* Handled by this handler. */
2719  session_media_set_handler(session_media, handler);
2720  break;
2722  /* Handled by this handler. */
2723  session_media_set_handler(session_media, handler);
2724  return 1;
2725  }
2726  /* Move to the next stream */
2727  break;
2728  }
2729  }
2730  return 0;
2731 }
static const char type[]
Definition: chan_ooh323.c:109
struct ast_sip_session_media_state * pending_media_state
#define OBJ_KEY
Definition: astobj2.h:1155
A handler for SDPs in SIP sessions.
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
enum ast_media_type ast_media_type_from_str(const char *media_type_str)
Conversion function to take a media string and convert it to a media type.
Definition: codec.c:363
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_sip_session_media_state * active_media_state
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *session, const struct ast_stream *stream)
Determines if a provided pending stream will be the default stream or not.
static void session_media_set_handler(struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
Set an SDP stream handler for a corresponding session media.
Set when the stream is sending and receiving media.
Definition: stream.h:82
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
struct ast_sip_session_media * ast_sip_session_media_state_add(struct ast_sip_session *session, struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
Allocate an ast_session_media and add it to the media state&#39;s vector.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
ast_sip_session_sdp_stream_defer
Set when the stream is sending media only.
Definition: stream.h:86
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
Definition: stream.c:460
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition: stream.c:423
enum ast_sip_session_sdp_stream_defer(* defer_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
Determine whether a stream requires that the re-invite be deferred. If a stream can not be immediatel...
ast_media_type
Types of media.
Definition: codec.h:30
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
Set when the stream is receiving media only.
Definition: stream.h:90

◆ send_delayed_request()

static int send_delayed_request ( struct ast_sip_session session,
struct ast_sip_session_delayed_request delay 
)
static

Definition at line 1394 of file res_pjsip_session.c.

References ast_sip_session_delayed_request::active_media_state, ast_sip_session_get_name(), AST_SIP_SESSION_REFRESH_METHOD_INVITE, AST_SIP_SESSION_REFRESH_METHOD_UPDATE, ast_sip_session_terminate(), delayed_method2str(), DELAYED_METHOD_BYE, DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, ast_sip_session_delayed_request::generate_new_sdp, LOG_WARNING, ast_sip_session_delayed_request::method, NULL, ast_sip_session_delayed_request::on_request_creation, ast_sip_session_delayed_request::on_response, ast_sip_session_delayed_request::on_sdp_creation, ast_sip_session_delayed_request::pending_media_state, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, and sip_session_refresh().

Referenced by invite_proceeding(), and invite_terminated().

1395 {
1396  int res;
1397  SCOPE_ENTER(3, "%s: sending delayed %s request\n",
1398  ast_sip_session_get_name(session),
1399  delayed_method2str(delay->method));
1400 
1401  switch (delay->method) {
1402  case DELAYED_METHOD_INVITE:
1403  res = sip_session_refresh(session, delay->on_request_creation,
1404  delay->on_sdp_creation, delay->on_response,
1406  delay->active_media_state, 1);
1407  /* Ownership of media state transitions to ast_sip_session_refresh */
1408  delay->pending_media_state = NULL;
1409  delay->active_media_state = NULL;
1410  SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
1411  case DELAYED_METHOD_UPDATE:
1412  res = sip_session_refresh(session, delay->on_request_creation,
1413  delay->on_sdp_creation, delay->on_response,
1415  delay->active_media_state, 1);
1416  /* Ownership of media state transitions to ast_sip_session_refresh */
1417  delay->pending_media_state = NULL;
1418  delay->active_media_state = NULL;
1419  SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
1420  case DELAYED_METHOD_BYE:
1421  ast_sip_session_terminate(session, 0);
1422  SCOPE_EXIT_RTN_VALUE(0, "%s: Terminating session on delayed BYE\n", ast_sip_session_get_name(session));
1423  }
1424 
1425  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",
1426  ast_sip_session_get_name(session),
1427  delayed_method2str(delay->method), delay->method);
1428 }
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
Definition: logger.h:940
ast_sip_session_sdp_creation_cb on_sdp_creation
struct ast_sip_session_media_state * pending_media_state
#define LOG_WARNING
Definition: logger.h:274
ast_sip_session_request_creation_cb on_request_creation
static const char * delayed_method2str(enum delayed_method method)
#define NULL
Definition: resample.c:96
struct ast_sip_session_media_state * active_media_state
static int sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queued)
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
ast_sip_session_response_cb on_response
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
void ast_sip_session_terminate(struct ast_sip_session *session, int response)
Terminate a session and, if possible, send the provided response code.

◆ session_datastore_destroy()

static void session_datastore_destroy ( void *  obj)
static

Definition at line 1229 of file res_pjsip_session.c.

References ast_free, ast_datastore::data, ast_datastore_info::destroy, ast_datastore::info, NULL, and ast_datastore::uid.

Referenced by ast_sip_session_alloc_datastore().

1230 {
1231  struct ast_datastore *datastore = obj;
1232 
1233  /* Using the destroy function (if present) destroy the data */
1234  if (datastore->info->destroy != NULL && datastore->data != NULL) {
1235  datastore->info->destroy(datastore->data);
1236  datastore->data = NULL;
1237  }
1238 
1239  ast_free((void *) datastore->uid);
1240  datastore->uid = NULL;
1241 }
Structure for a data store object.
Definition: datastore.h:68
#define NULL
Definition: resample.c:96
const char * uid
Definition: datastore.h:69
const struct ast_datastore_info * info
Definition: datastore.h:71
void(* destroy)(void *data)
Definition: datastore.h:34
#define ast_free(a)
Definition: astmm.h:182
void * data
Definition: datastore.h:70

◆ session_destructor()

static void session_destructor ( void *  obj)
static

Definition at line 2900 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ao2_cleanup, ast_sip_session::aor, ast_debug, ast_dsp_free(), ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, ast_party_id_free(), ast_sip_session_get_name(), ast_sip_session_media_state_free(), ast_sip_session_remove_supplements(), ast_sorcery_object_get_id(), ast_strdupa, ast_taskprocessor_unreference(), ast_test_suite_event_notify, AST_VECTOR_FREE, AST_VECTOR_RESET, ast_sip_session::contact, ast_sip_session::datastores, delayed_request_free(), ast_sip_session::delayed_requests, ast_sip_session::direct_media_cap, ast_sip_session::dsp, ast_sip_session::endpoint, handle_session_destroy(), ast_sip_session::id, ast_sip_session::inv_session, ast_sip_session_delayed_request::next, ast_sip_session::pending_media_state, ast_sip_session::serializer, and ast_sip_session::supplements.

Referenced by ast_sip_session_alloc().

2901 {
2902  struct ast_sip_session *session = obj;
2903  struct ast_sip_session_delayed_request *delay;
2904 
2905 #ifdef TEST_FRAMEWORK
2906  /* We dup the endpoint ID in case the endpoint gets freed out from under us */
2907  const char *endpoint_name = session->endpoint ?
2908  ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>";
2909 #endif
2910 
2911  ast_debug(3, "%s: Destroying SIP session\n", ast_sip_session_get_name(session));
2912 
2913  ast_test_suite_event_notify("SESSION_DESTROYING",
2914  "Endpoint: %s\r\n"
2915  "AOR: %s\r\n"
2916  "Contact: %s"
2917  , endpoint_name
2918  , session->aor ? ast_sorcery_object_get_id(session->aor) : "<none>"
2919  , session->contact ? ast_sorcery_object_get_id(session->contact) : "<none>"
2920  );
2921 
2922  /* fire session destroy handler */
2923  handle_session_destroy(session);
2924 
2925  /* remove all registered supplements */
2928 
2929  /* remove all saved media stats */
2930  AST_VECTOR_RESET(&session->media_stats, ast_free);
2931  AST_VECTOR_FREE(&session->media_stats);
2932 
2934  ao2_cleanup(session->datastores);
2937 
2938  while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
2939  delayed_request_free(delay);
2940  }
2941  ast_party_id_free(&session->id);
2942  ao2_cleanup(session->endpoint);
2943  ao2_cleanup(session->aor);
2944  ao2_cleanup(session->contact);
2945  ao2_cleanup(session->direct_media_cap);
2946 
2947  ast_dsp_free(session->dsp);
2948 
2949  if (session->inv_session) {
2950  struct pjsip_dialog *dlg = session->inv_session->dlg;
2951 
2952  /* The INVITE session uses the dialog pool for memory, so we need to
2953  * decrement its reference first before that of the dialog.
2954  */
2955 
2956 #ifdef HAVE_PJSIP_INV_SESSION_REF
2957  pjsip_inv_dec_ref(session->inv_session);
2958 #endif
2959  pjsip_dlg_dec_session(dlg, &session_module);
2960  }
2961 
2962  ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name);
2963 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_sip_endpoint * endpoint
struct ast_sip_session_media_state * pending_media_state
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
struct ao2_container * datastores
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition: channel.c:1811
struct ast_sip_session_delayed_request * next
struct pjsip_inv_session * inv_session
A structure describing a SIP session.
struct ast_format_cap * direct_media_cap
struct ast_sip_session_media_state * active_media_state
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
struct ast_dsp * dsp
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ast_mansession session
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static pjsip_module session_module
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
static void handle_session_destroy(struct ast_sip_session *session)
struct ast_taskprocessor * serializer
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
void ast_sip_session_remove_supplements(struct ast_sip_session *session)
Remove supplements from a SIP session.
#define ast_free(a)
Definition: astmm.h:182
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:627
struct ast_sip_session::@308 supplements
Structure used for sending delayed requests.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_sip_session::@309 delayed_requests
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
struct ast_sip_contact * contact
struct ast_sip_aor * aor
struct ast_party_id id

◆ session_end()

static int session_end ( void *  vsession)
static

Definition at line 4525 of file res_pjsip_session.c.

References handle_session_end(), and sip_session_defer_termination_stop_timer().

Referenced by ast_sip_session_create_outgoing(), ast_sip_session_end_if_deferred(), ast_sip_session_terminate(), and session_inv_on_state_changed().

4526 {
4527  struct ast_sip_session *session = vsession;
4528 
4529  /* Stop the scheduled termination */
4531 
4532  /* Session is dead. Notify the supplements. */
4533  handle_session_end(session);
4534 
4535  return 0;
4536 }
static void handle_session_end(struct ast_sip_session *session)
A structure describing a SIP session.
static struct ast_mansession session
static void sip_session_defer_termination_stop_timer(struct ast_sip_session *session)

◆ session_end_completion()

static int session_end_completion ( void *  vsession)
static

Definition at line 4548 of file res_pjsip_session.c.

References ao2_cleanup, ast_sip_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), ast_sip_session::inv_session, and NULL.

Referenced by ast_sip_session_create_outgoing(), ast_sip_session_terminate(), and session_end_if_disconnected().

4549 {
4550  struct ast_sip_session *session = vsession;
4551 
4554 
4555  /* Now we can release the ref that was held by session->inv_session */
4556  ao2_cleanup(session);
4557  return 0;
4558 }
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
A structure describing a SIP session.
static struct ast_mansession session
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ session_end_if_disconnected()

static int session_end_if_disconnected ( int  id,
pjsip_inv_session *  inv 
)
static

Definition at line 4701 of file res_pjsip_session.c.

References ast_sip_push_task(), id, NULL, ast_sip_session::serializer, session, and session_end_completion().

Referenced by session_inv_on_tsx_state_changed().

4702 {
4703  struct ast_sip_session *session;
4704 
4705  if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
4706  return 0;
4707  }
4708 
4709  /*
4710  * We are locking because ast_sip_dialog_get_session() needs
4711  * the dialog locked to get the session by other threads.
4712  */
4713  pjsip_dlg_inc_lock(inv->dlg);
4714  session = inv->mod_data[id];
4715  inv->mod_data[id] = NULL;
4716  pjsip_dlg_dec_lock(inv->dlg);
4717 
4718  /*
4719  * Pass the session ref held by session->inv_session to
4720  * session_end_completion().
4721  */
4722  if (session
4723  && ast_sip_push_task(session->serializer, session_end_completion, session)) {
4724  /* Do it anyway even though this is not the right thread. */
4725  session_end_completion(session);
4726  }
4727 
4728  return 1;
4729 }
static int session_end_completion(void *vsession)
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
static struct ast_mansession session
struct ast_taskprocessor * serializer
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
enum queue_result id
Definition: app_queue.c:1507

◆ session_inv_on_create_offer()

static void session_inv_on_create_offer ( pjsip_inv_session *  inv,
pjmedia_sdp_session **  p_offer 
)
static

Definition at line 5259 of file res_pjsip_session.c.

References ast_queue_unhold(), ast_sip_session::channel, create_local_sdp(), ast_sip_session::inv_session, and NULL.

5260 {
5261  struct ast_sip_session *session = inv->mod_data[session_module.id];
5262  const pjmedia_sdp_session *previous_sdp = NULL;
5263  pjmedia_sdp_session *offer;
5264  int i;
5265 
5266  if (inv->neg) {
5267  if (pjmedia_sdp_neg_was_answer_remote(inv->neg)) {
5268  pjmedia_sdp_neg_get_active_remote(inv->neg, &previous_sdp);
5269  } else {
5270  pjmedia_sdp_neg_get_active_local(inv->neg, &previous_sdp);
5271  }
5272  }
5273 
5274  offer = create_local_sdp(inv, session, previous_sdp);
5275  if (!offer) {
5276  return;
5277  }
5278 
5279  ast_queue_unhold(session->channel);
5280 
5281  /*
5282  * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite).
5283  * When hold is initially indicated, we
5284  * - Receive an INVITE with no SDP
5285  * - Send a 200 OK with SDP, indicating sendrecv in the media streams
5286  * - Receive an ACK with SDP, indicating sendonly in the media streams
5287  *
5288  * At this point, the pjmedia negotiator saves the state of the media direction so that
5289  * if we are to send any offers, we'll offer recvonly in the media streams. This is
5290  * problematic if the device is attempting to unhold, though. If the device unholds
5291  * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly.
5292  * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond
5293  * with sendonly or inactive. The result of this is that the stream is not off hold.
5294  *
5295  * Therefore, in this case, when we receive a reinvite while the stream is on hold, we
5296  * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv
5297  * in order to get the stream off hold. If this is actually a different purpose reinvite
5298  * (like a session timer refresh), then the answerer can respond to our sendrecv with
5299  * sendonly, keeping the stream on hold.
5300  */
5301  for (i = 0; i < offer->media_count; ++i) {
5302  pjmedia_sdp_media *m = offer->media[i];
5303  pjmedia_sdp_attr *recvonly;
5304  pjmedia_sdp_attr *inactive;
5305  pjmedia_sdp_attr *sendonly;
5306 
5307  recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL);
5308  inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL);
5309  sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL);
5310  if (recvonly || inactive || sendonly) {
5311  pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly;
5312  pjmedia_sdp_attr *sendrecv;
5313 
5314  pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove);
5315 
5316  sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL);
5317  pjmedia_sdp_media_add_attr(m, sendrecv);
5318  }
5319  }
5320 
5321  *p_offer = offer;
5322 }
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1216
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
A structure describing a SIP session.
static struct ast_mansession session
struct ast_channel * channel
static pjsip_module session_module
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)

◆ session_inv_on_media_update()

static void session_inv_on_media_update ( pjsip_inv_session *  inv,
pj_status_t  status 
)
static

Definition at line 5324 of file res_pjsip_session.c.

References ast_sip_media_rtp_configuration::accept_multiple_sdp_answers, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, ast_channel_hangupcause_set(), ast_channel_name(), ast_queue_hangup(), ast_set_hangupsource(), ast_shutdown_final(), ast_sip_session_get_name(), ast_sip_session_media_state_reset(), ast_trace, ast_sip_session::channel, ast_sip_session::endpoint, ast_sip_media_rtp_configuration::follow_early_media_fork, handle_negotiated_sdp(), ast_sip_endpoint::media, ast_sip_session::pending_media_state, ast_sip_endpoint_media_configuration::rtp, SCOPE_ENTER, and SCOPE_EXIT_RTN.

5325 {
5326  struct ast_sip_session *session = inv->mod_data[session_module.id];
5327  const pjmedia_sdp_session *local, *remote;
5328  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
5329 
5330  if (ast_shutdown_final()) {
5331  SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5332  }
5333 
5334  session = inv->mod_data[session_module.id];
5335  if (!session || !session->channel) {
5336  /*
5337  * If we don't have a session or channel then we really
5338  * don't care about media updates.
5339  * Just ignore
5340  */
5341  SCOPE_EXIT_RTN("%s: No channel or session\n", ast_sip_session_get_name(session));
5342  }
5343 
5344  if (session->endpoint) {
5345  int bail = 0;
5346 
5347  /*
5348  * If following_fork is set, then this is probably the result of a
5349  * forked INVITE and SDP asnwers coming from the different fork UAS
5350  * destinations. In this case updated_sdp_answer will also be set.
5351  *
5352  * If only updated_sdp_answer is set, then this is the non-forking
5353  * scenario where the same UAS just needs to change something like
5354  * the media port.
5355  */
5356 
5357  if (inv->following_fork) {
5358  if (session->endpoint->media.rtp.follow_early_media_fork) {
5359  ast_trace(-1, "%s: Following early media fork with different To tags\n", ast_sip_session_get_name(session));
5360  } else {
5361  ast_trace(-1, "%s: Not following early media fork with different To tags\n", ast_sip_session_get_name(session));
5362  bail = 1;
5363  }
5364  }
5365 #ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS
5366  else if (inv->updated_sdp_answer) {
5368  ast_trace(-1, "%s: Accepting updated SDP with same To tag\n", ast_sip_session_get_name(session));
5369  } else {
5370  ast_trace(-1, "%s: Ignoring updated SDP answer with same To tag\n", ast_sip_session_get_name(session));
5371  bail = 1;
5372  }
5373  }
5374 #endif
5375  if (bail) {
5376  SCOPE_EXIT_RTN("%s: Bailing\n", ast_sip_session_get_name(session));
5377  }
5378  }
5379 
5380  if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||
5381  (pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {
5383  ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
5384  ast_queue_hangup(session->channel);
5385  SCOPE_EXIT_RTN("%s: Couldn't get active or local or remote negotiator. Hanging up\n", ast_sip_session_get_name(session));
5386  }
5387 
5388  if (handle_negotiated_sdp(session, local, remote)) {
5390  SCOPE_EXIT_RTN("%s: handle_negotiated_sdp failed. Resetting pending media state\n", ast_sip_session_get_name(session));
5391  }
5392  SCOPE_EXIT_RTN("%s\n", ast_sip_session_get_name(session));
5393 }
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
struct ast_sip_endpoint * endpoint
struct ast_sip_session_media_state * pending_media_state
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
unsigned int accept_multiple_sdp_answers
Definition: res_pjsip.h:723
A structure describing a SIP session.
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
unsigned int follow_early_media_fork
Definition: res_pjsip.h:721
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it&#39;s bridge.
Definition: channel.c:2504
static struct ast_mansession session
struct ast_sip_media_rtp_configuration rtp
Definition: res_pjsip.h:764
struct ast_channel * channel
static pjsip_module session_module
int ast_shutdown_final(void)
Definition: asterisk.c:1829
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
#define AST_CAUSE_BEARERCAPABILITY_NOTAVAIL
Definition: causes.h:129
jack_status_t status
Definition: app_jack.c:146

◆ session_inv_on_new_session()

static void session_inv_on_new_session ( pjsip_inv_session *  inv,
pjsip_event *  e 
)
static

Definition at line 4696 of file res_pjsip_session.c.

4697 {
4698  /* XXX STUB */
4699 }

◆ session_inv_on_redirected()

static pjsip_redirect_op session_inv_on_redirected ( pjsip_inv_session *  inv,
const pjsip_uri *  target,
const pjsip_event *  e 
)
static

Definition at line 5395 of file res_pjsip_session.c.

References ast_copy_pj_str(), AST_MAX_EXTENSION, ast_shutdown_final(), AST_SIP_REDIRECT_URI_CORE, AST_SIP_REDIRECT_URI_PJSIP, AST_SIP_REDIRECT_USER, AST_SIP_SESSION_BEFORE_REDIRECTING, AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_object_get_id(), ast_sip_session::channel, ast_sip_session::endpoint, exten, handle_incoming(), ast_sip_endpoint::redirect_method, and session.

5396 {
5397  struct ast_sip_session *session;
5398  const pjsip_sip_uri *uri;
5399 
5400  if (ast_shutdown_final()) {
5401  return PJSIP_REDIRECT_STOP;
5402  }
5403 
5404  session = inv->mod_data[session_module.id];
5405  if (!session || !session->channel) {
5406  return PJSIP_REDIRECT_STOP;
5407  }
5408 
5410  return PJSIP_REDIRECT_ACCEPT;
5411  }
5412 
5413  if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
5414  return PJSIP_REDIRECT_STOP;
5415  }
5416 
5417  handle_incoming(session, e->body.rx_msg.rdata, AST_SIP_SESSION_BEFORE_REDIRECTING);
5418 
5419  uri = pjsip_uri_get_uri(target);
5420 
5421  if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
5422  char exten[AST_MAX_EXTENSION];
5423 
5424  ast_copy_pj_str(exten, &uri->user, sizeof(exten));
5425 
5426  /*
5427  * We may want to match in the dialplan without any user
5428  * options getting in the way.
5429  */
5431 
5432  ast_channel_call_forward_set(session->channel, exten);
5433  } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
5434  char target_uri[PJSIP_MAX_URL_SIZE];
5435  /* PJSIP/ + endpoint length + / + max URL size */
5436  char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
5437 
5438  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
5439  sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
5440  ast_channel_call_forward_set(session->channel, forward);
5441  }
5442 
5443  return PJSIP_REDIRECT_STOP;
5444 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
struct ast_sip_endpoint * endpoint
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
A structure describing a SIP session.
static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
static struct ast_mansession session
#define AST_MAX_EXTENSION
Definition: channel.h:135
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_channel * channel
static pjsip_module session_module
int ast_shutdown_final(void)
Definition: asterisk.c:1829
enum ast_sip_session_redirect redirect_method
Definition: res_pjsip.h:873

◆ session_inv_on_rx_offer()

static void session_inv_on_rx_offer ( pjsip_inv_session *  inv,
const pjmedia_sdp_session *  offer 
)
static

Definition at line 5236 of file res_pjsip_session.c.

References answer(), ast_shutdown_final(), ast_sip_session_get_name(), ast_sip_session_media_state_reset(), create_local_sdp(), handle_incoming_sdp(), ast_sip_session::pending_media_state, SCOPE_ENTER, and SCOPE_EXIT_RTN.

5237 {
5238  struct ast_sip_session *session = inv->mod_data[session_module.id];
5239  pjmedia_sdp_session *answer;
5240  SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
5241 
5242  if (ast_shutdown_final()) {
5243  SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5244  }
5245 
5246  session = inv->mod_data[session_module.id];
5247  if (handle_incoming_sdp(session, offer)) {
5249  SCOPE_EXIT_RTN("%s: handle_incoming_sdp failed\n", ast_sip_session_get_name(session));
5250  }
5251 
5252  if ((answer = create_local_sdp(inv, session, offer))) {
5253  pjsip_inv_set_sdp_answer(inv, answer);
5254  SCOPE_EXIT_RTN("%s: Set SDP answer\n", ast_sip_session_get_name(session));
5255  }
5256  SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));
5257 }
struct ast_sip_session_media_state * pending_media_state
static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
A structure describing a SIP session.
static struct ast_mansession session
static pjsip_module session_module
static int answer(void *data)
Definition: chan_pjsip.c:682
int ast_shutdown_final(void)
Definition: asterisk.c:1829
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.

◆ session_inv_on_state_changed()

static void session_inv_on_state_changed ( pjsip_inv_session *  inv,
pjsip_event *  e 
)
static

Definition at line 4615 of file res_pjsip_session.c.

References ast_debug, ast_shutdown_final(), ast_sip_push_task(), ast_sip_session_get_name(), check_request_status(), ast_sip_session::defer_end, ast_sip_session::ended_while_deferred, handle_incoming_before_media(), NULL, print_debug_details, SCOPE_ENTER, SCOPE_EXIT_RTN, ast_sip_session::serializer, session_end(), and type.

4616 {
4617  pjsip_event_id_e type;
4618  struct ast_sip_session *session = inv->mod_data[session_module.id];
4619  SCOPE_ENTER(1, "%s Event: %s Inv State: %s\n", ast_sip_session_get_name(session),
4620  pjsip_event_str(e->type), pjsip_inv_state_name(inv->state));
4621 
4622  if (ast_shutdown_final()) {
4623  SCOPE_EXIT_RTN("Shutting down\n");
4624  }
4625 
4626  if (e) {
4627  print_debug_details(inv, NULL, e);
4628  type = e->type;
4629  } else {
4630  type = PJSIP_EVENT_UNKNOWN;
4631  }
4632 
4633  session = inv->mod_data[session_module.id];
4634  if (!session) {
4635  SCOPE_EXIT_RTN("No session\n");
4636  }
4637 
4638  switch(type) {
4639  case PJSIP_EVENT_TX_MSG:
4640  break;
4641  case PJSIP_EVENT_RX_MSG:
4642  handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);
4643  break;
4644  case PJSIP_EVENT_TSX_STATE:
4645  ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),
4646  pjsip_event_str(e->body.tsx_state.type));
4647  /* Transaction state changes are prompted by some other underlying event. */
4648  switch(e->body.tsx_state.type) {
4649  case PJSIP_EVENT_TX_MSG:
4650  break;
4651  case PJSIP_EVENT_RX_MSG:
4652  if (!check_request_status(inv, e)) {
4653  handle_incoming_before_media(inv, session, e->body.tsx_state.src.rdata);
4654  }
4655  break;
4656  case PJSIP_EVENT_TRANSPORT_ERROR:
4657  case PJSIP_EVENT_TIMER:
4658  /*
4659  * Check the request status on transport error or timeout. A transport
4660  * error can occur when a TCP socket closes and that can be the result
4661  * of a 503. Also we may need to failover on a timeout (408).
4662  */
4663  check_request_status(inv, e);
4664  break;
4665  case PJSIP_EVENT_USER:
4666  case PJSIP_EVENT_UNKNOWN:
4667  case PJSIP_EVENT_TSX_STATE:
4668  /* Inception? */
4669  break;
4670  }
4671  break;
4672  case PJSIP_EVENT_TRANSPORT_ERROR:
4673  case PJSIP_EVENT_TIMER:
4674  case PJSIP_EVENT_UNKNOWN:
4675  case PJSIP_EVENT_USER:
4676  default:
4677  break;
4678  }
4679 
4680  if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
4681  if (session->defer_end) {
4682  ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));
4683  session->ended_while_deferred = 1;
4684  SCOPE_EXIT_RTN("Deferring\n");
4685  }
4686 
4687  if (ast_sip_push_task(session->serializer, session_end, session)) {
4688  /* Do it anyway even though this is not the right thread. */
4689  session_end(session);
4690  }
4691  }
4692 
4693  SCOPE_EXIT_RTN();
4694 }
unsigned int defer_end
static const char type[]
Definition: chan_ooh323.c:109
#define print_debug_details(inv, tsx, e)
unsigned int ended_while_deferred
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
static int session_end(void *vsession)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ast_mansession session
static int check_request_status(pjsip_inv_session *inv, pjsip_event *e)
static void handle_incoming_before_media(pjsip_inv_session *inv, struct ast_sip_session *session, pjsip_rx_data *rdata)
static pjsip_module session_module
struct ast_taskprocessor * serializer
int ast_shutdown_final(void)
Definition: asterisk.c:1829
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.

◆ session_inv_on_tsx_state_changed()

static void session_inv_on_tsx_state_changed ( pjsip_inv_session *  inv,
pjsip_transaction *  tsx,
pjsip_event *  e 
)
static

Definition at line 4731 of file res_pjsip_session.c.

References AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, ast_channel_hangupcause(), ast_channel_name(), ast_debug, AST_LIST_EMPTY, ast_shutdown_final(), ast_sip_create_request_with_auth(), ast_sip_mod_data_get, AST_SIP_SESSION_AFTER_MEDIA, ast_sip_session_get_name(), ast_sip_session_send_request(), ast_sip_session_send_request_with_cb(), ast_sorcery_object_get_id(), ast_test_suite_event_notify, ast_sip_session::authentication_challenge_count, ast_sip_session::channel, check_delayed_requests(), ast_sip_session::delayed_requests, ast_sip_session::endpoint, handle_incoming(), id, ast_sip_session::inv_session, invite_proceeding(), invite_terminated(), MAX_RX_CHALLENGES, MOD_DATA_ON_RESPONSE, NULL, ast_sip_endpoint::outbound_auths, print_debug_details, reschedule_reinvite(), SCOPE_ENTER, SCOPE_EXIT_RTN, session_end_if_disconnected(), and update_completed().

4732 {
4734  int id = session_module.id;
4735  pjsip_tx_data *tdata;
4736  struct ast_sip_session *session = inv->mod_data[session_module.id];
4737  SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4738  pjsip_tsx_state_str(tsx->state), pjsip_inv_state_name(inv->state));
4739 
4740  if (ast_shutdown_final()) {
4741  SCOPE_EXIT_RTN("Shutting down\n");
4742  }
4743 
4744  session = inv->mod_data[id];
4745 
4746  print_debug_details(inv, tsx, e);
4747  if (!session) {
4748  /* The session has ended. Ignore the transaction change. */
4749  SCOPE_EXIT_RTN("Session ended\n");
4750  }
4751 
4752  /*
4753  * If the session is disconnected really nothing else to do unless currently transacting
4754  * a BYE. If a BYE then hold off destruction until the transaction timeout occurs. This
4755  * has to be done for BYEs because sometimes the dialog can be in a disconnected
4756  * state but the BYE request transaction has not yet completed.
4757  */
4758  if (tsx->method.id != PJSIP_BYE_METHOD && session_end_if_disconnected(id, inv)) {
4759  SCOPE_EXIT_RTN("Disconnected\n");
4760  }
4761 
4762  switch (e->body.tsx_state.type) {
4763  case PJSIP_EVENT_TX_MSG:
4764  /* When we create an outgoing request, we do not have access to the transaction that
4765  * is created. Instead, We have to place transaction-specific data in the tdata. Here,
4766  * we transfer the data into the transaction. This way, when we receive a response, we
4767  * can dig this data out again
4768  */
4769  tsx->mod_data[id] = e->body.tsx_state.src.tdata->mod_data[id];
4770  break;
4771  case PJSIP_EVENT_RX_MSG:
4772  cb = ast_sip_mod_data_get(tsx->mod_data, id, MOD_DATA_ON_RESPONSE);
4773  /* As the PJSIP invite session implementation responds with a 200 OK before we have a
4774  * chance to be invoked session supplements for BYE requests actually end up executing
4775  * in the invite session state callback as well. To prevent session supplements from
4776  * running on the BYE request again we explicitly squash invocation of them here.
4777  */
4778  if ((e->body.tsx_state.src.rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) ||
4779  (tsx->method.id != PJSIP_BYE_METHOD)) {
4780  handle_incoming(session, e->body.tsx_state.src.rdata,
4782  }
4783  if (tsx->method.id == PJSIP_INVITE_METHOD) {
4784  if (tsx->role == PJSIP_ROLE_UAC) {
4785  if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
4786  /* This means we got a non 2XX final response to our outgoing INVITE */
4787  if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
4788  reschedule_reinvite(session, cb);
4789  SCOPE_EXIT_RTN("Non 2XX final response\n");
4790  }
4791  if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
4792  ast_debug(1, "%s: reINVITE received final response code %d\n",
4793  ast_sip_session_get_name(session),
4794  tsx->status_code);
4795  if ((tsx->status_code == 401 || tsx->status_code == 407)
4798  &session->endpoint->outbound_auths,
4799  e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
4800  /* Send authed reINVITE */
4801  ast_sip_session_send_request_with_cb(session, tdata, cb);
4802  SCOPE_EXIT_RTN("Sending authed reinvite\n");
4803  }
4804  /* Per RFC3261 14.1 a response to a re-INVITE should only terminate
4805  * the dialog if a 481 or 408 occurs. All other responses should leave
4806  * the dialog untouched.
4807  */
4808  if (tsx->status_code == 481 || tsx->status_code == 408) {
4809  if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
4810  && tdata) {
4811  ast_sip_session_send_request(session, tdata);
4812  }
4813  }
4814  }
4815  } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
4816  if (!inv->cancelling
4817  && inv->role == PJSIP_ROLE_UAC
4818  && inv->state == PJSIP_INV_STATE_CONFIRMED
4819  && pjmedia_sdp_neg_was_answer_remote(inv->neg)
4820  && pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE
4822  ) {
4823  /*
4824  * We didn't send a CANCEL but the UAS sent us the 200 OK with an invalid or unacceptable codec SDP.
4825  * In this case the SDP negotiation is incomplete and PJPROJECT has already sent the ACK.
4826  * So, we send the BYE with 503 status code here. And the actual hangup cause code is already set
4827  * to AST_CAUSE_BEARERCAPABILITY_NOTAVAIL by the session_inv_on_media_update(), setting the 503
4828  * status code doesn't affect to hangup cause code.
4829  */
4830  ast_debug(1, "Endpoint '%s(%s)': Ending session due to 200 OK with incomplete SDP negotiation. %s\n",
4832  session->channel ? ast_channel_name(session->channel) : "",
4833  pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4834  pjsip_inv_end_session(session->inv_session, 503, NULL, &tdata);
4835  SCOPE_EXIT_RTN("Incomplete SDP negotiation\n");
4836  }
4837 
4838  if (inv->cancelling && tsx->status_code == PJSIP_SC_OK) {
4839  int sdp_negotiation_done =
4840  pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE;
4841 
4842  /*
4843  * We can get here for the following reasons.
4844  *
4845  * 1) The race condition detailed in RFC5407 section 3.1.2.
4846  * We sent a CANCEL at the same time that the UAS sent us a
4847  * 200 OK with a valid SDP for the original INVITE. As a
4848  * result, we have now received a 200 OK for a cancelled
4849  * call and the SDP negotiation is complete. We need to
4850  * immediately send a BYE to end the dialog.
4851  *
4852  * 2) We sent a CANCEL and hit the race condition but the
4853  * UAS sent us an invalid SDP with the 200 OK. In this case
4854  * the SDP negotiation is incomplete and PJPROJECT has
4855  * already sent the BYE for us because of the invalid SDP.
4856  */
4857  ast_test_suite_event_notify("PJSIP_SESSION_CANCELED",
4858  "Endpoint: %s\r\n"
4859  "Channel: %s\r\n"
4860  "Message: %s\r\n"
4861  "SDP: %s",
4863  session->channel ? ast_channel_name(session->channel) : "",
4864  pjsip_rx_data_get_info(e->body.tsx_state.src.rdata),
4865  sdp_negotiation_done ? "complete" : "incomplete");
4866  if (!sdp_negotiation_done) {
4867  ast_debug(1, "%s: Incomplete SDP negotiation cancelled session. %s\n",
4868  ast_sip_session_get_name(session),
4869  pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4870  } else if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
4871  && tdata) {
4872  ast_debug(1, "%s: Ending session due to RFC5407 race condition. %s\n",
4873  ast_sip_session_get_name(session),
4874  pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4875  ast_sip_session_send_request(session, tdata);
4876  }
4877  }
4878  }
4879  }
4880  } else {
4881  /* All other methods */
4882  if (tsx->role == PJSIP_ROLE_UAC) {
4883  if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
4884  /* This means we got a final response to our outgoing method */
4885  ast_debug(1, "%s: %.*s received final response code %d\n",
4886  ast_sip_session_get_name(session),
4887  (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4888  tsx->status_code);
4889  if ((tsx->status_code == 401 || tsx->status_code == 407)
4892  &session->endpoint->outbound_auths,
4893  e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
4894  /* Send authed version of the method */
4895  ast_sip_session_send_request_with_cb(session, tdata, cb);
4896  SCOPE_EXIT_RTN("Sending authed %.*s\n",
4897  (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name));
4898  }
4899  }
4900  }
4901  }
4902  if (cb) {
4903  cb(session, e->body.tsx_state.src.rdata);
4904  }
4905  break;
4906  case PJSIP_EVENT_TRANSPORT_ERROR:
4907  case PJSIP_EVENT_TIMER:
4908  /*
4909  * The timer event is run by the pjsip monitor thread and not
4910  * by the session serializer.
4911  */
4912  if (session_end_if_disconnected(id, inv)) {
4913  SCOPE_EXIT_RTN("Disconnected\n");
4914  }
4915  break;
4916  case PJSIP_EVENT_USER:
4917  case PJSIP_EVENT_UNKNOWN:
4918  case PJSIP_EVENT_TSX_STATE:
4919  /* Inception? */
4920  break;
4921  }
4922 
4923  if (AST_LIST_EMPTY(&session->delayed_requests)) {
4924  /* No delayed request pending, so just return */
4925  SCOPE_EXIT_RTN("Nothing delayed\n");
4926  }
4927 
4928  if (tsx->method.id == PJSIP_INVITE_METHOD) {
4929  if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
4930  ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
4931  ast_sip_session_get_name(session),
4932  pjsip_tsx_state_str(tsx->state));
4934  } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
4935  /*
4936  * Terminated INVITE transactions always should result in
4937  * queuing delayed requests, no matter what event caused
4938  * the transaction to terminate.
4939  */
4940  ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
4941  ast_sip_session_get_name(session),
4942  pjsip_tsx_state_str(tsx->state));
4944  }
4945  } else if (tsx->role == PJSIP_ROLE_UAC
4946  && tsx->state == PJSIP_TSX_STATE_COMPLETED
4947  && !pj_strcmp2(&tsx->method.name, "UPDATE")) {
4948  ast_debug(3, "%s: UPDATE delay check. tsx-state:%s\n",
4949  ast_sip_session_get_name(session),
4950  pjsip_tsx_state_str(tsx->state));
4952  }
4953 
4954  SCOPE_EXIT_RTN();
4955 }
struct ast_sip_endpoint * endpoint
static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session_response_cb on_response)
int(* ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata)
#define print_debug_details(inv, tsx, e)
struct ast_sip_auth_vector outbound_auths
Definition: res_pjsip.h:855
#define MOD_DATA_ON_RESPONSE
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
static int invite_terminated(void *vsession)
A structure describing a SIP session.
static void check_delayed_requests(struct ast_sip_session *session, int(*cb)(void *vsession))
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
static struct ast_mansession session
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_channel * channel
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition: res_pjsip.c:3412
static pjsip_module session_module
#define ast_sip_mod_data_get(mod_data, id, key)
Using the dictionary stored in mod_data array at a given id, retrieve the value associated with the g...
Definition: res_pjsip.h:2638
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
static int invite_proceeding(void *vsession)
int ast_shutdown_final(void)
Definition: asterisk.c:1829
#define MAX_RX_CHALLENGES
Definition: res_pjsip.h:80
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
static int session_end_if_disconnected(int id, pjsip_inv_session *inv)
struct ast_sip_session::@309 delayed_requests
int ast_channel_hangupcause(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response)
Send a SIP request and get called back when a response is received.
unsigned int authentication_challenge_count
enum queue_result id
Definition: app_queue.c:1507
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.
#define AST_CAUSE_BEARERCAPABILITY_NOTAVAIL
Definition: causes.h:129
static int update_completed(void *vsession)

◆ session_media_dtor()

static void session_media_dtor ( void *  obj)
static

Definition at line 469 of file res_pjsip_session.c.

References ao2_callback, ast_free, ast_sdp_srtp_destroy(), ast_sip_session_media::mid, ast_sip_session_media::remote_label, ast_sip_session_media::remote_mslabel, ast_sip_session_media::srtp, stream_destroy(), and ast_sip_session_media::stream_name.

Referenced by ast_sip_session_media_state_add(), and test_media_add().

470 {
471  struct ast_sip_session_media *session_media = obj;
472 
473  /* It is possible for multiple handlers to have allocated memory on the
474  * session media (usually through a stream changing types). Therefore, we
475  * traverse all the SDP handlers and let them all call stream_destroy on
476  * the session_media
477  */
478  ao2_callback(sdp_handlers, 0, stream_destroy, session_media);
479 
480  if (session_media->srtp) {
481  ast_sdp_srtp_destroy(session_media->srtp);
482  }
483 
484  ast_free(session_media->mid);
485  ast_free(session_media->remote_mslabel);
486  ast_free(session_media->remote_label);
487  ast_free(session_media->stream_name);
488 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
char * mid
Media identifier for this stream (may be shared across multiple streams)
static int stream_destroy(void *obj, void *arg, int flags)
char * stream_name
Stream name.
struct ast_sdp_srtp * srtp
Holds SRTP information.
#define ast_free(a)
Definition: astmm.h:182
char * remote_mslabel
Remote media stream label.
void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp)
free a ast_sdp_srtp structure
Definition: sdp_srtp.c:51
A structure containing SIP session media information.
char * remote_label
Remote stream label.
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.

◆ session_media_set_handler()

static void session_media_set_handler ( struct ast_sip_session_media session_media,
struct ast_sip_session_sdp_handler handler 
)
static

Set an SDP stream handler for a corresponding session media.

Note
Always use this function to set the SDP handler for a session media.

This function will properly free resources on the SDP handler currently being used by the session media, then set the session media to use the new SDP handler.

Definition at line 445 of file res_pjsip_session.c.

References ast_assert, handler(), ast_sip_session_media::handler, and ast_sip_session_sdp_handler::stream_destroy.

Referenced by add_sdp_streams(), handle_incoming_sdp(), handle_negotiated_sdp(), handle_negotiated_sdp_session_media(), and sdp_requires_deferral().

447 {
448  ast_assert(session_media->handler != handler);
449 
450  if (session_media->handler) {
451  session_media->handler->stream_destroy(session_media);
452  }
453  session_media->handler = handler;
454 }
void(* stream_destroy)(struct ast_sip_session_media *session_media)
Destroy a session_media created by this handler.
#define ast_assert(a)
Definition: utils.h:695
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59

◆ session_on_rx_request()

static pj_bool_t session_on_rx_request ( pjsip_rx_data *  rdata)
static

Called when a new SIP request comes into PJSIP.

This function is called under two circumstances 1) An out-of-dialog request is received by PJSIP 2) An in-dialog request that the inv_session layer does not handle is received (such as an in-dialog INFO)

Except for INVITEs, there is very little we actually do in this function 1) For requests we don't handle, we return PJ_FALSE 2) For new INVITEs, handle them now to prevent retransmissions from trying to setup the same call again. 3) For in-dialog requests we handle, we process them in the .on_state_changed = session_inv_on_state_changed or .on_tsx_state_changed = session_inv_on_tsx_state_changed callbacks instead.

Definition at line 4215 of file res_pjsip_session.c.

References ast_alloca, ast_log, ast_sip_session_get_name(), handle_new_invite_request(), has_supplement(), LOG_WARNING, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and TRACE_ATLEAST.

Referenced by ast_sip_session_send_response().

4216 {
4217  pj_status_t handled = PJ_FALSE;
4218  struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4219  pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4220  pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4221  struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4222  char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4223  int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4224  SCOPE_ENTER(1, "%s Request: %.*s %s\n", ast_sip_session_get_name(session),
4225  (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), res ? req_uri : "");
4226 
4227  switch (req.method.id) {
4228  case PJSIP_INVITE_METHOD:
4229  if (dlg) {
4230  ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
4231  break;
4232  }
4233  handled = PJ_TRUE;
4235  break;
4236  default:
4237  /* Handle other in-dialog methods if their supplements have been registered */
4238  handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
4239  has_supplement(inv_session->mod_data[session_module.id], rdata);
4240  break;
4241  }
4242 
4243  SCOPE_EXIT_RTN_VALUE(handled, "%s Handled request %.*s %s ? %s\n", ast_sip_session_get_name(session),
4244  (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), req_uri,
4245  handled == PJ_TRUE ? "yes" : "no");
4246 }
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
#define ast_log
Definition: astobj2.c:42
static struct ast_mansession session
static pjsip_module session_module
static pj_bool_t has_supplement(const struct ast_sip_session *session, const pjsip_rx_data *rdata)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
#define TRACE_ATLEAST(level)
Definition: logger.h:637
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
static void handle_new_invite_request(pjsip_rx_data *rdata)

◆ session_on_rx_response()

static pj_bool_t session_on_rx_response ( pjsip_rx_data *  rdata)
static

Definition at line 4185 of file res_pjsip_session.c.

References ast_sip_session_get_name(), NULL, SCOPE_ENTER, and SCOPE_EXIT_RTN_VALUE.

Referenced by ast_sip_session_send_response().

4186 {
4187 
4188  struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4189  pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4190  pjsip_inv_session *inv_session = dlg ? pjsip_dlg_get_inv_session(dlg) : NULL;
4191  struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4192  SCOPE_ENTER(1, "%s Method: %.*s Status: %d\n", ast_sip_session_get_name(session),
4193  (int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
4194 
4195  SCOPE_EXIT_RTN_VALUE(PJ_FALSE);
4196 }
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
static struct ast_mansession session
static pjsip_module session_module
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
jack_status_t status
Definition: app_jack.c:146

◆ session_on_tsx_state()

static void session_on_tsx_state ( pjsip_transaction *  tsx,
pjsip_event *  e 
)
static

Definition at line 4163 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ast_sip_session_get_name(), ast_str_tmp, ast_stream_topology_to_str(), ast_trace, NULL, ast_sip_session::pending_media_state, SCOPE_ENTER, SCOPE_EXIT_RTN, and ast_sip_session_media_state::topology.

Referenced by ast_sip_session_send_response().

4164 {
4165 
4166  pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
4167  pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4168  struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4169  SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4170  pjsip_tsx_state_str(tsx->state), inv_session ? pjsip_inv_state_name(inv_session->state) : "unknown");
4171 
4172  if (session) {
4173  ast_trace(2, "Topology: Pending: %s Active: %s\n",
4176  }
4177 
4178  SCOPE_EXIT_RTN();
4179 }
struct ast_sip_session_media_state * pending_media_state
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
A structure describing a SIP session.
struct ast_sip_session_media_state * active_media_state
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
static struct ast_mansession session
static pjsip_module session_module
#define SCOPE_EXIT_RTN(...)
Scope Exit with return.
Definition: logger.h:854
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_stream_topology * topology
The media stream topology.

◆ session_outgoing_nat_hook()

static void session_outgoing_nat_hook ( pjsip_tx_data *  tdata,
struct ast_sip_transport transport 
)
static

Hook for modifying outgoing messages with SDP to contain the proper address information.

Definition at line 5457 of file res_pjsip_session.c.

References ao2_cleanup, ao2_find, ast_copy_pj_str(), ast_debug, AST_LIST_TRAVERSE, ast_sip_dialog_get_session(), ast_sip_get_transport_state(), ast_sip_is_content_type(), ast_sip_mod_data_get, ast_sip_mod_data_set, ast_sip_session_get_name(), ast_sip_transport_is_local, ast_sockaddr_parse(), ast_sockaddr_stringify_host(), ast_sorcery_object_get_id(), ast_strlen_zero, ast_sip_session_sdp_handler::change_outgoing_sdp_stream_media_address, ast_sip_transport::external_media_address, handler(), host, MOD_DATA_NAT_HOOK, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, PARSE_PORT_FORBID, and RAII_VAR.

Referenced by load_module().

5458 {
5460  struct ast_sip_nat_hook *hook = ast_sip_mod_data_get(
5461  tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK);
5462  struct pjmedia_sdp_session *sdp;
5463  pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
5465  int stream;
5466 
5467  /* SDP produced by us directly will never be multipart */
5468  if (!transport_state || hook || !tdata->msg->body ||
5469  !ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") ||
5471  return;
5472  }
5473 
5474  sdp = tdata->msg->body->data;
5475 
5476  if (sdp->conn) {
5477  char host[NI_MAXHOST];
5478  struct ast_sockaddr our_sdp_addr = { { 0, } };
5479 
5480  ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
5481  ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
5482 
5483  /* Reversed check here. We don't check the remote
5484  * endpoint being in our local net, but whether our
5485  * outgoing session IP is local. If it is, we'll do
5486  * rewriting. No localnet configured? Always rewrite. */
5487  if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {
5488  ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),
5489  ast_sockaddr_stringify_host(&transport_state->external_media_address));
5490  pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address));
5491  pj_strassign(&sdp->origin.addr, &sdp->conn->addr);
5492  }
5493  }
5494 
5495  for (stream = 0; stream < sdp->media_count; ++stream) {
5496  /* See if there are registered handlers for this media stream type */
5497  char media[20];
5499  RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5500 
5501  /* We need a null-terminated version of the media string */
5502  ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
5503 
5504  handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
5505  if (!handler_list) {
5506  ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session),
5507  media);
5508  continue;
5509  }
5510  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5512  handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
5513  }
5514  }
5515  }
5516 
5517  /* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
5518  ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK, nat_hook);
5519 }
struct ast_sip_session * ast_sip_dialog_get_session(pjsip_dialog *dlg)
Retrieves a session from a dialog.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
#define OBJ_KEY
Definition: astobj2.h:1155
const ast_string_field external_media_address
Definition: res_pjsip.h:191
A handler for SDPs in SIP sessions.
void(* change_outgoing_sdp_stream_media_address)(struct pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
Update media stream with external address if applicable.
static struct ast_sip_nat_hook * nat_hook
NAT hook for modifying outgoing messages with SDP.
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
#define NULL
Definition: resample.c:96
Socket address structure.
Definition: netsock2.h:97
A structure describing a SIP session.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Structure for SIP nat hook information.
Definition: res_pjsip.h:271
static char host[256]
Definition: muted.c:77
Structure for SIP transport information.
Definition: res_pjsip.h:87
struct ast_sip_session_sdp_handler * next
#define ast_sip_mod_data_set(pool, mod_data, id, key, val)
Utilizing a mod_data array for a given id, set the value associated with the given key...
Definition: res_pjsip.h:2670
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static struct ast_mansession session
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static pjsip_module session_module
#define ast_sip_mod_data_get(mod_data, id, key)
Using the dictionary stored in mod_data array at a given id, retrieve the value associated with the g...
Definition: res_pjsip.h:2638
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
Definition: res_pjsip.c:5259
#define ast_sip_transport_is_local(transport_state, addr)
Definition: res_pjsip.h:165
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
#define MOD_DATA_NAT_HOOK
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
static char * ast_sockaddr_stringify_host(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only, suitable for a URL (with brack...
Definition: netsock2.h:331

◆ session_reinvite_on_rx_request()

static pj_bool_t session_reinvite_on_rx_request ( pjsip_rx_data *  rdata)
static

Definition at line 2733 of file res_pjsip_session.c.

References ao2_cleanup, ast_sip_dialog_get_session(), ast_sip_get_pjsip_endpoint(), ast_sip_session_media_state_reset(), ast_sip_session::channel, ast_sip_session::deferred_reinvite, ast_sip_session::inv_session, NULL, ast_sip_session::pending_media_state, RAII_VAR, and sdp_requires_deferral().

2734 {
2735  pjsip_dialog *dlg;
2737  pjsip_rdata_sdp_info *sdp_info;
2738  int deferred;
2739 
2740  if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
2741  !(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
2742  !(session = ast_sip_dialog_get_session(dlg)) ||
2743  !session->channel) {
2744  return PJ_FALSE;
2745  }
2746 
2747  if (session->inv_session->invite_tsx) {
2748  /* There's a transaction in progress so bail now and let pjproject send 491 */
2749  return PJ_FALSE;
2750  }
2751 
2752  if (session->deferred_reinvite) {
2753  pj_str_t key, deferred_key;
2754  pjsip_tx_data *tdata;
2755 
2756  /* We use memory from the new request on purpose so the deferred reinvite pool does not grow uncontrollably */
2757  pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &rdata->msg_info.cseq->method, rdata);
2758  pjsip_tsx_create_key(rdata->tp_info.pool, &deferred_key, PJSIP_ROLE_UAS, &session->deferred_reinvite->msg_info.cseq->method,
2759  session->deferred_reinvite);
2760 
2761  /* If this is a retransmission ignore it */
2762  if (!pj_strcmp(&key, &deferred_key)) {
2763  return PJ_TRUE;
2764  }
2765 
2766  /* Otherwise this is a new re-invite, so reject it */
2767  if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) {
2768  if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
2769  pjsip_tx_data_dec_ref(tdata);
2770  }
2771  }
2772 
2773  return PJ_TRUE;
2774  }
2775 
2776  if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
2777  (sdp_info->sdp_err != PJ_SUCCESS)) {
2778  return PJ_FALSE;
2779  }
2780 
2781  if (!sdp_info->sdp) {
2782  return PJ_FALSE;
2783  }
2784 
2785  deferred = sdp_requires_deferral(session, sdp_info->sdp);
2786  if (deferred == -1) {
2787  ast_sip_session_media_state_reset(session->pending_media_state);
2788  return PJ_FALSE;
2789  } else if (!deferred) {
2790  return PJ_FALSE;
2791  }
2792 
2793  pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
2794 
2795  return PJ_TRUE;
2796 }
struct ast_sip_session * ast_sip_dialog_get_session(pjsip_dialog *dlg)
Retrieves a session from a dialog.
#define NULL
Definition: resample.c:96
A structure describing a SIP session.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static struct ast_mansession session
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
Determine whether the SDP provided requires deferral of negotiating or not.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.

◆ session_termination_cb()

static void session_termination_cb ( pj_timer_heap_t *  timer_heap,
struct pj_timer_entry *  entry 
)
static

Definition at line 3545 of file res_pjsip_session.c.

References ao2_cleanup, ast_sip_push_task(), ast_sip_session::serializer, and session_termination_task().

Referenced by ast_sip_session_defer_termination().

3546 {
3547  struct ast_sip_session *session = entry->user_data;
3548 
3549  if (ast_sip_push_task(session->serializer, session_termination_task, session)) {
3550  ao2_cleanup(session);
3551  }
3552 }
A structure describing a SIP session.
static struct ast_mansession session
struct ast_taskprocessor * serializer
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
static int session_termination_task(void *data)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Definition: search.h:40

◆ session_termination_task()

static int session_termination_task ( void *  data)
static

Definition at line 3530 of file res_pjsip_session.c.

References ao2_ref, ast_sip_session_terminate(), ast_sip_session::defer_terminate, and ast_sip_session::inv_session.

Referenced by session_termination_cb().

3531 {
3532  struct ast_sip_session *session = data;
3533 
3534  if (session->defer_terminate) {
3535  session->defer_terminate = 0;
3536  if (session->inv_session) {
3537  ast_sip_session_terminate(session, 0);
3538  }
3539  }
3540 
3541  ao2_ref(session, -1);
3542  return 0;
3543 }
unsigned int defer_terminate
struct pjsip_inv_session * inv_session
A structure describing a SIP session.
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_sip_session_terminate(struct ast_sip_session *session, int response)
Terminate a session and, if possible, send the provided response code.

◆ set_from_header()

static void set_from_header ( struct ast_sip_session session)
static

Definition at line 1637 of file res_pjsip_session.c.

References ast_channel_connected_effective_id(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_party_id_copy(), ast_party_id_free(), ast_party_id_init(), ast_party_id_presentation(), AST_PRES_ALLOWED, AST_PRES_RESTRICTION, ast_sip_add_usereqphone(), ast_sip_get_use_callerid_contact(), ast_sip_modify_id_header(), ast_sip_session_get_name(), ast_strlen_zero, ast_sip_session::channel, ast_sip_endpoint::contact_user, ast_sip_session::endpoint, ast_sip_endpoint::fromdomain, ast_sip_endpoint::fromuser, ast_sip_endpoint::id, ast_sip_session::inv_session, NULL, ast_party_id::number, pbx_builtin_getvar_helper(), S_COR, ast_sip_session::saved_from_hdr, ast_party_number::str, ast_sip_endpoint_id_configuration::trust_outbound, and ast_party_number::valid.

Referenced by ast_sip_session_create_invite().

1638 {
1639  struct ast_party_id effective_id;
1640  struct ast_party_id connected_id;
1641  pj_pool_t *dlg_pool;
1642  pjsip_fromto_hdr *dlg_info;
1643  pjsip_contact_hdr *dlg_contact;
1644  pjsip_name_addr *dlg_info_name_addr;
1645  pjsip_sip_uri *dlg_info_uri;
1646  pjsip_sip_uri *dlg_contact_uri;
1647  int restricted;
1648  const char *pjsip_from_domain;
1649 
1650  if (!session->channel || session->saved_from_hdr) {
1651  return;
1652  }
1653 
1654  /* We need to save off connected_id for RPID/PAI generation */
1655  ast_party_id_init(&connected_id);
1656  ast_channel_lock(session->channel);
1657  effective_id = ast_channel_connected_effective_id(session->channel);
1658  ast_party_id_copy(&connected_id, &effective_id);
1659  ast_channel_unlock(session->channel);
1660 
1661  restricted =
1663 
1664  /* Now set up dlg->local.info so pjsip can correctly generate From */
1665 
1666  dlg_pool = session->inv_session->dlg->pool;
1667  dlg_info = session->inv_session->dlg->local.info;
1668  dlg_contact = session->inv_session->dlg->local.contact;
1669  dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1670  dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1671  dlg_contact_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(dlg_contact->uri);
1672 
1673  if (session->endpoint->id.trust_outbound || !restricted) {
1674  ast_sip_modify_id_header(dlg_pool, dlg_info, &connected_id);
1676  pj_strdup2(dlg_pool, &dlg_contact_uri->user, S_COR(connected_id.number.valid, connected_id.number.str, ""));
1677  }
1678  }
1679 
1680  ast_party_id_free(&connected_id);
1681 
1682  if (!ast_strlen_zero(session->endpoint->fromuser)) {
1683  dlg_info_name_addr->display.ptr = NULL;
1684  dlg_info_name_addr->display.slen = 0;
1685  pj_strdup2(dlg_pool, &dlg_info_uri->user, session->endpoint->fromuser);
1686  }
1687 
1688  if (!ast_strlen_zero(session->endpoint->fromdomain)) {
1689  pj_strdup2(dlg_pool, &dlg_info_uri->host, session->endpoint->fromdomain);
1690  }
1691 
1692  /*
1693  * Channel variable for compatibility with chan_sip SIPFROMDOMAIN
1694  */
1695  ast_channel_lock(session->channel);
1696  pjsip_from_domain = pbx_builtin_getvar_helper(session->channel, "SIPFROMDOMAIN");
1697  if (!ast_strlen_zero(pjsip_from_domain)) {
1698  ast_debug(3, "%s: From header domain reset by channel variable SIPFROMDOMAIN (%s)\n",
1699  ast_sip_session_get_name(session), pjsip_from_domain);
1700  pj_strdup2(dlg_pool, &dlg_info_uri->host, pjsip_from_domain);
1701  }
1702  ast_channel_unlock(session->channel);
1703 
1704  /* We need to save off the non-anonymized From for RPID/PAI generation (for domain) */
1705  session->saved_from_hdr = pjsip_hdr_clone(dlg_pool, dlg_info);
1706  ast_sip_add_usereqphone(session->endpoint, dlg_pool, session->saved_from_hdr->uri);
1707 
1708  /* In chan_sip, fromuser and fromdomain trump restricted so we only
1709  * anonymize if they're not set.
1710  */
1711  if (restricted) {
1712  /* fromuser doesn't provide a display name so we always set it */
1713  pj_strdup2(dlg_pool, &dlg_info_name_addr->display, "Anonymous");
1714 
1715  if (ast_strlen_zero(session->endpoint->fromuser)) {
1716  pj_strdup2(dlg_pool, &dlg_info_uri->user, "anonymous");
1717  }
1718 
1720  pj_strdup2(dlg_pool, &dlg_contact_uri->user, "anonymous");
1721  }
1722 
1723  if (ast_strlen_zero(session->endpoint->fromdomain)) {
1724  pj_strdup2(dlg_pool, &dlg_info_uri->host, "anonymous.invalid");
1725  }
1726  } else {
1727  ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri);
1728  }
1729 }
Information needed to identify an endpoint in a call.
Definition: channel.h:339
#define ast_channel_lock(chan)
Definition: channel.h:2945
struct ast_sip_endpoint * endpoint
void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri)
Add &#39;user=phone&#39; parameter to URI if enabled and user is a phone number.
Definition: res_pjsip.c:3994
const ast_string_field fromuser
Definition: res_pjsip.h:829
char * contact_user
Definition: res_pjsip.h:887
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1821
void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
Copy the source party id information to the destination party id.
Definition: channel.c:1765
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition: channel.c:1811
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
struct ast_channel * channel
unsigned int ast_sip_get_use_callerid_contact(void)
Retrieve the global setting &#39;use_callerid_contact&#39;.
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:847
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
Definition: channel.c:1757
void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id)
Set name and number information on an identity header.
Definition: res_pjsip.c:5587
#define AST_PRES_RESTRICTION
Definition: callerid.h:323
#define AST_PRES_ALLOWED
Definition: callerid.h:324
pjsip_fromto_hdr * saved_from_hdr
const ast_string_field fromdomain
Definition: res_pjsip.h:831

◆ set_mid_and_bundle_group()

static int set_mid_and_bundle_group ( struct ast_sip_session session,
struct ast_sip_session_media session_media,
const pjmedia_sdp_session *  sdp,
const struct pjmedia_sdp_media *  stream 
)
static

Definition at line 646 of file res_pjsip_session.c.

References ast_calloc, ast_copy_pj_str(), ast_free, ast_sip_endpoint_media_configuration::bundle, ast_sip_session_media::bundle_group, ast_sip_session_media::bundled, ast_sip_session::endpoint, get_mid_bundle_group(), ast_sip_endpoint::media, ast_sip_session_media::mid, and NULL.

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

650 {
651  pjmedia_sdp_attr *attr;
652 
653  if (!session->endpoint->media.bundle) {
654  return 0;
655  }
656 
657  /* By default on an incoming negotiation we assume no mid and bundle group is present */
658  ast_free(session_media->mid);
659  session_media->mid = NULL;
660  session_media->bundle_group = -1;
661  session_media->bundled = 0;
662 
663  /* Grab the media identifier for the stream */
664  attr = pjmedia_sdp_media_find_attr2(stream, "mid", NULL);
665  if (!attr) {
666  return 0;
667  }
668 
669  session_media->mid = ast_calloc(1, attr->value.slen + 1);
670  if (!session_media->mid) {
671  return 0;
672  }
673  ast_copy_pj_str(session_media->mid, &attr->value, attr->value.slen + 1);
674 
675  /* Determine what bundle group this is part of */
676  session_media->bundle_group = get_mid_bundle_group(sdp, session_media->mid);
677 
678  /* If this is actually part of a bundle group then the other side requested or accepted the bundle request */
679  session_media->bundled = session_media->bundle_group != -1;
680 
681  return 0;
682 }
struct ast_sip_endpoint * endpoint
char * mid
Media identifier for this stream (may be shared across multiple streams)
static int get_mid_bundle_group(const pjmedia_sdp_session *sdp, const char *mid)
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
#define NULL
Definition: resample.c:96
unsigned int bundled
Whether this stream is currently bundled or not.
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int bundle_group
The bundle group the stream belongs to.

◆ set_remote_mslabel_and_stream_group()

static void set_remote_mslabel_and_stream_group ( struct ast_sip_session session,
struct ast_sip_session_media session_media,
const pjmedia_sdp_session *  sdp,
const struct pjmedia_sdp_media *  stream,
struct ast_stream asterisk_stream 
)
static

Definition at line 684 of file res_pjsip_session.c.

References ast_copy_pj_str(), ast_free, ast_strdup, ast_stream_set_group(), ast_strlen_zero, AST_VECTOR_GET, AST_VECTOR_SIZE, NULL, ast_sip_session::pending_media_state, ast_sip_session_media::remote_label, ast_sip_session_media::remote_mslabel, strsep(), and tmp().

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

689 {
690  int index;
691 
692  ast_free(session_media->remote_mslabel);
693  session_media->remote_mslabel = NULL;
694  ast_free(session_media->remote_label);
695  session_media->remote_label = NULL;
696 
697  for (index = 0; index < stream->attr_count; ++index) {
698  pjmedia_sdp_attr *attr = stream->attr[index];
699  char attr_value[pj_strlen(&attr->value) + 1];
700  char *ssrc_attribute_name, *ssrc_attribute_value = NULL;
701  char *msid, *tmp = attr_value;
702  static const pj_str_t STR_msid = { "msid", 4 };
703  static const pj_str_t STR_ssrc = { "ssrc", 4 };
704  static const pj_str_t STR_label = { "label", 5 };
705 
706  if (!pj_strcmp(&attr->name, &STR_label)) {
707  ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
708  session_media->remote_label = ast_strdup(attr_value);
709  } else if (!pj_strcmp(&attr->name, &STR_msid)) {
710  ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
711  msid = strsep(&tmp, " ");
712  session_media->remote_mslabel = ast_strdup(msid);
713  break;
714  } else if (!pj_strcmp(&attr->name, &STR_ssrc)) {
715  ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
716 
717  if ((ssrc_attribute_name = strchr(attr_value, ' '))) {
718  /* This has an actual attribute */
719  *ssrc_attribute_name++ = '\0';
720  ssrc_attribute_value = strchr(ssrc_attribute_name, ':');
721  if (ssrc_attribute_value) {
722  /* Values are actually optional according to the spec */
723  *ssrc_attribute_value++ = '\0';
724  }
725 
726  if (!strcasecmp(ssrc_attribute_name, "mslabel") && !ast_strlen_zero(ssrc_attribute_value)) {
727  session_media->remote_mslabel = ast_strdup(ssrc_attribute_value);
728  break;
729  }
730  }
731  }
732  }
733 
734  if (ast_strlen_zero(session_media->remote_mslabel)) {
735  return;
736  }
737 
738  /* Iterate through the existing streams looking for a match and if so then group this with it */
739  for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
740  struct ast_sip_session_media *group_session_media;
741 
742  group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
743 
744  if (ast_strlen_zero(group_session_media->remote_mslabel) ||
745  strcmp(group_session_media->remote_mslabel, session_media->remote_mslabel)) {
746  continue;
747  }
748 
749  ast_stream_set_group(asterisk_stream, index);
750  break;
751  }
752 }
struct ast_sip_session_media_state * pending_media_state
static int tmp()
Definition: bt_open.c:389
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
void ast_stream_set_group(struct ast_stream *stream, int group)
Set the stream group for a stream.
Definition: stream.c:1084
#define ast_free(a)
Definition: astmm.h:182
char * remote_mslabel
Remote media stream label.
A structure containing SIP session media information.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
char * strsep(char **str, const char *delims)
char * remote_label
Remote stream label.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ setup_outbound_invite_auth()

static int setup_outbound_invite_auth ( pjsip_dialog *  dlg)
static

Definition at line 3306 of file res_pjsip_session.c.

References NULL, and status.

Referenced by ast_sip_session_create_outgoing().

3307 {
3308  pj_status_t status;
3309 
3310  ++dlg->sess_count;
3311  status = pjsip_dlg_add_usage(dlg, &outbound_invite_auth_module, NULL);
3312  --dlg->sess_count;
3313 
3314  return status != PJ_SUCCESS ? -1 : 0;
3315 }
#define NULL
Definition: resample.c:96
static pjsip_module outbound_invite_auth_module
jack_status_t status
Definition: app_jack.c:146

◆ sip_channel_destroy()

static void sip_channel_destroy ( void *  obj)
static

Destructor for SIP channel.

Definition at line 2966 of file res_pjsip_session.c.

References ao2_cleanup, ast_sip_channel_pvt::pvt, and ast_sip_channel_pvt::session.

Referenced by ast_sip_channel_pvt_alloc().

2967 {
2968  struct ast_sip_channel_pvt *channel = obj;
2969 
2970  ao2_cleanup(channel->pvt);
2971  ao2_cleanup(channel->session);
2972 }
void * pvt
Pointer to channel specific implementation information, must be ao2 object.
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Definition: muted.c:95
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ sip_session_defer_termination_stop_timer()

static void sip_session_defer_termination_stop_timer ( struct ast_sip_session session)
static

Definition at line 3588 of file res_pjsip_session.c.

References ao2_ref, ast_sip_get_pjsip_endpoint(), and ast_sip_session::scheduled_termination.

Referenced by ast_sip_session_defer_termination_cancel(), and session_end().

3589 {
3590  if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
3591  &session->scheduled_termination, session->scheduled_termination.id)) {
3592  ao2_ref(session, -1);
3593  }
3594 }
#define ao2_ref(o, delta)
Definition: astobj2.h:464
pj_timer_entry scheduled_termination
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718

◆ sip_session_refresh()

static int sip_session_refresh ( struct ast_sip_session session,
ast_sip_session_request_creation_cb  on_request_creation,
ast_sip_session_sdp_creation_cb  on_sdp_creation,
ast_sip_session_response_cb  on_response,
enum ast_sip_session_refresh_method  method,
int  generate_new_sdp,
struct ast_sip_session_media_state pending_media_state,
struct ast_sip_session_media_state active_media_state,
int  queued 
)
static

Definition at line 2184 of file res_pjsip_session.c.

References ast_sip_session::active_media_state, ao2_bump, ao2_cleanup, ao2_ref, ast_format_cap_alloc, ast_format_cap_count(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_get_compatible(), AST_LIST_EMPTY, AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_END, AST_MEDIA_TYPE_IMAGE, AST_MEDIA_TYPE_VIDEO, ast_sip_session_get_name(), ast_sip_session_media_state_clone(), ast_sip_session_media_state_free(), ast_sip_session_media_state_reset(), AST_SIP_SESSION_REFRESH_METHOD_INVITE, ast_sip_session_send_request_with_cb(), ast_str_tmp, ast_stream_clone(), ast_stream_free(), ast_stream_get_formats(), ast_stream_get_metadata(), ast_stream_get_name(), ast_stream_get_state(), ast_stream_get_type(), ast_stream_set_formats(), ast_stream_set_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_append_stream(), ast_stream_topology_del_stream(), ast_stream_topology_equal(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_to_str(), ast_trace, AST_VECTOR_GET, AST_VECTOR_REMOVE, AST_VECTOR_SIZE, ast_sip_endpoint_media_configuration::codecs, ast_sip_session_media_state::default_session, delay_request(), DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, ast_sip_session::delayed_requests, end, ast_sip_session::endpoint, generate_session_refresh_sdp(), ast_sip_session::inv_session, is_stream_limitation_reached(), LOG_ERROR, LOG_WARNING, ast_sip_endpoint::media, NULL, ast_sip_session::pending_media_state, ast_stream::position, resolve_refresh_media_states(), SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG_EXPR, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, and ast_sip_session_media_state::topology.

Referenced by ast_sip_session_refresh(), and send_delayed_request().

2192 {
2193  pjsip_inv_session *inv_session = session->inv_session;
2194  pjmedia_sdp_session *new_sdp = NULL;
2195  pjsip_tx_data *tdata;
2196  int res = -1;
2197  SCOPE_ENTER(3, "%s: New SDP? %s Queued? %s DP: %s DA: %s\n", ast_sip_session_get_name(session),
2198  generate_new_sdp ? "yes" : "no", queued ? "yes" : "no",
2199  pending_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)) : "none",
2200  active_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)) : "none");
2201 
2202  if (pending_media_state && (!pending_media_state->topology || !generate_new_sdp)) {
2203 
2204  ast_sip_session_media_state_free(pending_media_state);
2205  ast_sip_session_media_state_free(active_media_state);
2206  SCOPE_EXIT_RTN_VALUE(-1, "%s: Not sending reinvite because %s%s\n", ast_sip_session_get_name(session),
2207  pending_media_state->topology == NULL ? "pending topology is null " : "",
2208  !generate_new_sdp ? "generate_new_sdp is false" : "");
2209  }
2210 
2211  if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
2212  /* Don't try to do anything with a hung-up call */
2213  ast_sip_session_media_state_free(pending_media_state);
2214  ast_sip_session_media_state_free(active_media_state);
2215  SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because of disconnected state\n",
2216  ast_sip_session_get_name(session));
2217  }
2218 
2219  /* If the dialog has not yet been established we have to defer until it has */
2220  if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
2221  res = delay_request(session, on_request_creation, on_sdp_creation, on_response,
2222  generate_new_sdp,
2225  pending_media_state, active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2226  SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because dialog has not been established\n",
2227  ast_sip_session_get_name(session));
2228  }
2229 
2231  if (inv_session->invite_tsx) {
2232  /* We can't send a reinvite yet, so delay it */
2233  res = delay_request(session, on_request_creation, on_sdp_creation,
2234  on_response, generate_new_sdp, DELAYED_METHOD_INVITE, pending_media_state,
2235  active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2236  SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding transaction\n",
2237  ast_sip_session_get_name(session));
2238  } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {
2239  /* Initial INVITE transaction failed to progress us to a confirmed state
2240  * which means re-invites are not possible
2241  */
2242  ast_sip_session_media_state_free(pending_media_state);
2243  ast_sip_session_media_state_free(active_media_state);
2244  SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because not in confirmed state\n",
2245  ast_sip_session_get_name(session));
2246  }
2247  }
2248 
2249  if (generate_new_sdp) {
2250  /* SDP can only be generated if current negotiation has already completed */
2251  if (inv_session->neg
2252  && pjmedia_sdp_neg_get_state(inv_session->neg)
2253  != PJMEDIA_SDP_NEG_STATE_DONE) {
2254  res = delay_request(session, on_request_creation, on_sdp_creation,
2255  on_response, generate_new_sdp,
2257  ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2258  active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2259  SCOPE_EXIT_RTN_VALUE(res, "%s: Delay session refresh with new SDP because SDP negotiation is not yet done\n",
2260  ast_sip_session_get_name(session));
2261  }
2262 
2263  /* If an explicitly requested media state has been provided use it instead of any pending one */
2264  if (pending_media_state) {
2265  int index;
2266  int type_streams[AST_MEDIA_TYPE_END] = {0};
2267 
2268  ast_trace(-1, "%s: Pending media state exists\n", ast_sip_session_get_name(session));
2269 
2270  /* Media state conveys a desired media state, so if there are outstanding
2271  * delayed requests we need to ensure we go into the queue and not jump
2272  * ahead. If we sent this media state now then updates could go out of
2273  * order.
2274  */
2275  if (!queued && !AST_LIST_EMPTY(&session->delayed_requests)) {
2276  res = delay_request(session, on_request_creation, on_sdp_creation,
2277  on_response, generate_new_sdp,
2279  ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2280  active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2281  SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding requests\n",
2282  ast_sip_session_get_name(session));
2283  }
2284 
2285  /*
2286  * Attempt to resolve only if objects are available, and it's not
2287  * switching to or from an image type.
2288  */
2289  if (active_media_state && active_media_state->topology &&
2290  (!active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] ==
2291  !pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE])) {
2292 
2293  struct ast_sip_session_media_state *new_pending_state;
2294 
2295  ast_trace(-1, "%s: Active media state exists and is%s equal to pending\n", ast_sip_session_get_name(session),
2296  !ast_stream_topology_equal(active_media_state->topology,pending_media_state->topology) ? " not" : "");
2297  ast_trace(-1, "%s: DP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));
2298  ast_trace(-1, "%s: DA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)));
2299  ast_trace(-1, "%s: CP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)));
2300  ast_trace(-1, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
2301 
2302  new_pending_state = resolve_refresh_media_states(ast_sip_session_get_name(session),
2303  pending_media_state, active_media_state, session->active_media_state, 1);
2304  if (new_pending_state) {
2305  ast_trace(-1, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(new_pending_state->topology, &STR_TMP)));
2306  ast_sip_session_media_state_free(pending_media_state);
2307  pending_media_state = new_pending_state;
2308  } else {
2309  ast_sip_session_media_state_reset(pending_media_state);
2310  ast_sip_session_media_state_free(active_media_state);
2311  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Unable to merge media states\n", ast_sip_session_get_name(session));
2312  }
2313  }
2314 
2315  /* Prune the media state so the number of streams fit within the configured limits - we do it here
2316  * so that the index of the resulting streams in the SDP match. If we simply left the streams out
2317  * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that
2318  * are configurable on the endpoint.
2319  */
2320  ast_trace(-1, "%s: Pruning and checking formats of streams\n", ast_sip_session_get_name(session));
2321 
2322  for (index = 0; index < ast_stream_topology_get_count(pending_media_state->topology); ++index) {
2323  struct ast_stream *existing_stream = NULL;
2324  struct ast_stream *stream = ast_stream_topology_get_stream(pending_media_state->topology, index);
2325  SCOPE_ENTER(4, "%s: Checking stream %s\n", ast_sip_session_get_name(session),
2326  ast_stream_get_name(stream));
2327 
2328  if (session->active_media_state->topology &&
2330  existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2331  ast_trace(-1, "%s: Found existing stream %s\n", ast_sip_session_get_name(session),
2332  ast_stream_get_name(existing_stream));
2333  }
2334 
2335  if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {
2336  if (index < AST_VECTOR_SIZE(&pending_media_state->sessions)) {
2337  struct ast_sip_session_media *session_media = AST_VECTOR_GET(&pending_media_state->sessions, index);
2338 
2339  ao2_cleanup(session_media);
2340  AST_VECTOR_REMOVE(&pending_media_state->sessions, index, 1);
2341  }
2342 
2343  ast_stream_topology_del_stream(pending_media_state->topology, index);
2344  ast_trace(-1, "%s: Dropped overlimit stream %s\n", ast_sip_session_get_name(session),
2345  ast_stream_get_name(stream));
2346 
2347  /* A stream has potentially moved into our spot so we need to jump back so we process it */
2348  index -= 1;
2349  SCOPE_EXIT_EXPR(continue);
2350  }
2351 
2352  /* No need to do anything with stream if it's media state is removed */
2354  /* If there is no existing stream we can just not have this stream in the topology at all. */
2355  if (!existing_stream) {
2356  ast_trace(-1, "%s: Dropped removed stream %s\n", ast_sip_session_get_name(session),
2357  ast_stream_get_name(stream));
2358  ast_stream_topology_del_stream(pending_media_state->topology, index);
2359  /* TODO: Do we need to remove the corresponding media state? */
2360  index -= 1;
2361  }
2362  SCOPE_EXIT_EXPR(continue);
2363  }
2364 
2365  /* Enforce the configured allowed codecs on audio and video streams */
2367  !ast_stream_get_metadata(stream, "pjsip_session_refresh")) {
2368  struct ast_format_cap *joint_cap;
2369 
2371  if (!joint_cap) {
2372  ast_sip_session_media_state_free(pending_media_state);
2373  ast_sip_session_media_state_free(active_media_state);
2374  res = -1;
2375  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to alloc format caps\n", ast_sip_session_get_name(session));
2376  }
2378  if (!ast_format_cap_count(joint_cap)) {
2379  ao2_ref(joint_cap, -1);
2380 
2381  if (!existing_stream) {
2382  /* If there is no existing stream we can just not have this stream in the topology
2383  * at all.
2384  */
2385  ast_stream_topology_del_stream(pending_media_state->topology, index);
2386  index -= 1;
2387  SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2388  ast_sip_session_get_name(session), ast_stream_get_name(stream));
2389  } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) ||
2390  strcmp(ast_stream_get_name(stream), ast_stream_get_name(existing_stream))) {
2391  /* If the underlying stream is a different type or different name then we have to
2392  * mark it as removed, as it is replacing an existing stream. We do this so order
2393  * is preserved.
2394  */
2396  SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2397  ast_sip_session_get_name(session), ast_stream_get_name(stream));
2398  } else {
2399  /* However if the stream is otherwise remaining the same we can keep the formats
2400  * that exist on it already which allows media to continue to flow. We don't modify
2401  * the format capabilities but do need to cast it so that ao2_bump can raise the
2402  * reference count.
2403  */
2404  joint_cap = ao2_bump((struct ast_format_cap *)ast_stream_get_formats(existing_stream));
2405  }
2406  }
2407  ast_stream_set_formats(stream, joint_cap);
2408  ao2_cleanup(joint_cap);
2409  }
2410 
2411  ++type_streams[ast_stream_get_type(stream)];
2412 
2413  SCOPE_EXIT();
2414  }
2415 
2416  if (session->active_media_state->topology) {
2417  /* SDP is a fun thing. Take for example the fact that streams are never removed. They just become
2418  * declined. To better handle this in the case where something requests a topology change for fewer
2419  * streams than are currently present we fill in the topology to match the current number of streams
2420  * that are active.
2421  */
2422 
2423  for (index = ast_stream_topology_get_count(pending_media_state->topology);
2424  index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) {
2425  struct ast_stream *stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2426  struct ast_stream *cloned;
2427  int position;
2428  SCOPE_ENTER(4, "%s: Stream %s not in pending\n", ast_sip_session_get_name(session),
2429  ast_stream_get_name(stream));
2430 
2431  cloned = ast_stream_clone(stream, NULL);
2432  if (!cloned) {
2433  ast_sip_session_media_state_free(pending_media_state);
2434  ast_sip_session_media_state_free(active_media_state);
2435  res = -1;
2436  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to clone stream %s\n",
2437  ast_sip_session_get_name(session), ast_stream_get_name(stream));
2438  }
2439 
2441  position = ast_stream_topology_append_stream(pending_media_state->topology, cloned);
2442  if (position < 0) {
2443  ast_stream_free(cloned);
2444  ast_sip_session_media_state_free(pending_media_state);
2445  ast_sip_session_media_state_free(active_media_state);
2446  res = -1;
2447  SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to append cloned stream\n",
2448  ast_sip_session_get_name(session));
2449  }
2450  SCOPE_EXIT("%s: Appended empty stream in position %d to make counts match\n",
2451  ast_sip_session_get_name(session), position);
2452  }
2453 
2454  /*
2455  * We can suppress this re-invite if the pending topology is equal to the currently
2456  * active topology.
2457  */
2458  if (ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
2459  ast_trace(-1, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
2460  ast_trace(-1, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));
2461  ast_sip_session_media_state_free(pending_media_state);
2462  ast_sip_session_media_state_free(active_media_state);
2463  /* For external consumers we return 0 to say success, but internally for
2464  * send_delayed_request we return a separate value to indicate that this
2465  * session refresh would be redundant so we didn't send it
2466  */
2467  SCOPE_EXIT_RTN_VALUE(queued ? 1 : 0, "%s: Topologies are equal. Not sending re-invite\n",
2468  ast_sip_session_get_name(session));
2469  }
2470  }
2471 
2473  session->pending_media_state = pending_media_state;
2474  }
2475 
2476  new_sdp = generate_session_refresh_sdp(session);
2477  if (!new_sdp) {
2479  ast_sip_session_media_state_free(active_media_state);
2480  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to generate session refresh SDP. Not sending session refresh\n",
2481  ast_sip_session_get_name(session));
2482  }
2483  if (on_sdp_creation) {
2484  if (on_sdp_creation(session, new_sdp)) {
2486  ast_sip_session_media_state_free(active_media_state);
2487  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_sdp_creation failed\n", ast_sip_session_get_name(session));
2488  }
2489  }
2490  }
2491 
2493  if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
2494  if (generate_new_sdp) {
2496  }
2497  ast_sip_session_media_state_free(active_media_state);
2498  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create reinvite properly\n", ast_sip_session_get_name(session));
2499  }
2500  } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
2501  if (generate_new_sdp) {
2503  }
2504  ast_sip_session_media_state_free(active_media_state);
2505  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create UPDATE properly\n", ast_sip_session_get_name(session));
2506  }
2507  if (on_request_creation) {
2508  if (on_request_creation(session, tdata)) {
2509  if (generate_new_sdp) {
2511  }
2512  ast_sip_session_media_state_free(active_media_state);
2513  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));
2514  }
2515  }
2516  ast_sip_session_send_request_with_cb(session, tdata, on_response);
2517  ast_sip_session_media_state_free(active_media_state);
2518 
2519 end:
2520  SCOPE_EXIT_RTN_VALUE(res, "%s: Sending session refresh SDP via %s\n", ast_sip_session_get_name(session),
2521  method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE");
2522 }
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
Definition: logger.h:940
struct ast_sip_endpoint * endpoint
Structure which contains media state information (streams, sessions)
struct ast_sip_session_media_state * pending_media_state
static int is_stream_limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
#define LOG_WARNING
Definition: logger.h:274
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, enum delayed_method method, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queue_head)
struct ast_format_cap * codecs
Definition: res_pjsip.h:770
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
#define ast_trace(level,...)
Print a basic trace message.
Definition: logger.h:692
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition: format_cap.c:395
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
#define SCOPE_EXIT_LOG_EXPR(__expr, __log_level,...)
Definition: logger.h:946
char * end
Definition: eagi_proxy.c:73
struct pjsip_inv_session * inv_session
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
struct ast_sip_session_media_state * active_media_state
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * method
Definition: res_pjsip.c:4335
#define SCOPE_EXIT(...)
Scope Exit.
Definition: logger.h:805
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition: stream.c:330
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
#define SCOPE_EXIT_EXPR(__expr,...)
Definition: logger.h:834
static pjmedia_sdp_session * generate_session_refresh_sdp(struct ast_sip_session *session)
#define LOG_ERROR
Definition: logger.h:285
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right)
Compare two stream topologies to see if they are equal.
Definition: stream.c:696
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
struct ast_sip_session_media_state * ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state)
Clone a media state.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
A structure containing SIP session media information.
struct ast_sip_session::@309 delayed_requests
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream * ast_stream_clone(const struct ast_stream *stream, const char *name)
Create a deep clone of an existing stream.
Definition: stream.c:257
struct ast_stream_topology * topology
The media stream topology.
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition: stream.c:423
void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response)
Send a SIP request and get called back when a response is received.
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
Find the compatible formats between two capabilities structures.
Definition: format_cap.c:630
int ast_stream_topology_del_stream(struct ast_stream_topology *topology, unsigned int position)
Delete a specified stream from the given topology.
Definition: stream.c:825
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
unsigned int position
The position of the stream in the topology.
Definition: stream.c:90
static struct ast_sip_session_media_state * resolve_refresh_media_states(const char *session_name, struct ast_sip_session_media_state *delayed_pending_state, struct ast_sip_session_media_state *delayed_active_state, struct ast_sip_session_media_state *current_active_state, int run_post_validation)

◆ sip_session_suspend_task()

static int sip_session_suspend_task ( void *  data)
static

Definition at line 3134 of file res_pjsip_session.c.

References ao2_lock, ao2_object_get_lockaddr(), ao2_ref, ao2_unlock, ast_cond_signal, ast_cond_wait, ast_sip_session_suspender::complete, ast_sip_session_suspender::cond_complete, ast_sip_session_suspender::cond_suspended, and ast_sip_session_suspender::suspended.

Referenced by ast_sip_session_suspend().

3135 {
3136  struct ast_sip_session_suspender *suspender = data;
3137 
3138  ao2_lock(suspender);
3139 
3140  /* Signal that the serializer task is now suspended. */
3141  suspender->suspended = 1;
3142  ast_cond_signal(&suspender->cond_suspended);
3143 
3144  /* Wait for the serializer suspension to be completed. */
3145  while (!suspender->complete) {
3146  ast_cond_wait(&suspender->cond_complete, ao2_object_get_lockaddr(suspender));
3147  }
3148 
3149  ao2_unlock(suspender);
3150  ao2_ref(suspender, -1);
3151 
3152  return 0;
3153 }
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_cond_signal(cond)
Definition: lock.h:201
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct controlling the suspension of the session&#39;s serializer.

◆ sip_session_suspender_dtor()

static void sip_session_suspender_dtor ( void *  vdoomed)
static

Definition at line 3118 of file res_pjsip_session.c.

References ast_cond_destroy, ast_sip_session_suspender::cond_complete, and ast_sip_session_suspender::cond_suspended.

Referenced by ast_sip_session_suspend().

3119 {
3120  struct ast_sip_session_suspender *doomed = vdoomed;
3121 
3122  ast_cond_destroy(&doomed->cond_suspended);
3123  ast_cond_destroy(&doomed->cond_complete);
3124 }
#define ast_cond_destroy(cond)
Definition: lock.h:200
struct controlling the suspension of the session&#39;s serializer.

◆ stream_destroy()

static int stream_destroy ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 456 of file res_pjsip_session.c.

References AST_LIST_TRAVERSE, handler(), sdp_handler_list::list, ast_sip_session_sdp_handler::next, and ast_sip_session_sdp_handler::stream_destroy.

Referenced by session_media_dtor().

457 {
458  struct sdp_handler_list *handler_list = obj;
459  struct ast_sip_session_media *session_media = arg;
461 
462  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
463  handler->stream_destroy(session_media);
464  }
465 
466  return 0;
467 }
void(* stream_destroy)(struct ast_sip_session_media *session_media)
Destroy a session_media created by this handler.
A handler for SDPs in SIP sessions.
struct ast_sip_session_sdp_handler * next
struct sdp_handler_list::@487 list
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
A structure containing SIP session media information.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59

◆ test_is_media_session_equal()

static int test_is_media_session_equal ( struct ast_sip_session_media left,
struct ast_sip_session_media right 
)
static

Definition at line 5580 of file res_pjsip_session.c.

Referenced by test_is_media_state_equal().

5581 {
5582  if (left == right) {
5583  return 1;
5584  }
5585 
5586  if (!left) {
5587  return 1;
5588  }
5589 
5590  if (!right) {
5591  return 0;
5592  }
5593  return memcmp(left, right, sizeof(*left)) == 0;
5594 }

◆ test_is_media_state_equal()

static int test_is_media_state_equal ( struct ast_sip_session_media_state left,
struct ast_sip_session_media_state right,
int  assert_on_failure 
)
static

Definition at line 5596 of file res_pjsip_session.c.

References ast_assert, AST_MEDIA_TYPE_END, ast_stream_topology_equal(), AST_VECTOR_GET, AST_VECTOR_GET_ADDR, AST_VECTOR_SIZE, ast_sip_session_media_state::default_session, ast_sip_session_media::label, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, ast_sip_session_media::stream_num, test_is_media_session_equal(), and ast_sip_session_media_state::topology.

5598 {
5599  int i;
5600  SCOPE_ENTER(2);
5601 
5602  if (left == right) {
5603  SCOPE_EXIT_RTN_VALUE(1, "equal\n");
5604  }
5605 
5606  if (!(left && right)) {
5607  ast_assert(!assert_on_failure);
5608  SCOPE_EXIT_RTN_VALUE(0, "one is null: left: %p right: %p\n", left, right);
5609  }
5610 
5611  if (!ast_stream_topology_equal(left->topology, right->topology)) {
5612  ast_assert(!assert_on_failure);
5613  SCOPE_EXIT_RTN_VALUE(0, "topologies differ\n");
5614  }
5615  if (AST_VECTOR_SIZE(&left->sessions) != AST_VECTOR_SIZE(&right->sessions)) {
5616  ast_assert(!assert_on_failure);
5617  SCOPE_EXIT_RTN_VALUE(0, "session vector sizes different: left %zu != right %zu\n",
5618  AST_VECTOR_SIZE(&left->sessions),
5619  AST_VECTOR_SIZE(&right->sessions));
5620  }
5621  if (AST_VECTOR_SIZE(&left->read_callbacks) != AST_VECTOR_SIZE(&right->read_callbacks)) {
5622  ast_assert(!assert_on_failure);
5623  SCOPE_EXIT_RTN_VALUE(0, "read_callback vector sizes different: left %zu != right %zu\n",
5624  AST_VECTOR_SIZE(&left->read_callbacks),
5625  AST_VECTOR_SIZE(&right->read_callbacks));
5626  }
5627 
5628  for (i = 0; i < AST_VECTOR_SIZE(&left->sessions) ; i++) {
5629  if (!test_is_media_session_equal(AST_VECTOR_GET(&left->sessions, i), AST_VECTOR_GET(&right->sessions, i))) {
5630  ast_assert(!assert_on_failure);
5631  SCOPE_EXIT_RTN_VALUE(0, "Media session %d different\n", i);
5632  }
5633  }
5634 
5635  for (i = 0; i < AST_VECTOR_SIZE(&left->read_callbacks) ; i++) {
5636  if (memcmp(AST_VECTOR_GET_ADDR(&left->read_callbacks, i),
5637  AST_VECTOR_GET_ADDR(&right->read_callbacks, i),
5638  sizeof(struct ast_sip_session_media_read_callback_state)) != 0) {
5639  ast_assert(!assert_on_failure);
5640  SCOPE_EXIT_RTN_VALUE(0, "read_callback %d different\n", i);
5641  }
5642  }
5643 
5644  for (i = 0; i < AST_MEDIA_TYPE_END; i++) {
5645  if (!(left->default_session[i] && right->default_session[i])) {
5646  continue;
5647  }
5648  if (!left->default_session[i] || !right->default_session[i]
5649  || left->default_session[i]->stream_num != right->default_session[i]->stream_num) {
5650  ast_assert(!assert_on_failure);
5651  SCOPE_EXIT_RTN_VALUE(0, "Default media session %d different. Left: %s Right: %s\n", i,
5652  left->default_session[i] ? left->default_session[i]->label : "null",
5653  right->default_session[i] ? right->default_session[i]->label : "null");
5654  }
5655  }
5656 
5657  SCOPE_EXIT_RTN_VALUE(1, "equal\n");
5658 }
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
#define ast_assert(a)
Definition: utils.h:695
static int test_is_media_session_equal(struct ast_sip_session_media *left, struct ast_sip_session_media *right)
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:670
Structure which contains read callback information.
int stream_num
The stream number to place into any resulting frames.
int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right)
Compare two stream topologies to see if they are equal.
Definition: stream.c:696
#define SCOPE_ENTER(level,...)
Non RAII_VAR Scope Trace macros The advantage of these macros is that the EXITs will have the actual ...
Definition: logger.h:780
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Scope Exit with return value.
Definition: logger.h:875
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
struct ast_stream_topology * topology
The media stream topology.
char label[AST_UUID_STR_LEN]
Track label.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ test_media_add()

static struct ast_sip_session_media* test_media_add ( struct ast_sip_session_media_state media_state,
const char *  name,
enum ast_media_type  type,
enum ast_stream_state  state,
int  position 
)
static

Definition at line 5536 of file res_pjsip_session.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_stream_get_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_append_stream(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_set_stream(), AST_VECTOR_REPLACE, ast_sip_session_media::bundle_group, ast_sip_session_media_state::default_session, ast_sip_session_media::keepalive_sched_id, ast_sip_session_media::label, NULL, ast_stream::position, session_media_dtor(), ast_sip_session_media::stream_num, test_stream_alloc(), ast_sip_session_media::timeout_sched_id, ast_sip_session_media_state::topology, ast_sip_session_media::type, and type.

Referenced by AST_TEST_DEFINE().

5539 {
5540  struct ast_sip_session_media *session_media = NULL;
5541  struct ast_stream *stream = NULL;
5542 
5543  stream = test_stream_alloc(name, type, state);
5544  if (!stream) {
5545  return NULL;
5546  }
5547 
5548  if (position >= 0 && position < ast_stream_topology_get_count(media_state->topology)) {
5549  ast_stream_topology_set_stream(media_state->topology, position, stream);
5550  } else {
5551  position = ast_stream_topology_append_stream(media_state->topology, stream);
5552  }
5553 
5554  session_media = ao2_alloc_options(sizeof(*session_media), session_media_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
5555  if (!session_media) {
5556  return NULL;
5557  }
5558 
5559  session_media->keepalive_sched_id = -1;
5560  session_media->timeout_sched_id = -1;
5561  session_media->type = type;
5562  session_media->stream_num = position;
5563  session_media->bundle_group = -1;
5564  strcpy(session_media->label, name);
5565 
5566  if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {
5567  ao2_ref(session_media, -1);
5568 
5569  return NULL;
5570  }
5571 
5572  /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */
5574  media_state->default_session[type] = session_media;
5575  }
5576 
5577  return session_media;
5578 }
static const char type[]
Definition: chan_ooh323.c:109
Set when the stream has been removed/declined.
Definition: stream.h:78
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
#define NULL
Definition: resample.c:96
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int stream_num
The stream number to place into any resulting frames.
static void session_media_dtor(void *obj)
static struct ast_stream * test_stream_alloc(const char *name, enum ast_media_type type, enum ast_stream_state state)
int timeout_sched_id
Scheduler ID for RTP timeout.
static const char name[]
Definition: cdr_mysql.c:74
int bundle_group
The bundle group the stream belongs to.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
int keepalive_sched_id
Scheduler ID for RTP keepalive.
A structure containing SIP session media information.
enum ast_media_type type
Media type of this session media.
struct ast_stream_topology * topology
The media stream topology.
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:284
char label[AST_UUID_STR_LEN]
Track label.
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
unsigned int position
The position of the stream in the topology.
Definition: stream.c:90

◆ test_stream_alloc()

static struct ast_stream* test_stream_alloc ( const char *  name,
enum ast_media_type  type,
enum ast_stream_state  state 
)
static

Definition at line 5523 of file res_pjsip_session.c.

References ast_stream_alloc(), ast_stream_set_state(), and NULL.

Referenced by test_media_add().

5524 {
5525  struct ast_stream *stream;
5526 
5527  stream = ast_stream_alloc(name, type);
5528  if (!stream) {
5529  return NULL;
5530  }
5531  ast_stream_set_state(stream, state);
5532 
5533  return stream;
5534 }
static const char type[]
Definition: chan_ooh323.c:109
#define NULL
Definition: resample.c:96
static const char name[]
Definition: cdr_mysql.c:74
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6108 of file res_pjsip_session.c.

References ao2_cleanup, AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_APP_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_sip_get_sorcery(), ast_sip_unregister_service(), ast_sorcery_delete(), AST_TEST_UNREGISTER, ASTERISK_GPL_KEY, and load_module().

6109 {
6110 #ifdef TEST_FRAMEWORK
6111  AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6112 #endif
6119  return 0;
6120 }
static pjsip_module session_reinvite_module
static struct ast_sip_nat_hook * nat_hook
NAT hook for modifying outgoing messages with SDP.
static pjsip_module session_module
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
static pjsip_module outbound_invite_auth_module

◆ update_completed()

static int update_completed ( void *  vsession)
static

Definition at line 1568 of file res_pjsip_session.c.

References ast_sip_session::inv_session, invite_proceeding(), invite_terminated(), and session.

Referenced by session_inv_on_tsx_state_changed().

1569 {
1570  struct ast_sip_session *session = vsession;
1571  int res;
1572 
1573  if (session->inv_session->invite_tsx) {
1574  res = invite_proceeding(session);
1575  } else {
1576  res = invite_terminated(session);
1577  }
1578 
1579  return res;
1580 }
struct pjsip_inv_session * inv_session
static int invite_terminated(void *vsession)
A structure describing a SIP session.
static struct ast_mansession session
static int invite_proceeding(void *vsession)

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Session resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
static

Definition at line 6128 of file res_pjsip_session.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6128 of file res_pjsip_session.c.

◆ inv_callback

pjsip_inv_callback inv_callback
static

Definition at line 5446 of file res_pjsip_session.c.

◆ nat_hook

struct ast_sip_nat_hook* nat_hook
static

NAT hook for modifying outgoing messages with SDP.

Definition at line 84 of file res_pjsip_session.c.

◆ outbound_invite_auth_module

pjsip_module outbound_invite_auth_module
static
Initial value:
= {
.name = {"Outbound INVITE Auth", 20},
.priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
.on_rx_response = outbound_invite_auth,
}
static pj_bool_t outbound_invite_auth(pjsip_rx_data *rdata)

Definition at line 3290 of file res_pjsip_session.c.

◆ sdp_handlers

struct ao2_container* sdp_handlers
static

Registered SDP stream handlers.

This container is keyed on stream types. Each object in the container is a linked list of handlers for the stream type.

Definition at line 93 of file res_pjsip_session.c.

◆ session_module

pjsip_module session_module
static

Definition at line 2587 of file res_pjsip_session.c.

◆ session_reinvite_module

pjsip_module session_reinvite_module
static
Initial value:
= {
.name = { "Session Re-Invite Module", 24 },
.priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
}
static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata)

Definition at line 2812 of file res_pjsip_session.c.