Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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 "res_pjsip_session/pjsip_session.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 DATASTORE_BUCKETS   53
 
#define DEFAULT_NUM_SESSION_MEDIA   2
 
#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 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)
 
int ast_sip_can_present_connected_id (const struct ast_sip_session *session, const struct ast_party_id *id)
 Determines if the Connected Line info can be presented for this session. More...
 
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...
 
pjsip_dialog * ast_sip_session_get_dialog (const struct ast_sip_session *session)
 Retrieves a dialog from a session. 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...
 
pjsip_inv_state ast_sip_session_get_pjsip_inv_state (const struct ast_sip_session *session)
 Retrieves the pjsip_inv_state from a 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...
 
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, const unsigned int ignore_active_stream_topology)
 
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 int fetch_callerid_num (struct ast_sip_session *session, pjsip_rx_data *rdata, char *buf, size_t len)
 Fetch just the Caller ID number in order of PAI, RPID, From. More...
 
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 pj_status_t session_on_tx_response (pjsip_tx_data *tdata)
 
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 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 = AST_BUILDOPT_SUM, .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

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Definition at line 1237 of file res_pjsip_session.c.

◆ DEFAULT_NUM_SESSION_MEDIA

#define DEFAULT_NUM_SESSION_MEDIA   2

Definition at line 63 of file res_pjsip_session.c.

◆ GET_STREAM_NAME_SAFE

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

Definition at line 1750 of file res_pjsip_session.c.

◆ 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 1748 of file res_pjsip_session.c.

◆ GET_STREAM_STATE_SAFE

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

Definition at line 1749 of file res_pjsip_session.c.

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1238 of file res_pjsip_session.c.

◆ MOD_DATA_NAT_HOOK

#define MOD_DATA_NAT_HOOK   "nat_hook"

Definition at line 60 of file res_pjsip_session.c.

◆ MOD_DATA_ON_RESPONSE

#define MOD_DATA_ON_RESPONSE   "on_response"

Definition at line 59 of file res_pjsip_session.c.

◆ print_debug_details

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

Definition at line 4490 of file res_pjsip_session.c.

◆ SDP_HANDLER_BUCKETS

#define SDP_HANDLER_BUCKETS   11

Definition at line 57 of file res_pjsip_session.c.

◆ STATE_NONE

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

Definition at line 1747 of file res_pjsip_session.c.

◆ STATE_REMOVED

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

Definition at line 1746 of file res_pjsip_session.c.

◆ STREAM_REMOVED

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

Definition at line 1745 of file res_pjsip_session.c.

Enumeration Type Documentation

◆ delayed_method

Enumerator
DELAYED_METHOD_INVITE 
DELAYED_METHOD_UPDATE 
DELAYED_METHOD_BYE 

Definition at line 1306 of file res_pjsip_session.c.

1306 {
1310};
@ DELAYED_METHOD_INVITE
@ DELAYED_METHOD_BYE
@ DELAYED_METHOD_UPDATE

◆ 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 3700 of file res_pjsip_session.c.

3700 {
3701 /*! The extension was successfully found */
3703 /*! The extension specified in the RURI was not found */
3705 /*! The extension specified in the RURI was a partial match */
3707 /*! The RURI is of an unsupported scheme */
3709};
@ SIP_GET_DEST_EXTEN_FOUND
@ SIP_GET_DEST_EXTEN_PARTIAL
@ SIP_GET_DEST_UNSUPPORTED_URI
@ SIP_GET_DEST_EXTEN_NOT_FOUND

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 4441 of file res_pjsip_session.c.

4442{
4443 int id = session_module.id;
4444 struct ast_sip_session *session = NULL;
4445
4446 if (!DEBUG_ATLEAST(5)) {
4447 /* Debug not spamy enough */
4448 return;
4449 }
4450
4451 ast_log(LOG_DEBUG, "Function %s called on event %s\n",
4452 function, pjsip_event_str(e->type));
4453 if (!inv) {
4454 ast_log(LOG_DEBUG, "Transaction %p does not belong to an inv_session?\n", tsx);
4455 ast_log(LOG_DEBUG, "The transaction state is %s\n",
4456 pjsip_tsx_state_str(tsx->state));
4457 return;
4458 }
4459 if (id > -1) {
4460 session = inv->mod_data[session_module.id];
4461 }
4462 if (!session) {
4463 ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv);
4464 } else {
4465 ast_log(LOG_DEBUG, "The state change pertains to the endpoint '%s(%s)'\n",
4467 session->channel ? ast_channel_name(session->channel) : "");
4468 }
4469 if (inv->invite_tsx) {
4470 ast_log(LOG_DEBUG, "The inv session still has an invite_tsx (%p)\n",
4471 inv->invite_tsx);
4472 } else {
4473 ast_log(LOG_DEBUG, "The inv session does NOT have an invite_tsx\n");
4474 }
4475 if (tsx) {
4476 ast_log(LOG_DEBUG, "The %s %.*s transaction involved in this state change is %p\n",
4477 pjsip_role_name(tsx->role),
4478 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4479 tsx);
4480 ast_log(LOG_DEBUG, "The current transaction state is %s\n",
4481 pjsip_tsx_state_str(tsx->state));
4482 ast_log(LOG_DEBUG, "The transaction state change event is %s\n",
4483 pjsip_event_str(e->body.tsx_state.type));
4484 } else {
4485 ast_log(LOG_DEBUG, "There is no transaction involved in this state change\n");
4486 }
4487 ast_log(LOG_DEBUG, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
4488}
static struct ast_mansession session
#define ast_log
Definition: astobj2.c:42
const char * ast_channel_name(const struct ast_channel *chan)
#define DEBUG_ATLEAST(level)
#define LOG_DEBUG
static pjsip_module session_module
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
A structure describing a SIP session.

References ast_channel_name(), ast_log, ast_sorcery_object_get_id(), DEBUG_ATLEAST, LOG_DEBUG, NULL, session, and session_module.

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 6275 of file res_pjsip_session.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 6275 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 5106 of file res_pjsip_session.c.

5107{
5108 pj_str_t stmp;
5109 pjmedia_sdp_attr *attr;
5110 struct sip_session_media_bundle_group bundle_groups[PJMEDIA_MAX_SDP_MEDIA];
5111 int index, mid_id;
5112 struct sip_session_media_bundle_group *bundle_group;
5113
5114 if (session->endpoint->media.webrtc) {
5115 attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
5116 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5117 }
5118
5119 if (!session->endpoint->media.bundle) {
5120 return 0;
5121 }
5122
5123 memset(bundle_groups, 0, sizeof(bundle_groups));
5124
5125 /* Build the bundle group layout so we can then add it to the SDP */
5126 for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
5127 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
5128
5129 /* If this stream is not part of a bundle group we can't add it */
5130 if (session_media->bundle_group == -1) {
5131 continue;
5132 }
5133
5134 bundle_group = &bundle_groups[session_media->bundle_group];
5135
5136 /* If this is the first mid then we need to allocate the attribute string and place BUNDLE in front */
5137 if (!bundle_group->mids[0]) {
5138 bundle_group->mids[0] = session_media->mid;
5139 bundle_group->attr_string = ast_str_create(64);
5140 if (!bundle_group->attr_string) {
5141 continue;
5142 }
5143
5144 ast_str_set(&bundle_group->attr_string, 0, "BUNDLE %s", session_media->mid);
5145 continue;
5146 }
5147
5148 for (mid_id = 1; mid_id < PJMEDIA_MAX_SDP_MEDIA; ++mid_id) {
5149 if (!bundle_group->mids[mid_id]) {
5150 bundle_group->mids[mid_id] = session_media->mid;
5151 ast_str_append(&bundle_group->attr_string, 0, " %s", session_media->mid);
5152 break;
5153 } else if (!strcmp(bundle_group->mids[mid_id], session_media->mid)) {
5154 break;
5155 }
5156 }
5157 }
5158
5159 /* Add all bundle groups that have mids to the SDP */
5160 for (index = 0; index < PJMEDIA_MAX_SDP_MEDIA; ++index) {
5161 bundle_group = &bundle_groups[index];
5162
5163 if (!bundle_group->attr_string) {
5164 continue;
5165 }
5166
5167 attr = pjmedia_sdp_attr_create(pool, "group", pj_cstr(&stmp, ast_str_buffer(bundle_group->attr_string)));
5168 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5169
5170 ast_free(bundle_group->attr_string);
5171 }
5172
5173 return 0;
5174}
#define ast_free(a)
Definition: astmm.h:180
static int answer(void *data)
Definition: chan_pjsip.c:683
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:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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:1113
A structure containing SIP session media information.
int bundle_group
The bundle group the stream belongs to.
char * mid
Media identifier for this stream (may be shared across multiple streams)
Bundle group building structure.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References answer(), ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_session_media::bundle_group, ast_sip_session_media::mid, and session.

Referenced by create_local_sdp().

◆ 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 5052 of file res_pjsip_session.c.

5056{
5057 struct ast_sip_session_sdp_handler *handler = session_media->handler;
5058 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5059 int res = 0;
5060 SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
5061 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5062
5063 if (handler) {
5064 /* if an already assigned handler reports a catastrophic error, fail */
5065 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
5066 if (res < 0) {
5067 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5068 }
5069 SCOPE_EXIT_RTN_VALUE(0, "Had handler\n");
5070 }
5071
5072 handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY);
5073 if (!handler_list) {
5074 SCOPE_EXIT_RTN_VALUE(0, "No handlers\n");
5075 }
5076
5077 /* no handler for this stream type and we have a list to search */
5078 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5079 if (handler == session_media->handler) {
5080 continue;
5081 }
5082 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
5083 if (res < 0) {
5084 /* catastrophic error */
5085 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5086 }
5087 if (res > 0) {
5088 /* Handled by this handler. Move to the next stream */
5089 session_media_set_handler(session_media, handler);
5090 SCOPE_EXIT_RTN_VALUE(0, "Handled\n");
5091 }
5092 }
5093
5094 /* streams that weren't handled won't be included in generated outbound SDP */
5095 SCOPE_EXIT_RTN_VALUE(0, "Not handled\n");
5096}
#define OBJ_KEY
Definition: astobj2.h:1151
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
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:348
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_ENTER(level,...)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
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 struct ao2_container * sdp_handlers
Registered SDP stream handlers.
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_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 ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition: strings.h:1189
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
enum ast_media_type type
Media type of this session media.
A handler for SDPs in SIP sessions.
struct ast_sip_session_sdp_handler * next
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 RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References answer(), 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_media::handler, handler(), ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, sdp_handlers, session, session_media_set_handler(), and ast_sip_session_media::type.

Referenced by create_local_sdp().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 6275 of file res_pjsip_session.c.

◆ ast_sip_can_present_connected_id()

int ast_sip_can_present_connected_id ( const struct ast_sip_session session,
const struct ast_party_id id 
)

Determines if the Connected Line info can be presented for this session.

Parameters
sessionThe session
idThe Connected Line info to evaluate
Return values
1The Connected Line info can be presented
0The Connected Line info cannot be presented

Definition at line 131 of file res_pjsip_session.c.

132{
133 return id->number.valid
134 && (session->endpoint->id.trust_outbound
136}
#define AST_PRES_ALLOWED
Definition: callerid.h:432
#define AST_PRES_RESTRICTION
Definition: callerid.h:431
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1821

References ast_party_id_presentation(), AST_PRES_ALLOWED, AST_PRES_RESTRICTION, and session.

Referenced by add_id_headers(), and stir_shaken_outgoing_request().

◆ 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 2994 of file res_pjsip_session.c.

2995{
2996 struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
2997
2998 if (!channel) {
2999 return NULL;
3000 }
3001
3002 ao2_ref(pvt, +1);
3003 channel->pvt = pvt;
3004 ao2_ref(session, +1);
3005 channel->session = session;
3006
3007 return channel;
3008}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static void sip_channel_destroy(void *obj)
Destructor for SIP channel.
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
void * pvt
Pointer to channel specific implementation information, must be ao2 object.

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

Referenced by chan_pjsip_new().

◆ 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 3648 of file res_pjsip_session.c.

3649{
3650 pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3651 struct ast_sip_session *session;
3652
3653 if (!inv_session ||
3654 !(session = inv_session->mod_data[session_module.id])) {
3655 return NULL;
3656 }
3657
3658 ao2_ref(session, +1);
3659
3660 return session;
3661}
struct pjsip_inv_session * inv_session

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

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

◆ 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 1284 of file res_pjsip_session.c.

1285{
1286 ast_assert(datastore != NULL);
1287 ast_assert(datastore->info != NULL);
1288 ast_assert(ast_strlen_zero(datastore->uid) == 0);
1289
1290 if (!ao2_link(session->datastores, datastore)) {
1291 return -1;
1292 }
1293 return 0;
1294}
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
const struct ast_datastore_info * info
Definition: datastore.h:67
const char * uid
Definition: datastore.h:65
#define ast_assert(a)
Definition: utils.h:739

References ao2_link, ast_assert, ast_strlen_zero(), ast_datastore::info, NULL, session, and ast_datastore::uid.

Referenced by add_header(), aoc_send_as_xml(), ast_sip_session_add_reason_header(), chan_pjsip_incoming_request(), chan_pjsip_session_begin(), handle_incoming_request(), incoming_request(), incoming_response(), rfc3329_incoming_response(), session_refresh_state_get_or_alloc(), and t38_state_get_or_alloc().

◆ 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
invThe PJSIP INVITE session data
rdataINVITE request received (NULL if for outgoing allocation)

Definition at line 3010 of file res_pjsip_session.c.

3012{
3014 struct ast_sip_session *ret_session;
3015 int dsp_features = 0;
3016
3018 if (!session) {
3019 return NULL;
3020 }
3021
3022 AST_LIST_HEAD_INIT(&session->supplements);
3023 AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
3025
3027 if (!session->direct_media_cap) {
3028 return NULL;
3029 }
3032 if (!session->datastores) {
3033 return NULL;
3034 }
3035 session->active_media_state = ast_sip_session_media_state_alloc();
3036 if (!session->active_media_state) {
3037 return NULL;
3038 }
3039 session->pending_media_state = ast_sip_session_media_state_alloc();
3040 if (!session->pending_media_state) {
3041 return NULL;
3042 }
3043 if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
3044 return NULL;
3045 }
3046
3048 dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3049 }
3050 if (endpoint->faxdetect) {
3051 dsp_features |= DSP_FEATURE_FAX_DETECT;
3052 }
3053 if (dsp_features) {
3054 session->dsp = ast_dsp_new();
3055 if (!session->dsp) {
3056 return NULL;
3057 }
3058
3059 ast_dsp_set_features(session->dsp, dsp_features);
3060 }
3061
3062 session->endpoint = ao2_bump(endpoint);
3063
3064 if (rdata) {
3065 /*
3066 * We must continue using the serializer that the original
3067 * INVITE came in on for the dialog. There may be
3068 * retransmissions already enqueued in the original
3069 * serializer that can result in reentrancy and message
3070 * sequencing problems.
3071 */
3072 session->serializer = ast_sip_get_distributor_serializer(rdata);
3073 } else {
3074 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
3075
3076 /* Create name with seq number appended. */
3077 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outsess/%s",
3079
3080 session->serializer = ast_sip_create_serializer(tps_name);
3081 }
3082 if (!session->serializer) {
3083 return NULL;
3084 }
3087
3088 /* When a PJSIP INVITE session is created it is created with a reference
3089 * count of 1, with that reference being managed by the underlying state
3090 * of the INVITE session itself. When the INVITE session transitions to
3091 * a DISCONNECTED state that reference is released. This means we can not
3092 * rely on that reference to ensure the INVITE session remains for the
3093 * lifetime of our session. To ensure it does we add our own reference
3094 * and release it when our own session goes away, ensuring that the INVITE
3095 * session remains for the lifetime of session.
3096 */
3097
3098#ifdef HAVE_PJSIP_INV_SESSION_REF
3099 if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
3100 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3101 return NULL;
3102 }
3103#endif
3104
3105 pjsip_dlg_inc_session(inv_session->dlg, &session_module);
3106 inv_session->mod_data[session_module.id] = ao2_bump(session);
3107 session->contact = ao2_bump(contact);
3108 session->inv_session = inv_session;
3109
3110 session->dtmf = endpoint->dtmf;
3111 session->moh_passthrough = endpoint->moh_passthrough;
3112
3114 /* Release the ref held by session->inv_session */
3115 ao2_ref(session, -1);
3116 return NULL;
3117 }
3118
3119 session->authentication_challenge_count = 0;
3120
3121 /* Fire session begin handlers */
3123
3124 /* Avoid unnecessary ref manipulation to return a session */
3125 ret_session = session;
3126 session = NULL;
3127 return ret_session;
3128}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
Definition: channel.c:1757
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
#define DSP_FEATURE_FAX_DETECT
Definition: dsp.h:29
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
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.
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.
#define LOG_ERROR
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
@ AST_SIP_DTMF_AUTO
Definition: res_pjsip.h:554
@ AST_SIP_DTMF_INBAND
Definition: res_pjsip.h:550
static void handle_session_begin(struct ast_sip_session *session)
#define DATASTORE_BUCKETS
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
static void session_destructor(void *obj)
static int datastore_cmp(void *obj, void *arg, int flags)
static int datastore_hash(const void *obj, int flags)
int ast_sip_session_add_supplements(struct ast_sip_session *session)
Add supplements to a SIP session.
Definition: pjsip_session.c:90
unsigned int moh_passthrough
Definition: res_pjsip.h:1034
enum ast_sip_dtmf_mode dtmf
Definition: res_pjsip.h:1012
unsigned int faxdetect
Definition: res_pjsip.h:1024
struct ast_sip_contact * contact
struct ast_sip_endpoint * endpoint
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 AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

References 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::contact, DATASTORE_BUCKETS, datastore_cmp(), datastore_hash(), DSP_FEATURE_DIGIT_DETECT, DSP_FEATURE_FAX_DETECT, ast_sip_endpoint::dtmf, ast_sip_session::endpoint, ast_sip_endpoint::faxdetect, handle_session_begin(), ast_sip_session::inv_session, LOG_ERROR, ast_sip_endpoint::moh_passthrough, NULL, RAII_VAR, session, session_destructor(), and session_module.

Referenced by ast_sip_session_create_outgoing(), and handle_new_invite_request().

◆ 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 1254 of file res_pjsip_session.c.

1255{
1256 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
1257 char uuid_buf[AST_UUID_STR_LEN];
1258 const char *uid_ptr = uid;
1259
1260 if (!info) {
1261 return NULL;
1262 }
1263
1264 datastore = ao2_alloc(sizeof(*datastore), session_datastore_destroy);
1265 if (!datastore) {
1266 return NULL;
1267 }
1268
1269 datastore->info = info;
1270 if (ast_strlen_zero(uid)) {
1271 /* They didn't provide an ID so we'll provide one ourself */
1272 uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
1273 }
1274
1275 datastore->uid = ast_strdup(uid_ptr);
1276 if (!datastore->uid) {
1277 return NULL;
1278 }
1279
1280 ao2_ref(datastore, +1);
1281 return datastore;
1282}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
def info(msg)
static void session_datastore_destroy(void *obj)
Structure for a data store object.
Definition: datastore.h:64
#define AST_UUID_STR_LEN
Definition: uuid.h:27
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:141

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(), aoc_send_as_xml(), ast_sip_session_add_reason_header(), chan_pjsip_incoming_request(), chan_pjsip_session_begin(), handle_incoming_request(), incoming_request(), incoming_response(), rfc3329_incoming_response(), session_refresh_state_get_or_alloc(), and t38_state_get_or_alloc().

◆ 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 2867 of file res_pjsip_session.c.

2868{
2869 pjmedia_sdp_session *offer;
2871
2872 if (!(offer = create_local_sdp(session->inv_session, session, NULL, 0))) {
2873 pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
2874 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create offer\n");
2875 }
2876
2877 pjsip_inv_set_local_sdp(session->inv_session, offer);
2878 pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
2879#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
2880 if (!session->endpoint->preferred_codec_only) {
2881 pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
2882 }
2883#endif
2884
2885 /*
2886 * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the
2887 * From in the initial INVITE will be wrong but the rest of the messages will be OK.
2888 */
2890
2891 if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
2892 SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
2893 }
2894
2896}
static void set_from_header(struct ast_sip_session *session)
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer, const unsigned int ignore_active_stream_topology)

References ast_sip_session_get_name(), create_local_sdp(), NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, and set_from_header().

Referenced by call().

◆ 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 3337 of file res_pjsip_session.c.

3340{
3341 const char *uri = NULL;
3342 RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup);
3343 RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
3344 pjsip_timer_setting timer;
3345 pjsip_dialog *dlg;
3346 struct pjsip_inv_session *inv_session;
3348 struct ast_sip_session *ret_session;
3349 SCOPE_ENTER(1, "%s %s Topology: %s\n", ast_sorcery_object_get_id(endpoint), request_user,
3350 ast_str_tmp(256, ast_stream_topology_to_str(req_topology, &STR_TMP)));
3351
3352 /* If no location has been provided use the AOR list from the endpoint itself */
3353 if (location || !contact) {
3354 location = S_OR(location, endpoint->aors);
3355
3357 &found_aor, &found_contact);
3358 if (!found_contact || ast_strlen_zero(found_contact->uri)) {
3359 uri = location;
3360 } else {
3361 uri = found_contact->uri;
3362 }
3363 } else {
3364 uri = contact->uri;
3365 }
3366
3367 /* If we still have no URI to dial fail to create the session */
3368 if (ast_strlen_zero(uri)) {
3369 ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
3371 SCOPE_EXIT_RTN_VALUE(NULL, "No URI\n");
3372 }
3373
3374 if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
3375 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create dialog\n");
3376 }
3377
3378 if (setup_outbound_invite_auth(dlg)) {
3379 pjsip_dlg_terminate(dlg);
3380 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't setup auth\n");
3381 }
3382
3383 if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
3384 pjsip_dlg_terminate(dlg);
3385 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create uac\n");
3386 }
3387#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3388 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3389#endif
3390
3391 pjsip_timer_setting_default(&timer);
3393 timer.sess_expires = endpoint->extensions.timer.sess_expires;
3394 pjsip_timer_init_session(inv_session, &timer);
3395
3396 session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact,
3397 inv_session, NULL);
3398 if (!session) {
3399 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3400 return NULL;
3401 }
3402 session->aor = ao2_bump(found_aor);
3403 session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;
3404
3406
3407 if (ast_stream_topology_get_count(req_topology) > 0) {
3408 /* get joint caps between req_topology and endpoint topology */
3409 int i;
3410
3411 for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {
3412 struct ast_stream *req_stream;
3413 struct ast_stream *clone_stream;
3414
3415 req_stream = ast_stream_topology_get_stream(req_topology, i);
3416
3418 continue;
3419 }
3420
3421 clone_stream = ast_sip_session_create_joint_call_stream(session, req_stream);
3422 if (!clone_stream || ast_stream_get_format_count(clone_stream) == 0) {
3423 ast_stream_free(clone_stream);
3424 continue;
3425 }
3426
3427 if (!session->pending_media_state->topology) {
3428 session->pending_media_state->topology = ast_stream_topology_alloc();
3429 if (!session->pending_media_state->topology) {
3430 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3431 ao2_ref(session, -1);
3432 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create topology\n");
3433 }
3434 }
3435
3436 if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) {
3437 ast_stream_free(clone_stream);
3438 continue;
3439 }
3440 }
3441 }
3442
3443 if (!session->pending_media_state->topology) {
3444 /* Use the configured topology on the endpoint as the pending one */
3445 session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology);
3446 if (!session->pending_media_state->topology) {
3447 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3448 ao2_ref(session, -1);
3449 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't clone topology\n");
3450 }
3451 }
3452
3453 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3454 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3455 /* Since we are not notifying ourselves that the INVITE session is being terminated
3456 * we need to manually drop its reference to session
3457 */
3458 ao2_ref(session, -1);
3459 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't add usage\n");
3460 }
3461
3462 /* Avoid unnecessary ref manipulation to return a session */
3463 ret_session = session;
3464 session = NULL;
3465 SCOPE_EXIT_RTN_VALUE(ret_session);
3466}
static struct ast_timer * timer
Definition: chan_iax2.c:364
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
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:964
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition: res_pjsip.h:1306
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_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 int setup_outbound_invite_auth(pjsip_dialog *dlg)
@ AST_SIP_SESSION_OUTGOING_CALL
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.
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition: stream.h:78
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
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
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
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 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
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
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 S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
A SIP address of record.
Definition: res_pjsip.h:478
Contact associated with an address of record.
Definition: res_pjsip.h:392
const ast_string_field uri
Definition: res_pjsip.h:414
struct ast_sip_timer_options timer
Definition: res_pjsip.h:721
struct ast_party_id self
Definition: res_pjsip.h:772
struct ast_stream_topology * topology
Definition: res_pjsip.h:923
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:1002
const ast_string_field aors
Definition: res_pjsip.h:992
struct ast_sip_endpoint_extensions extensions
Definition: res_pjsip.h:994
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:996
unsigned int sess_expires
Definition: res_pjsip.h:708
unsigned int min_se
Definition: res_pjsip.h:706

References ao2_bump, ao2_cleanup, ao2_ref, 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::contact, ast_sip_session::endpoint, ast_sip_endpoint::extensions, ast_sip_endpoint_extensions::flags, ast_sip_endpoint::id, ast_sip_session::inv_session, LOG_ERROR, ast_sip_endpoint::media, ast_sip_timer_options::min_se, NULL, RAII_VAR, S_OR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, ast_sip_endpoint_id_configuration::self, ast_sip_timer_options::sess_expires, session, session_module, setup_outbound_invite_auth(), timer, ast_sip_endpoint_extensions::timer, ast_sip_endpoint_media_configuration::topology, and ast_sip_contact::uri.

Referenced by request().

◆ 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 3574 of file res_pjsip_session.c.

3575{
3576 pj_time_val delay = { .sec = 60, };
3577 int res;
3578
3579 /* The session should not have an active deferred termination request. */
3580 ast_assert(!session->defer_terminate);
3581
3582 session->defer_terminate = 1;
3583
3584 session->defer_end = 1;
3585 session->ended_while_deferred = 0;
3586
3587 ao2_ref(session, +1);
3588 pj_timer_entry_init(&session->scheduled_termination, 0, session, session_termination_cb);
3589
3590 res = (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
3591 &session->scheduled_termination, &delay) != PJ_SUCCESS) ? -1 : 0;
3592 if (res) {
3593 session->defer_terminate = 0;
3594 ao2_ref(session, -1);
3595 }
3596 return res;
3597}
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
static void session_termination_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)

References ao2_ref, ast_assert, ast_sip_get_pjsip_endpoint(), session, and session_termination_cb().

Referenced by refer_incoming_attended_request(), and refer_incoming_blind_request().

◆ 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 3614 of file res_pjsip_session.c.

3615{
3616 if (!session->defer_terminate) {
3617 /* Already canceled or timer fired. */
3618 return;
3619 }
3620
3621 session->defer_terminate = 0;
3622
3623 if (session->terminate_while_deferred) {
3624 /* Complete the termination started by the upper layer. */
3626 }
3627
3628 /* Stop the termination timer if it is still running. */
3630}
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.

References ast_sip_session_terminate(), session, and sip_session_defer_termination_stop_timer().

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

◆ 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 3632 of file res_pjsip_session.c.

3633{
3634 if (!session->defer_end) {
3635 return;
3636 }
3637
3638 session->defer_end = 0;
3639
3640 if (session->ended_while_deferred) {
3641 /* Complete the session end started by the remote hangup. */
3642 ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3643 session->ended_while_deferred = 0;
3645 }
3646}
#define ast_debug(level,...)
Log a DEBUG message.
static int session_end(void *vsession)

References ast_debug, ast_sip_session_get_name(), session, 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().

◆ 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 1296 of file res_pjsip_session.c.

1297{
1298 return ao2_find(session->datastores, name, OBJ_KEY);
1299}
static const char name[]
Definition: format_mp3.c:68

References ao2_find, name, OBJ_KEY, and session.

Referenced by add_header(), aoc_bye_outgoing_request(), aoc_bye_outgoing_response(), aoc_invite_outgoing_response(), aoc_send_as_xml(), chan_pjsip_get_rtp_peer(), channel_read_pjsip(), direct_media_mitigate_glare(), handle_outgoing_response(), incoming_request(), incoming_response(), outgoing_request(), read_header(), read_headers(), reason_header_outgoing_response(), remove_header(), rfc3329_incoming_response(), rfc3329_outgoing_request(), session_refresh_state_get_or_alloc(), t38_automatic_reject(), t38_state_get_or_alloc(), and update_header().

◆ ast_sip_session_get_dialog()

pjsip_dialog * ast_sip_session_get_dialog ( const struct ast_sip_session session)

Retrieves a dialog from a session.

Parameters
sessionThe session to retrieve the dialog from
Return values
non-NULLif dialog exists
NULLif no dialog

Definition at line 3663 of file res_pjsip_session.c.

3664{
3665 pjsip_inv_session *inv_session = session->inv_session;
3666
3667 if (!inv_session) {
3668 return NULL;
3669 }
3670
3671 return inv_session->dlg;
3672}

References ast_sip_session::inv_session, NULL, and session.

◆ 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 117 of file res_pjsip_session.c.

118{
119 if (!session) {
120 return "(null session)";
121 }
122 if (session->channel) {
123 return ast_channel_name(session->channel);
124 } else if (session->endpoint) {
125 return ast_sorcery_object_get_id(session->endpoint);
126 } else {
127 return "unknown";
128 }
129}

References ast_channel_name(), ast_sorcery_object_get_id(), and session.

Referenced by add_date_header(), add_eprofile_to_channel(), add_fingerprints_if_present(), add_sdp_streams(), answer(), apply_negotiated_sdp_stream(), ast_sip_session_add_reason_header(), 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_prack(), 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(), process_failure(), reason_header_outgoing_response(), reschedule_reinvite(), resend_reinvite(), sdp_requires_deferral(), send_delayed_request(), send_topology_change_refresh(), session_destructor(), session_inv_on_create_offer(), 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(), sip_session_refresh(), stir_shaken_incoming_request(), and stir_shaken_outgoing_request().

◆ ast_sip_session_get_pjsip_inv_state()

pjsip_inv_state ast_sip_session_get_pjsip_inv_state ( const struct ast_sip_session session)

Retrieves the pjsip_inv_state from a session.

Parameters
sessionThe session to retrieve the state from
Return values
stateif inv_session exists
PJSIP_INV_STATE_NULLif inv_session is NULL

Definition at line 3674 of file res_pjsip_session.c.

3675{
3676 pjsip_inv_session *inv_session = session->inv_session;
3677
3678 if (!inv_session) {
3679 return PJSIP_INV_STATE_NULL;
3680 }
3681
3682 return inv_session->state;
3683}

References ast_sip_session::inv_session, and session.

◆ 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 368 of file res_pjsip_session.c.

369{
370 int index;
371
372 if (!session->pending_media_state->topology) {
373 ast_log(LOG_WARNING, "Pending topology was NULL for channel '%s'\n",
374 session->channel ? ast_channel_name(session->channel) : "unknown");
375 return 0;
376 }
377
379 return 0;
380 }
381
382 for (index = 0; index < ast_stream_topology_get_count(session->pending_media_state->topology); ++index) {
383 if (ast_stream_get_type(ast_stream_topology_get_stream(session->pending_media_state->topology, index)) !=
384 ast_stream_get_type(stream)) {
385 continue;
386 }
387
388 return ast_stream_topology_get_stream(session->pending_media_state->topology, index) == stream ? 1 : 0;
389 }
390
391 return 0;
392}
#define LOG_WARNING
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316

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(), LOG_WARNING, and session.

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

◆ 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 394 of file res_pjsip_session.c.

396{
397 struct ast_sip_session_media_read_callback_state callback_state = {
398 .fd = fd,
399 .read_callback = callback,
400 .session = session_media,
401 };
402
403 /* The contents of the vector are whole structs and not pointers */
404 return AST_VECTOR_APPEND(&session->pending_media_state->read_callbacks, callback_state);
405}
Structure which contains read callback information.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

References AST_VECTOR_APPEND, ast_sip_session_media_read_callback_state::fd, and session.

Referenced by apply_negotiated_sdp_stream().

◆ 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 423 of file res_pjsip_session.c.

424{
425 int index;
426
427 if (!session->endpoint->media.bundle || ast_strlen_zero(session_media->mid)) {
428 return session_media;
429 }
430
431 for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
432 struct ast_sip_session_media *bundle_group_session_media;
433
434 bundle_group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
435
436 /* The first session which is in the bundle group is considered the authoritative session for transport */
437 if (bundle_group_session_media->bundle_group == session_media->bundle_group) {
438 return bundle_group_session_media;
439 }
440 }
441
442 return session_media;
443}

References ast_strlen_zero(), AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_session_media::bundle_group, ast_sip_session_media::mid, and session.

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

◆ 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 407 of file res_pjsip_session.c.

409{
410 if (session_media->write_callback) {
411 if (session_media->write_callback == callback) {
412 return 0;
413 }
414
415 return -1;
416 }
417
418 session_media->write_callback = callback;
419
420 return 0;
421}
ast_sip_session_media_write_cb write_callback
The write callback when writing frames.

References ast_sip_session_media::write_callback.

Referenced by apply_negotiated_sdp_stream().

◆ 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 499 of file res_pjsip_session.c.

501{
502 struct ast_sip_session_media *session_media = NULL;
503 struct ast_sip_session_media *current_session_media = NULL;
504 SCOPE_ENTER(1, "%s Adding position %d\n", ast_sip_session_get_name(session), position);
505
506 /* It is possible for this media state to already contain a session for the stream. If this
507 * is the case we simply return it.
508 */
509 if (position < AST_VECTOR_SIZE(&media_state->sessions)) {
510 current_session_media = AST_VECTOR_GET(&media_state->sessions, position);
511 if (current_session_media && current_session_media->type == type) {
512 SCOPE_EXIT_RTN_VALUE(current_session_media, "Using existing media_session\n");
513 }
514 }
515
516 /* Determine if we can reuse the session media from the active media state if present */
517 if (position < AST_VECTOR_SIZE(&session->active_media_state->sessions)) {
518 session_media = AST_VECTOR_GET(&session->active_media_state->sessions, position);
519 /* A stream can never exist without an accompanying media session */
520 if (session_media->type == type) {
521 ao2_ref(session_media, +1);
522 ast_trace(1, "Reusing existing media session\n");
523 /*
524 * If this session_media was previously removed, its bundle group was probably reset
525 * to -1 so if bundling is enabled on the endpoint, we need to reset it to 0, set
526 * the bundled flag and reset its mid.
527 */
528 if (session->endpoint->media.bundle && session_media->bundle_group == -1) {
529 session_media->bundled = session->endpoint->media.webrtc;
530 session_media->bundle_group = 0;
531 ast_free(session_media->mid);
532 if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {
533 ao2_ref(session_media, -1);
534 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");
535 }
536 }
537 } else {
538 ast_trace(1, "Can't reuse existing media session because the types are different. %s <> %s\n",
540 session_media = NULL;
541 }
542 }
543
544 if (!session_media) {
545 /* No existing media session we can use so create a new one */
546 session_media = ao2_alloc_options(sizeof(*session_media), session_media_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
547 if (!session_media) {
548 return NULL;
549 }
550 ast_trace(1, "Creating new media session\n");
551
552 session_media->encryption = session->endpoint->media.rtp.encryption;
553 session_media->remote_ice = session->endpoint->media.rtp.ice_support;
554 session_media->remote_rtcp_mux = session->endpoint->media.rtcp_mux;
555 session_media->keepalive_sched_id = -1;
556 session_media->timeout_sched_id = -1;
557 session_media->type = type;
558 session_media->stream_num = position;
559
560 if (session->endpoint->media.bundle) {
561 /* This is a new stream so create a new mid based on media type and position, which makes it unique.
562 * If this is the result of an offer the mid will just end up getting replaced.
563 */
564 if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {
565 ao2_ref(session_media, -1);
566 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");
567 }
568 session_media->bundle_group = 0;
569
570 /* Some WebRTC clients can't handle an offer to bundle media streams. Instead they expect them to
571 * already be bundled. Every client handles this scenario though so if WebRTC is enabled just go
572 * ahead and treat the streams as having already been bundled.
573 */
574 session_media->bundled = session->endpoint->media.webrtc;
575 } else {
576 session_media->bundle_group = -1;
577 }
578 }
579
580 ast_free(session_media->stream_name);
581 session_media->stream_name = ast_strdup(ast_stream_get_name(ast_stream_topology_get_stream(media_state->topology, position)));
582
583 if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {
584 ao2_ref(session_media, -1);
585
586 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't replace media_session\n");
587 }
588
589 ao2_cleanup(current_session_media);
590
591 /* 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 */
593 ast_trace(1, "Setting media session as default for %s\n", ast_codec_media_type2str(session_media->type));
594
595 media_state->default_session[type] = session_media;
596 }
597
598 SCOPE_EXIT_RTN_VALUE(session_media, "Done\n");
599}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
static const char type[]
Definition: chan_ooh323.c:109
#define ast_trace(level,...)
static void session_media_dtor(void *obj)
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_media_state::@263 sessions
Mapping of stream to media sessions.
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
char * stream_name
Stream name.
unsigned int remote_ice
Does remote support ice.
unsigned int remote_rtcp_mux
Does remote support rtcp_mux.
int timeout_sched_id
Scheduler ID for RTP timeout.
int stream_num
The stream number to place into any resulting frames.
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.
int keepalive_sched_id
Scheduler ID for RTP keepalive.
#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

References 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_session_media::bundle_group, ast_sip_session_media::bundled, ast_sip_session_media_state::default_session, ast_sip_session_media::encryption, ast_sip_session_media::keepalive_sched_id, ast_sip_session_media::mid, NULL, ast_sip_session_media::remote_ice, ast_sip_session_media::remote_rtcp_mux, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_media_dtor(), ast_sip_session_media_state::sessions, 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, type, and ast_sip_session_media::type.

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

◆ 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 247 of file res_pjsip_session.c.

248{
251}
#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)

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().

◆ 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 306 of file res_pjsip_session.c.

307{
308 struct ast_sip_session_media_state *cloned;
309 int index;
310
311 if (!media_state) {
312 return NULL;
313 }
314
316 AST_VECTOR_SIZE(&media_state->sessions),
317 AST_VECTOR_SIZE(&media_state->read_callbacks));
318 if (!cloned) {
319 return NULL;
320 }
321
322 if (media_state->topology) {
323 cloned->topology = ast_stream_topology_clone(media_state->topology);
324 if (!cloned->topology) {
326 return NULL;
327 }
328 }
329
330 for (index = 0; index < AST_VECTOR_SIZE(&media_state->sessions); ++index) {
331 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index);
333
334 ao2_bump(session_media);
335 if (AST_VECTOR_REPLACE(&cloned->sessions, index, session_media)) {
336 ao2_cleanup(session_media);
337 }
339 !cloned->default_session[type]) {
340 cloned->default_session[type] = session_media;
341 }
342 }
343
344 for (index = 0; index < AST_VECTOR_SIZE(&media_state->read_callbacks); ++index) {
346
348 }
349
350 return cloned;
351}
ast_media_type
Types of media.
Definition: codec.h:30
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
ast_sip_session_media_read_cb read_callback
The callback to invoke.
Structure which contains media state information (streams, sessions)
struct ast_sip_session_media_state::@264 read_callbacks
Added read callbacks - these are whole structs and not pointers.
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:668

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::read_callbacks, ast_sip_session_media_state::sessions, 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().

◆ 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 353 of file res_pjsip_session.c.

354{
355 if (!media_state) {
356 return;
357 }
358
359 /* This will reset the internal state so we only have to free persistent things */
361
362 AST_VECTOR_FREE(&media_state->sessions);
363 AST_VECTOR_FREE(&media_state->read_callbacks);
364
365 ast_free(media_state);
366}
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_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174

References ast_free, ast_sip_session_media_state_reset(), AST_VECTOR_FREE, ast_sip_session_media_state::read_callbacks, and ast_sip_session_media_state::sessions.

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().

◆ 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 287 of file res_pjsip_session.c.

288{
289 int index;
290
291 if (!media_state) {
292 return;
293 }
294
295 AST_VECTOR_RESET(&media_state->sessions, ao2_cleanup);
297
298 for (index = 0; index < AST_MEDIA_TYPE_END; ++index) {
299 media_state->default_session[index] = NULL;
300 }
301
303 media_state->topology = NULL;
304}
@ AST_MEDIA_TYPE_END
Definition: codec.h:36
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571

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, ast_sip_session_media_state::read_callbacks, ast_sip_session_media_state::sessions, 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().

◆ 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
sip_sessionSession on which to save active media state for
media_stateThe media state to save

Definition at line 253 of file res_pjsip_session.c.

254{
255 int i;
256 int ret;
257
258 if (!media_state || !sip_session) {
259 return;
260 }
261
262 for (i = 0; i < AST_VECTOR_SIZE(&media_state->sessions); i++) {
263 struct ast_rtp_instance_stats *stats_tmp = NULL;
264 struct ast_sip_session_media *media = AST_VECTOR_GET(&media_state->sessions, i);
265 if (!media || !media->rtp) {
266 continue;
267 }
268
269 stats_tmp = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
270 if (!stats_tmp) {
271 return;
272 }
273
275 if (ret) {
276 ast_free(stats_tmp);
277 continue;
278 }
279
280 /* remove all the duplicated stats if exist */
282
283 AST_VECTOR_APPEND(&sip_session->media_stats, stats_tmp);
284 }
285}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static int media_stats_local_ssrc_cmp(const struct ast_rtp_instance_stats *vec_elem, const struct ast_rtp_instance_stats *srch)
@ AST_RTP_INSTANCE_STAT_ALL
Definition: rtp_engine.h:184
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:2459
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sip_session::@267 media_stats
#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

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, ast_sip_session::media_stats, media_stats_local_ssrc_cmp(), NULL, ast_sip_session_media::rtp, and ast_sip_session_media_state::sessions.

Referenced by ast_sip_session_terminate(), and handle_negotiated_sdp().

◆ 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 2536 of file res_pjsip_session.c.

2542{
2543 return sip_session_refresh(session, on_request_creation, on_sdp_creation,
2544 on_response, method, generate_new_sdp, media_state, NULL, 0);
2545}
const char * method
Definition: res_pjsip.c:1279
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)

References method, NULL, session, 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().

◆ 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
Return values
0Successfully updated the SDP answer
-1Failure to updated the SDP answer

Definition at line 2547 of file res_pjsip_session.c.

2549{
2550 pjsip_inv_session *inv_session = session->inv_session;
2551 pjmedia_sdp_session *new_answer = NULL;
2552 const pjmedia_sdp_session *previous_offer = NULL;
2554
2555 /* The SDP answer can only be regenerated if it is still pending to be sent */
2556 if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER &&
2557 pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) {
2558 ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n",
2559 ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg)));
2560 SCOPE_EXIT_RTN_VALUE(-1, "Bad negotiation state\n");
2561 }
2562
2563 pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer);
2564 if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2565 /* Transition the SDP negotiator back to when it received the remote offer */
2566 pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0);
2567 pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer);
2568 }
2569
2570 new_answer = create_local_sdp(inv_session, session, previous_offer, 0);
2571 if (!new_answer) {
2572 ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n",
2573 ast_channel_name(session->channel));
2574 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create new SDP\n");
2575 }
2576
2577 if (on_sdp_creation) {
2578 if (on_sdp_creation(session, new_answer)) {
2579 SCOPE_EXIT_RTN_VALUE(-1, "Callback failed\n");
2580 }
2581 }
2582
2583 pjsip_inv_set_sdp_answer(inv_session, new_answer);
2584
2586}

References ast_channel_name(), ast_log, ast_sip_session_get_name(), create_local_sdp(), LOG_WARNING, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and session.

Referenced by dtmf_mode_refresh_cb().

◆ 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 147 of file res_pjsip_session.c.

148{
149 RAII_VAR(struct sdp_handler_list *, handler_list,
150 ao2_find(sdp_handlers, stream_type, OBJ_KEY), ao2_cleanup);
152
153 if (handler_list) {
154 struct ast_sip_session_sdp_handler *iter;
155 /* Check if this handler is already registered for this stream type */
156 AST_LIST_TRAVERSE(&handler_list->list, iter, next) {
157 if (!strcmp(iter->id, handler->id)) {
158 ast_log(LOG_WARNING, "Handler '%s' already registered for stream type '%s'.\n", handler->id, stream_type);
159 return -1;
160 }
161 }
162 AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
163 ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
164
165 return 0;
166 }
167
168 /* No stream of this type has been registered yet, so we need to create a new list */
169 handler_list = ao2_alloc(sizeof(*handler_list) + strlen(stream_type), NULL);
170 if (!handler_list) {
171 return -1;
172 }
173 /* Safe use of strcpy */
174 strcpy(handler_list->stream_type, stream_type);
175 AST_LIST_HEAD_INIT_NOLOCK(&handler_list->list);
176 AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
177 if (!ao2_link(sdp_handlers, handler_list)) {
178 return -1;
179 }
180 ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
181
182 return 0;
183}
ast_mutex_t lock
Definition: app_sla.c:331
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604

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, handler(), ast_sip_session_sdp_handler::id, lock, LOG_WARNING, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, SCOPED_AO2LOCK, sdp_handlers, and sdp_handler_list::stream_type.

Referenced by load_module().

◆ 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 1301 of file res_pjsip_session.c.

1302{
1303 ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
1304}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039

References ao2_callback, name, NULL, OBJ_KEY, OBJ_NODATA, OBJ_UNLINK, and session.

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

◆ 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 2818 of file res_pjsip_session.c.

2819{
2820 if (!session->deferred_reinvite) {
2821 return;
2822 }
2823
2824 if (session->channel) {
2825 pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(),
2826 session->deferred_reinvite, NULL, NULL);
2827 }
2828 pjsip_rx_data_free_cloned(session->deferred_reinvite);
2829 session->deferred_reinvite = NULL;
2830}

References ast_sip_get_pjsip_endpoint(), NULL, and session.

Referenced by t38_automatic_reject(), and t38_interpret_parameters().

◆ 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 2862 of file res_pjsip_session.c.

2863{
2865}
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.

References ast_sip_session_send_request_with_cb(), NULL, and session.

Referenced by aoc_send_as_xml(), 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().

◆ 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 2838 of file res_pjsip_session.c.

2840{
2841 pjsip_inv_session *inv_session = session->inv_session;
2842
2843 /* For every request except BYE we disallow sending of the message when
2844 * the session has been disconnected. A BYE request is special though
2845 * because it can be sent again after the session is disconnected except
2846 * with credentials.
2847 */
2848 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED &&
2849 tdata->msg->line.req.method.id != PJSIP_BYE_METHOD) {
2850 return;
2851 }
2852
2853 ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id,
2854 MOD_DATA_ON_RESPONSE, on_response);
2855
2857 pjsip_inv_send_msg(session->inv_session, tdata);
2858
2859 return;
2860}
#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:2980
#define MOD_DATA_ON_RESPONSE
static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)

References ast_sip_mod_data_set, handle_outgoing_request(), MOD_DATA_ON_RESPONSE, session, and session_module.

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

◆ 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 2588 of file res_pjsip_session.c.

2589{
2590 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
2591 RAII_VAR(struct ast_sip_session *, dlg_session, dlg ? ast_sip_dialog_get_session(dlg) : NULL, ao2_cleanup);
2592 if (!dlg_session) {
2593 /* If the dialog has a session, handle_outgoing_response will be called
2594 from session_on_tx_response. If it does not, call it from here. */
2596 }
2597 pjsip_inv_send_msg(session->inv_session, tdata);
2598 return;
2599}
struct ast_sip_session * ast_sip_dialog_get_session(pjsip_dialog *dlg)
Retrieves a session from a dialog.
static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)

References ao2_cleanup, ast_sip_dialog_get_session(), handle_outgoing_response(), NULL, RAII_VAR, and session.

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

◆ 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.

Definition at line 3175 of file res_pjsip_session.c.

3176{
3177 struct ast_sip_session_suspender *suspender;
3178 int res;
3179
3180 ast_assert(session->suspended == NULL);
3181
3182 if (ast_taskprocessor_is_task(session->serializer)) {
3183 /* I am the session's serializer thread so I cannot suspend. */
3184 return;
3185 }
3186
3187 if (ast_taskprocessor_is_suspended(session->serializer)) {
3188 /* The serializer already suspended. */
3189 return;
3190 }
3191
3192 suspender = ao2_alloc(sizeof(*suspender), sip_session_suspender_dtor);
3193 if (!suspender) {
3194 /* We will just have to hope that the system does not deadlock */
3195 return;
3196 }
3197 ast_cond_init(&suspender->cond_suspended, NULL);
3198 ast_cond_init(&suspender->cond_complete, NULL);
3199
3200 ao2_ref(suspender, +1);
3201 res = ast_sip_push_task(session->serializer, sip_session_suspend_task, suspender);
3202 if (res) {
3203 /* We will just have to hope that the system does not deadlock */
3204 ao2_ref(suspender, -2);
3205 return;
3206 }
3207
3208 session->suspended = suspender;
3209
3210 /* Wait for the serializer to get suspended. */
3211 ao2_lock(suspender);
3212 while (!suspender->suspended) {
3213 ast_cond_wait(&suspender->cond_suspended, ao2_object_get_lockaddr(suspender));
3214 }
3215 ao2_unlock(suspender);
3216
3218}
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
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:2099
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define ast_cond_init(cond, attr)
Definition: lock.h:201
static int sip_session_suspend_task(void *data)
static void sip_session_suspender_dtor(void *vdoomed)
struct controlling the suspension of the session's serializer.
int ast_taskprocessor_is_suspended(struct ast_taskprocessor *tps)
Get the task processor suspend status.
int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
Am I the given taskprocessor's current task.
int ast_taskprocessor_suspend(struct ast_taskprocessor *tps)
Indicate the taskprocessor is suspended.

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, session, sip_session_suspend_task(), sip_session_suspender_dtor(), and ast_sip_session_suspender::suspended.

Referenced by chan_pjsip_indicate().

◆ 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 3471 of file res_pjsip_session.c.

3472{
3473 pj_status_t status;
3474 pjsip_tx_data *packet = NULL;
3475 SCOPE_ENTER(1, "%s Response %d\n", ast_sip_session_get_name(session), response);
3476
3477 if (session->defer_terminate) {
3478 session->terminate_while_deferred = 1;
3479 SCOPE_EXIT_RTN("Deferred\n");
3480 }
3481
3482 if (!response) {
3483 response = 603;
3484 }
3485
3486 /* The media sessions need to exist for the lifetime of the underlying channel
3487 * to ensure that anything (such as bridge_native_rtp) has access to them as
3488 * appropriate. Since ast_sip_session_terminate is called by chan_pjsip and other
3489 * places when the session is to be terminated we terminate any existing
3490 * media sessions here.
3491 */
3492 ast_sip_session_media_stats_save(session, session->active_media_state);
3493 SWAP(session->active_media_state, session->pending_media_state);
3494 ast_sip_session_media_state_reset(session->pending_media_state);
3495
3496 switch (session->inv_session->state) {
3497 case PJSIP_INV_STATE_NULL:
3498 if (!session->inv_session->invite_tsx) {
3499 /*
3500 * Normally, it's pjproject's transaction cleanup that ultimately causes the
3501 * final session reference to be released but if both STATE and invite_tsx are NULL,
3502 * we never created a transaction in the first place. In this case, we need to
3503 * do the cleanup ourselves.
3504 */
3505 /* Transfer the inv_session session reference to the session_end_task */
3506 session->inv_session->mod_data[session_module.id] = NULL;
3507 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3509 /*
3510 * session_end_completion will cleanup the final session reference unless
3511 * ast_sip_session_terminate's caller is holding one.
3512 */
3514 } else {
3515 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3516 }
3517 break;
3518 case PJSIP_INV_STATE_CONFIRMED:
3519 if (session->inv_session->invite_tsx) {
3520 ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",
3522 /* If this is delayed the only thing that will happen is a BYE request so we don't
3523 * actually need to store the response code for when it happens.
3524 */
3526 break;
3527 }
3528 /* Fall through */
3529 default:
3530 status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet);
3531 if (status == PJ_SUCCESS && packet) {
3532 struct ast_sip_session_delayed_request *delay;
3533
3534 /* Flush any delayed requests so they cannot overlap this transaction. */
3535 while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
3536 delayed_request_free(delay);
3537 }
3538
3539 if (packet->msg->type == PJSIP_RESPONSE_MSG) {
3541 } else {
3543 }
3544 }
3545 break;
3546 }
3548}
jack_status_t status
Definition: app_jack.c:146
#define SCOPE_EXIT_RTN(...)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
static int session_end_completion(void *vsession)
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP 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 void delayed_request_free(struct ast_sip_session_delayed_request *delay)
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
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.
struct ast_sip_session_delayed_request * next
#define SWAP(a, b)
Definition: utils.h:235

References 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(), delay_request(), DELAYED_METHOD_BYE, delayed_request_free(), ast_sip_session_delayed_request::next, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end(), session_end_completion(), session_module, status, and SWAP.

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

◆ 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 208 of file res_pjsip_session.c.

209{
211}
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
static int remove_handler(void *obj, void *arg, void *data, int flags)

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

Referenced by unload_module().

◆ 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.

Definition at line 3220 of file res_pjsip_session.c.

3221{
3222 struct ast_sip_session_suspender *suspender = session->suspended;
3223
3224 if (!suspender) {
3225 /* Nothing to do */
3226 return;
3227 }
3228 session->suspended = NULL;
3229
3230 /* Signal that the serializer task suspension is now complete. */
3231 ao2_lock(suspender);
3232 suspender->complete = 1;
3233 ast_cond_signal(&suspender->cond_complete);
3234 ao2_unlock(suspender);
3235
3236 ao2_ref(suspender, -1);
3237
3239}
#define ast_cond_signal(cond)
Definition: lock.h:203
int ast_taskprocessor_unsuspend(struct ast_taskprocessor *tps)
Indicate the taskprocessor is unsuspended.

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, and session.

Referenced by chan_pjsip_indicate().

◆ 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 3969 of file res_pjsip_session.c.

3970{
3971 pjsip_msg_body *body = rdata->msg_info.msg->body;
3972 pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3973
3974 if (body && ctype_hdr &&
3977 pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3978 while (part != NULL) {
3980 return 1;
3981 }
3982 part = pjsip_multipart_get_next_part(body, part);
3983 }
3984 }
3985 return 0;
3986}
#define SENTINEL
Definition: compiler.h:87
int ast_sip_is_media_type_in(pjsip_media_type *a,...) attribute_sentinel
Check if a media type is in a list of others.
Definition: res_pjsip.c:2228
pjsip_media_type pjsip_media_type_multipart_mixed
Definition: res_pjsip.c:3918
pjsip_media_type pjsip_media_type_multipart_alternative
Definition: res_pjsip.c:3917
static int check_content_disposition_in_multipart(pjsip_multipart_part *part)

References ast_sip_is_media_type_in(), check_content_disposition_in_multipart(), NULL, pjsip_media_type_multipart_alternative, pjsip_media_type_multipart_mixed, and SENTINEL.

Referenced by new_invite().

◆ check_content_disposition_in_multipart()

static int check_content_disposition_in_multipart ( pjsip_multipart_part *  part)
static

Definition at line 3945 of file res_pjsip_session.c.

3946{
3947 pjsip_hdr *hdr = part->hdr.next;
3948 static const pj_str_t str_handling_required = {"handling=required", 16};
3949
3950 while (hdr != &part->hdr) {
3951 if (hdr->type == PJSIP_H_OTHER) {
3952 pjsip_generic_string_hdr *generic_hdr = (pjsip_generic_string_hdr*)hdr;
3953
3954 if (!pj_stricmp2(&hdr->name, "Content-Disposition") &&
3955 pj_stristr(&generic_hdr->hvalue, &str_handling_required) &&
3956 !check_sdp_content_type_supported(&part->body->content_type)) {
3957 return 1;
3958 }
3959 }
3960 hdr = hdr->next;
3961 }
3962
3963 return 0;
3964}
static int check_sdp_content_type_supported(pjsip_media_type *content_type)

References check_sdp_content_type_supported().

Referenced by check_content_disposition().

◆ check_delayed_requests()

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

Definition at line 1593 of file res_pjsip_session.c.

1595{
1596 ao2_ref(session, +1);
1597 if (ast_sip_push_task(session->serializer, cb, session)) {
1598 ao2_ref(session, -1);
1599 }
1600}

References ao2_ref, ast_sip_push_task(), and session.

Referenced by session_inv_on_tsx_state_changed().

◆ check_request_status()

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

Definition at line 4654 of file res_pjsip_session.c.

4655{
4656 struct ast_sip_session *session = inv->mod_data[session_module.id];
4657 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4658
4659 if (tsx->status_code != 503 && tsx->status_code != 408) {
4660 return 0;
4661 }
4662
4663 if (!ast_sip_failover_request(tsx->last_tx)) {
4664 return 0;
4665 }
4666
4667 pjsip_inv_uac_restart(inv, PJ_FALSE);
4668 /*
4669 * Bump the ref since it will be on a new transaction and
4670 * we don't want it to go away along with the old transaction.
4671 */
4672 pjsip_tx_data_add_ref(tsx->last_tx);
4674 return 1;
4675}
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:1816

References ast_sip_failover_request(), ast_sip_session_send_request(), session, and session_module.

Referenced by session_inv_on_state_changed().

◆ check_sdp_content_type_supported()

static int check_sdp_content_type_supported ( pjsip_media_type *  content_type)
static

Definition at line 3933 of file res_pjsip_session.c.

3934{
3935 pjsip_media_type app_sdp;
3936 pjsip_media_type_init2(&app_sdp, "application", "sdp");
3937
3938 if (!pjsip_media_type_cmp(content_type, &app_sdp, 0)) {
3939 return 1;
3940 }
3941
3942 return 0;
3943}

Referenced by check_content_disposition_in_multipart().

◆ 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,
const unsigned int  ignore_active_stream_topology 
)
static

Definition at line 5176 of file res_pjsip_session.c.

5177{
5178 static const pj_str_t STR_IN = { "IN", 2 };
5179 static const pj_str_t STR_IP4 = { "IP4", 3 };
5180 static const pj_str_t STR_IP6 = { "IP6", 3 };
5181 pjmedia_sdp_session *local;
5182 int i;
5183 int stream;
5185
5186 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
5187 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Failed to create session SDP. Session has been already disconnected\n",
5189 }
5190
5191 if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
5192 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Pool allocation failure\n", ast_sip_session_get_name(session));
5193 }
5194
5195 if (!offer) {
5196 local->origin.version = local->origin.id = (pj_uint32_t)(ast_random());
5197 } else {
5198 local->origin.version = offer->origin.version + 1;
5199 local->origin.id = offer->origin.id;
5200 }
5201
5202 pj_strdup2(inv->pool_prov, &local->origin.user, session->endpoint->media.sdpowner);
5203 pj_strdup2(inv->pool_prov, &local->name, session->endpoint->media.sdpsession);
5204
5205 if (!session->pending_media_state->topology || !ast_stream_topology_get_count(session->pending_media_state->topology)) {
5206 /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication
5207 * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation
5208 * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the endpoint.
5209 * We will also do this if wanted by the ignore_active_stream_topology flag.
5210 */
5211 ast_trace(-1, "no information about stream topology received\n");
5212 ast_stream_topology_free(session->pending_media_state->topology);
5213 if (session->active_media_state->topology && !ignore_active_stream_topology) {
5214 ast_trace(-1, "using existing topology\n");
5215 session->pending_media_state->topology = ast_stream_topology_clone(session->active_media_state->topology);
5216 } else {
5217 if (ignore_active_stream_topology) {
5218 ast_trace(-1, "fall back to endpoint configuration - ignore active stream topolog\n");
5219 } else {
5220 ast_trace(-1, "fall back to endpoint configuration\n");
5221 }
5222 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
5223 }
5224 if (!session->pending_media_state->topology) {
5225 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: No pending media state topology\n", ast_sip_session_get_name(session));
5226 }
5227 }
5228
5229 ast_trace(-1, "%s: Processing streams\n", ast_sip_session_get_name(session));
5230
5231 for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) {
5232 struct ast_sip_session_media *session_media;
5233 struct ast_stream *stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
5234 unsigned int streams = local->media_count;
5235 SCOPE_ENTER(4, "%s: Processing stream %s\n", ast_sip_session_get_name(session),
5236 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5237
5238 /* This code does not enforce any maximum stream count limitations as that is done on either
5239 * the handling of an incoming SDP offer or on the handling of a session refresh.
5240 */
5241
5242 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i);
5243 if (!session_media) {
5244 local = NULL;
5245 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc/add session media for stream %s\n",
5247 }
5248
5249 if (add_sdp_streams(session_media, session, local, offer, stream)) {
5250 local = NULL;
5251 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't add sdp streams for stream %s\n",
5253 }
5254
5255 /* If a stream was actually added then add any additional details */
5256 if (streams != local->media_count) {
5257 pjmedia_sdp_media *media = local->media[streams];
5258 pj_str_t stmp;
5259 pjmedia_sdp_attr *attr;
5260
5261 /* Add the media identifier if present */
5262 if (!ast_strlen_zero(session_media->mid)) {
5263 attr = pjmedia_sdp_attr_create(inv->pool_prov, "mid", pj_cstr(&stmp, session_media->mid));
5264 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
5265 }
5266
5267 ast_trace(-1, "%s: Stream %s added%s%s\n", ast_sip_session_get_name(session),
5268 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5269 S_COR(!ast_strlen_zero(session_media->mid), " with mid ", ""), S_OR(session_media->mid, ""));
5270
5271 }
5272
5273 /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */
5274 if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) {
5275 SCOPE_EXIT_EXPR(break, "%s: Stream %s exceeded max pjmedia count of %d\n",
5277 PJMEDIA_MAX_SDP_MEDIA);
5278 }
5279
5280 SCOPE_EXIT("%s: Done with %s\n", ast_sip_session_get_name(session),
5281 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5282
5283 }
5284
5285 /* Add any bundle groups that are present on the media state */
5286 ast_trace(-1, "%s: Adding bundle groups (if available)\n", ast_sip_session_get_name(session));
5287 if (add_bundle_groups(session, inv->pool_prov, local)) {
5288 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't add bundle groups\n", ast_sip_session_get_name(session));
5289 }
5290
5291 /* Use the connection details of an available media if possible for SDP level */
5292 ast_trace(-1, "%s: Copying connection details\n", ast_sip_session_get_name(session));
5293
5294 for (stream = 0; stream < local->media_count; stream++) {
5295 SCOPE_ENTER(4, "%s: Processing media %d\n", ast_sip_session_get_name(session), stream);
5296 if (!local->media[stream]->conn) {
5297 SCOPE_EXIT_EXPR(continue, "%s: Media %d has no connection info\n", ast_sip_session_get_name(session), stream);
5298 }
5299
5300 if (local->conn) {
5301 if (!pj_strcmp(&local->conn->net_type, &local->media[stream]->conn->net_type) &&
5302 !pj_strcmp(&local->conn->addr_type, &local->media[stream]->conn->addr_type) &&
5303 !pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) {
5304 local->media[stream]->conn = NULL;
5305 }
5306 SCOPE_EXIT_EXPR(continue, "%s: Media %d has good existing connection info\n", ast_sip_session_get_name(session), stream);
5307 }
5308
5309 /* This stream's connection info will serve as the connection details for SDP level */
5310 local->conn = local->media[stream]->conn;
5311 local->media[stream]->conn = NULL;
5312
5313 SCOPE_EXIT_EXPR(continue, "%s: Media %d reset\n", ast_sip_session_get_name(session), stream);
5314 }
5315
5316 /* If no SDP level connection details are present then create some */
5317 if (!local->conn) {
5318 ast_trace(-1, "%s: Creating connection details\n", ast_sip_session_get_name(session));
5319
5320 local->conn = pj_pool_zalloc(inv->pool_prov, sizeof(struct pjmedia_sdp_conn));
5321 local->conn->net_type = STR_IN;
5322 local->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
5323
5324 if (!ast_strlen_zero(session->endpoint->media.address)) {
5325 pj_strdup2(inv->pool_prov, &local->conn->addr, session->endpoint->media.address);
5326 } else {
5327 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()));
5328 }
5329 }
5330
5331 pj_strassign(&local->origin.net_type, &local->conn->net_type);
5332 pj_strassign(&local->origin.addr_type, &local->conn->addr_type);
5333 pj_strassign(&local->origin.addr, &local->conn->addr);
5334
5335end:
5337}
char * end
Definition: eagi_proxy.c:73
#define SCOPE_EXIT_LOG_EXPR(__expr, __log_level,...)
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
#define SCOPE_EXIT_EXPR(__expr,...)
#define SCOPE_EXIT(...)
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
Definition: res_pjsip.c:2493
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 int add_bundle_groups(struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer)
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.
#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:87
long int ast_random(void)
Definition: utils.c:2312

References add_bundle_groups(), add_sdp_streams(), 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, LOG_ERROR, ast_sip_session_media::mid, NULL, S_COR, S_OR, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG_EXPR, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, and session.

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().

◆ datastore_cmp()

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

Definition at line 2908 of file res_pjsip_session.c.

2909{
2910 const struct ast_datastore *datastore1 = obj;
2911 const struct ast_datastore *datastore2 = arg;
2912 const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
2913
2914 ast_assert(datastore1->uid != NULL);
2915 ast_assert(uid2 != NULL);
2916
2917 return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
2918}
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028

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

Referenced by ast_sip_session_alloc().

◆ datastore_hash()

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

Definition at line 2898 of file res_pjsip_session.c.

2899{
2900 const struct ast_datastore *datastore = obj;
2901 const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
2902
2903 ast_assert(uid != NULL);
2904
2905 return ast_str_hash(uid);
2906}
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259

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

Referenced by ast_sip_session_alloc().

◆ 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 1602 of file res_pjsip_session.c.

1611{
1616
1617 if (!delay) {
1620 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1621 }
1622
1623 if (method == DELAYED_METHOD_BYE || queue_head) {
1624 /* Send BYE as early as possible */
1625 AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1626 } else {
1627 AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1628 }
1630}
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
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)
ast_sip_session_sdp_creation_cb on_sdp_creation
struct ast_sip_session_media_state * active_media_state
struct ast_sip_session_media_state * pending_media_state
ast_sip_session_response_cb on_response

References ast_sip_session_delayed_request::active_media_state, 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_request::generate_new_sdp, LOG_ERROR, method, ast_sip_session_delayed_request::next, 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 session.

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

◆ delayed_method2str()

static const char * delayed_method2str ( enum delayed_method  method)
static

Definition at line 1321 of file res_pjsip_session.c.

1322{
1323 const char *str = "<unknown>";
1324
1325 switch (method) {
1327 str = "INVITE";
1328 break;
1330 str = "UPDATE";
1331 break;
1332 case DELAYED_METHOD_BYE:
1333 str = "BYE";
1334 break;
1335 }
1336
1337 return str;
1338}
const char * str
Definition: app_jack.c:147

References DELAYED_METHOD_BYE, DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, method, and str.

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

◆ 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

◆ delayed_request_free()

static void delayed_request_free ( struct ast_sip_session_delayed_request delay)
static

◆ does_method_match()

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

Definition at line 4211 of file res_pjsip_session.c.

4212{
4213 pj_str_t method;
4214
4215 if (ast_strlen_zero(supplement_method)) {
4216 return PJ_TRUE;
4217 }
4218
4219 pj_cstr(&method, supplement_method);
4220
4221 return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
4222}
static const pjsip_method message_method
Definition: res_pjsip.c:1275

References ast_strlen_zero(), message_method, and method.

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

◆ fetch_callerid_num()

static int fetch_callerid_num ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
char *  buf,
size_t  len 
)
static

Fetch just the Caller ID number in order of PAI, RPID, From.

Definition at line 3686 of file res_pjsip_session.c.

3687{
3688 int res = -1;
3689 struct ast_party_id id;
3690
3691 ast_party_id_init(&id);
3692 if (!ast_sip_set_id_from_invite(rdata, &id, &session->endpoint->id.self, session->endpoint->id.trust_inbound)) {
3693 ast_copy_string(buf, id.number.str, len);
3694 res = 0;
3695 }
3696 ast_party_id_free(&id);
3697 return res;
3698}
enum queue_result id
Definition: app_queue.c:1638
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition: channel.c:1811
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_sip_set_id_from_invite(struct pjsip_rx_data *rdata, struct ast_party_id *id, struct ast_party_id *default_id, int trust_inbound)
Set the ID from an INVITE.
Definition: res_pjsip.c:2827
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Information needed to identify an endpoint in a call.
Definition: channel.h:338
Number structure.
Definition: app_followme.c:154

References ast_copy_string(), ast_party_id_free(), ast_party_id_init(), ast_sip_set_id_from_invite(), buf, id, len(), and session.

Referenced by get_destination().

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session * generate_session_refresh_sdp ( struct ast_sip_session session)
static

Definition at line 1632 of file res_pjsip_session.c.

1633{
1634 pjsip_inv_session *inv_session = session->inv_session;
1635 const pjmedia_sdp_session *previous_sdp = NULL;
1637
1638 if (inv_session->neg) {
1639 if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
1640 pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
1641 } else {
1642 pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
1643 }
1644 }
1645 SCOPE_EXIT_RTN_VALUE(create_local_sdp(inv_session, session, previous_sdp, 0));
1646}

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

Referenced by sip_session_refresh().

◆ 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 3721 of file res_pjsip_session.c.

3722{
3723 char cid_num[AST_CHANNEL_NAME];
3724 pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
3725 struct ast_features_pickup_config *pickup_cfg;
3726 const char *pickupexten;
3727
3728 if (!ast_sip_is_allowed_uri(ruri)) {
3730 }
3731
3732 ast_copy_pj_str(session->exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(session->exten));
3733 if (ast_strlen_zero(session->exten)) {
3734 /* Some SIP devices send an empty extension for PLAR: this should map to s */
3735 ast_debug(1, "RURI contains no user portion: defaulting to extension 's'\n");
3736 ast_copy_string(session->exten, "s", sizeof(session->exten));
3737 }
3738
3739 /*
3740 * We may want to match in the dialplan without any user
3741 * options getting in the way.
3742 */
3744
3745 pickup_cfg = ast_get_chan_features_pickup_config(NULL); /* session->channel doesn't exist yet, using NULL */
3746 if (!pickup_cfg) {
3747 ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",
3749 pickupexten = "";
3750 } else {
3751 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
3752 ao2_ref(pickup_cfg, -1);
3753 }
3754
3755 fetch_callerid_num(session, rdata, cid_num, sizeof(cid_num));
3756
3757 /* If there's an overlap_context override specified, use that; otherwise, just use the endpoint's context */
3758
3759 if (!strcmp(session->exten, pickupexten) ||
3760 ast_exists_extension(NULL, S_OR(session->endpoint->overlap_context, session->endpoint->context), session->exten, 1, S_OR(cid_num, NULL))) {
3761 /*
3762 * Save off the INVITE Request-URI in case it is
3763 * needed: CHANNEL(pjsip,request_uri)
3764 */
3765 session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri);
3766
3768 }
3769
3770 /*
3771 * Check for partial match via overlap dialling (if enabled)
3772 */
3773 if (session->endpoint->allow_overlap && (
3774 !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
3775 ast_canmatch_extension(NULL, S_OR(session->endpoint->overlap_context, session->endpoint->context), session->exten, 1, S_OR(cid_num, NULL)))) {
3776 /* Overlap partial match */
3778 }
3779
3781}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_CHANNEL_NAME
Definition: channel.h:171
struct ast_features_pickup_config * ast_get_chan_features_pickup_config(struct ast_channel *chan)
Get the pickup configuration options for a channel.
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:4175
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:4190
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
Definition: res_pjsip.c:3477
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition: res_pjsip.c:3472
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3351
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:2201
static int fetch_callerid_num(struct ast_sip_session *session, pjsip_rx_data *rdata, char *buf, size_t len)
Fetch just the Caller ID number in order of PAI, RPID, From.
Configuration relating to call pickup.

References ao2_ref, ast_canmatch_extension(), AST_CHANNEL_NAME, ast_copy_pj_str(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_get_chan_features_pickup_config(), ast_log, ast_sip_is_allowed_uri(), ast_sip_pjsip_uri_get_username(), ast_sip_session_get_name(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_strdupa, ast_strlen_zero(), fetch_callerid_num(), LOG_ERROR, NULL, ast_features_pickup_config::pickupexten, S_OR, session, 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().

◆ get_mid_bundle_group()

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

Definition at line 621 of file res_pjsip_session.c.

622{
623 int bundle_group = 0;
624 int index;
625
626 for (index = 0; index < sdp->attr_count; ++index) {
627 pjmedia_sdp_attr *attr = sdp->attr[index];
628 char value[pj_strlen(&attr->value) + 1], *mids = value, *attr_mid;
629
630 if (pj_strcmp2(&attr->name, "group") || pj_strncmp2(&attr->value, "BUNDLE", 6)) {
631 continue;
632 }
633
634 ast_copy_pj_str(value, &attr->value, sizeof(value));
635
636 /* Skip the BUNDLE at the front */
637 mids += 7;
638
639 while ((attr_mid = strsep(&mids, " "))) {
640 if (!strcmp(attr_mid, mid)) {
641 /* The ordering of attributes determines our internal identification of the bundle group based on number,
642 * with -1 being not in a bundle group. Since this is only exposed internally for response purposes it's
643 * actually even fine if things move around.
644 */
645 return bundle_group;
646 }
647 }
648
649 bundle_group++;
650 }
651
652 return -1;
653}
char * strsep(char **str, const char *delims)
int value
Definition: syslog.c:37

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

Referenced by set_mid_and_bundle_group().

◆ 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 4563 of file res_pjsip_session.c.

4565{
4566 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
4568 } else {
4569 handle_incoming_response(session, rdata, response_priority);
4570 }
4571
4572 return 0;
4573}
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)

References handle_incoming_request(), handle_incoming_response(), and session.

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

◆ 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 4677 of file res_pjsip_session.c.

4679{
4680 pjsip_msg *msg;
4681 ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4682 "request" : "response");
4683
4684
4686 msg = rdata->msg_info.msg;
4687 if (msg->type == PJSIP_REQUEST_MSG
4688 && msg->line.req.method.id == PJSIP_ACK_METHOD
4689 && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
4690 pjsip_tx_data *tdata;
4691
4692 /*
4693 * SDP negotiation failed on an incoming call that delayed
4694 * negotiation and then gave us an invalid SDP answer. We
4695 * need to send a BYE to end the call because of the invalid
4696 * SDP answer.
4697 */
4698 ast_debug(1,
4699 "%s: Ending session due to incomplete SDP negotiation. %s\n",
4701 pjsip_rx_data_get_info(rdata));
4702 if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
4703 && tdata) {
4705 }
4706 }
4707}
static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
@ AST_SIP_SESSION_BEFORE_MEDIA

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

Referenced by session_inv_on_state_changed().

◆ handle_incoming_request()

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

Definition at line 4492 of file res_pjsip_session.c.

4493{
4494 struct ast_sip_session_supplement *supplement;
4495 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4496 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));
4497
4498 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4499 if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
4500 if (supplement->incoming_request(session, rdata)) {
4501 break;
4502 }
4503 }
4504 }
4505
4507}
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
A supplement to SIP message processing.
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....

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 session.

Referenced by handle_incoming(), and new_invite().

◆ 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 4543 of file res_pjsip_session.c.

4545{
4546 struct ast_sip_session_supplement *supplement;
4547 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4548 SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4549 status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4550
4551 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4552 if (!(supplement->response_priority & response_priority)) {
4553 continue;
4554 }
4555 if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4556 supplement->incoming_response(session, rdata);
4557 }
4558 }
4559
4561}
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.
enum ast_sip_session_response_priority response_priority

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, session, and status.

Referenced by handle_incoming().

◆ handle_incoming_sdp()

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

Definition at line 773 of file res_pjsip_session.c.

774{
775 int i;
776 int handled = 0;
777 int type_streams[AST_MEDIA_TYPE_END] = {0};
778 SCOPE_ENTER(3, "%s: Media count: %d\n", ast_sip_session_get_name(session), sdp->media_count);
779
780 if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
781 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to handle incoming SDP. Session has been already disconnected\n",
783 }
784
785 /* It is possible for SDP deferral to have already created a pending topology */
786 if (!session->pending_media_state->topology) {
787 session->pending_media_state->topology = ast_stream_topology_alloc();
788 if (!session->pending_media_state->topology) {
789 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc pending topology\n",
791 }
792 }
793
794 for (i = 0; i < sdp->media_count; ++i) {
795 /* See if there are registered handlers for this media stream type */
796 char media[20];
798 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
799 struct ast_sip_session_media *session_media = NULL;
800 int res;
801 enum ast_media_type type;
802 struct ast_stream *stream = NULL;
803 pjmedia_sdp_media *remote_stream = sdp->media[i];
804 SCOPE_ENTER(4, "%s: Processing stream %d\n", ast_sip_session_get_name(session), i);
805
806 /* We need a null-terminated version of the media string */
807 ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
809
810 /* See if we have an already existing stream, which can occur from SDP deferral checking */
811 if (i < ast_stream_topology_get_count(session->pending_media_state->topology)) {
812 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
813 ast_trace(-1, "%s: Using existing pending stream %s\n", ast_sip_session_get_name(session),
814 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
815 }
816 if (!stream) {
817 struct ast_stream *existing_stream = NULL;
818 char *stream_name = NULL, *stream_name_allocated = NULL;
819 const char *stream_label = NULL;
820
821 if (session->active_media_state->topology &&
822 (i < ast_stream_topology_get_count(session->active_media_state->topology))) {
823 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
824 ast_trace(-1, "%s: Found existing active stream %s\n", ast_sip_session_get_name(session),
825 ast_str_tmp(128, ast_stream_to_str(existing_stream, &STR_TMP)));
826
827 if (ast_stream_get_state(existing_stream) != AST_STREAM_STATE_REMOVED) {
828 stream_name = (char *)ast_stream_get_name(existing_stream);
829 stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
830 }
831 }
832
833 if (ast_strlen_zero(stream_name)) {
834 if (ast_asprintf(&stream_name_allocated, "%s-%d", ast_codec_media_type2str(type), i) < 0) {
835 handled = 0;
836 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream name\n",
838
839 }
840 stream_name = stream_name_allocated;
841 ast_trace(-1, "%s: Using %s for new stream name\n", ast_sip_session_get_name(session),
842 stream_name);
843 }
844
845 stream = ast_stream_alloc(stream_name, type);
846 ast_free(stream_name_allocated);
847 if (!stream) {
848 handled = 0;
849 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream\n",
851 }
852
853 if (!ast_strlen_zero(stream_label)) {
854 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
855 ast_trace(-1, "%s: Using %s for new stream label\n", ast_sip_session_get_name(session),
856 stream_label);
857
858 }
859
860 if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
861 ast_stream_free(stream);
862 handled = 0;
863 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't set stream in topology\n",
865 }
866
867 /* For backwards compatibility with the core the default audio stream is always sendrecv */
868 if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
869 if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
870 /* Stream state reflects our state of a stream, so in the case of
871 * sendonly and recvonly we store the opposite since that is what ours
872 * is.
873 */
875 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
877 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
879 } else {
881 }
882 } else {
884 }
885 ast_trace(-1, "%s: Using new stream %s\n", ast_sip_session_get_name(session),
886 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
887 }
888
889 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
890 if (!session_media) {
891 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc session media\n",
893 }
894
895 /* If this stream is already declined mark it as such, or mark it as such if we've reached the limit */
896 if (!remote_stream->desc.port || is_stream_limitation_reached(type, session->endpoint, type_streams)) {
897 remove_stream_from_bundle(session_media, stream);
898 SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s'\n",
900 }
901
902 set_mid_and_bundle_group(session, session_media, sdp, remote_stream);
903 set_remote_mslabel_and_stream_group(session, session_media, sdp, remote_stream, stream);
904
905 if (session_media->handler) {
906 handler = session_media->handler;
907 ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
909 session_media->handler->id);
910 res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
911 if (res < 0) {
912 /* Catastrophic failure. Abort! */
913 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
915 } else if (res == 0) {
916 remove_stream_from_bundle(session_media, stream);
917 SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s\n",
919 } else if (res > 0) {
920 handled = 1;
921 ++type_streams[type];
922 /* Handled by this handler. Move to the next stream */
923 SCOPE_EXIT_EXPR(continue, "%s: Media stream %s handled by %s\n",
925 session_media->handler->id);
926 }
927 }
928
929 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
930 if (!handler_list) {
931 SCOPE_EXIT_EXPR(continue, "%s: Media stream %s has no registered handlers\n",
933 }
934 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
935 if (handler == session_media->handler) {
936 continue;
937 }
938 ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
940 handler->id);
941
942 res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
943 if (res < 0) {
944 /* Catastrophic failure. Abort! */
945 handled = 0;
946 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
948 } else if (res == 0) {
949 remove_stream_from_bundle(session_media, stream);
950 ast_trace(-1, "%s: Declining incoming SDP media stream %s\n",
952 continue;
953 } else if (res > 0) {
954 session_media_set_handler(session_media, handler);
955 handled = 1;
956 ++type_streams[type];
957 ast_trace(-1, "%s: Media stream %s handled by %s\n",
959 session_media->handler->id);
960 break;
961 }
962 }
963
964 SCOPE_EXIT("%s: Done with stream %s\n", ast_sip_session_get_name(session),
965 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
966 }
967
968end:
969 SCOPE_EXIT_RTN_VALUE(handled ? 0 : -1, "%s: Handled? %s\n", ast_sip_session_get_name(session),
970 handled ? "yes" : "no");
971}
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:364
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)
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 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 void remove_stream_from_bundle(struct ast_sip_session_media *session_media, struct ast_stream *stream)
static int is_stream_limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
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
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition: stream.c:423
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
@ AST_STREAM_STATE_RECVONLY
Set when the stream is receiving media only.
Definition: stream.h:90
@ AST_STREAM_STATE_INACTIVE
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
@ AST_STREAM_STATE_SENDRECV
Set when the stream is sending and receiving media.
Definition: stream.h:82
@ AST_STREAM_STATE_SENDONLY
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

References 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_media::handler, handler(), ast_sip_session_sdp_handler::id, is_stream_limitation_reached(), LOG_ERROR, NULL, OBJ_KEY, 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, sdp_handlers, session, session_media_set_handler(), set_mid_and_bundle_group(), set_remote_mslabel_and_stream_group(), and type.

Referenced by new_invite(), and session_inv_on_rx_offer().

◆ 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 1072 of file res_pjsip_session.c.

1073{
1074 int i;
1075 struct ast_stream_topology *topology;
1076 unsigned int changed = 0; /* 0 = unchanged, 1 = new source, 2 = new topology */
1078
1079 if (!session->pending_media_state->topology) {
1080 if (session->active_media_state->topology) {
1081 /*
1082 * This happens when we have negotiated media after receiving a 183,
1083 * and we're now receiving a 200 with a new SDP. In this case, there
1084 * is active_media_state, but the pending_media_state has been reset.
1085 */
1086 struct ast_sip_session_media_state *active_media_state_clone;
1087
1088 active_media_state_clone =
1089 ast_sip_session_media_state_clone(session->active_media_state);
1090 if (!active_media_state_clone) {
1091 ast_log(LOG_WARNING, "%s: Unable to clone active media state\n",
1093 return -1;
1094 }
1095
1096 ast_sip_session_media_state_free(session->pending_media_state);
1097 session->pending_media_state = active_media_state_clone;
1098 } else {
1099 ast_log(LOG_WARNING, "%s: No pending or active media state\n",
1101 return -1;
1102 }
1103 }
1104
1105 /* If we're handling negotiated streams, then we should already have set
1106 * up session media instances (and Asterisk streams) that correspond to
1107 * the local SDP, and there should be the same number of session medias
1108 * and streams as there are local SDP streams
1109 */
1110 if (ast_stream_topology_get_count(session->pending_media_state->topology) != local->media_count
1111 || AST_VECTOR_SIZE(&session->pending_media_state->sessions) != local->media_count) {
1112 ast_log(LOG_WARNING, "%s: Local SDP contains %d media streams while we expected it to contain %u\n",
1114 ast_stream_topology_get_count(session->pending_media_state->topology), local->media_count);
1115 SCOPE_EXIT_RTN_VALUE(-1, "Media stream count mismatch\n");
1116 }
1117
1118 AST_VECTOR_RESET(&session->pending_media_state->read_callbacks, AST_VECTOR_ELEM_CLEANUP_NOOP);
1119
1120 for (i = 0; i < local->media_count; ++i) {
1121 struct ast_sip_session_media *session_media;
1122 struct ast_stream *stream;
1123
1124 if (!remote->media[i]) {
1125 continue;
1126 }
1127
1128 session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i);
1129 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
1130
1131 /* Make sure that this stream is in the correct state. If we need to change
1132 * the state to REMOVED, then our work here is done, so go ahead and move on
1133 * to the next stream.
1134 */
1135 if (!remote->media[i]->desc.port) {
1137 continue;
1138 }
1139
1140 /* If the stream state is REMOVED, nothing needs to be done, so move on to the
1141 * next stream. This can occur if an internal thing has requested it to be
1142 * removed, or if we remove it as a result of the stream limit being reached.
1143 */
1145 /*
1146 * Defer removing the handler until we are ready to activate
1147 * the new topology. The channel's thread may still be using
1148 * the stream and we could crash before we are ready.
1149 */
1150 continue;
1151 }
1152
1153 if (handle_negotiated_sdp_session_media(session_media, session, local, remote, i, stream)) {
1154 SCOPE_EXIT_RTN_VALUE(-1, "Unable to handle negotiated session media\n");
1155 }
1156
1157 changed |= session_media->changed;
1158 session_media->changed = 0;
1159 }
1160
1161 /* Apply the pending media state to the channel and make it active */
1162 ast_channel_lock(session->channel);
1163
1164 /* Now update the stream handler for any declined/removed streams */
1165 for (i = 0; i < local->media_count; ++i) {
1166 struct ast_sip_session_media *session_media;
1167 struct ast_stream *stream;
1168
1169 if (!remote->media[i]) {
1170 continue;
1171 }
1172
1173 session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i);
1174 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
1175
1177 && session_media->handler) {
1178 /*
1179 * This stream is no longer being used and the channel's thread
1180 * is held off because we have the channel lock so release any
1181 * resources the handler may have on it.
1182 */
1183 session_media_set_handler(session_media, NULL);
1184 }
1185 }
1186
1187 /* Update the topology on the channel to match the accepted one */
1188 topology = ast_stream_topology_clone(session->pending_media_state->topology);
1189 if (topology) {
1190 ast_channel_set_stream_topology(session->channel, topology);
1191 /* If this is a remotely done renegotiation that has changed the stream topology notify what is
1192 * currently handling this channel. Note that fax uses its own process, so if we are transitioning
1193 * between audio and fax or vice versa we don't notify.
1194 */
1195 if (pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_FALSE &&
1196 session->active_media_state && session->active_media_state->topology &&
1197 !ast_stream_topology_equal(session->active_media_state->topology, topology) &&
1198 !session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] &&
1199 !session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]) {
1200 changed = 2;
1201 }
1202 }
1203
1204 /* Remove all current file descriptors from the channel */
1205 for (i = 0; i < AST_VECTOR_SIZE(&session->active_media_state->read_callbacks); ++i) {
1207 }
1208
1209 /* Add all the file descriptors from the pending media state */
1210 for (i = 0; i < AST_VECTOR_SIZE(&session->pending_media_state->read_callbacks); ++i) {
1211 struct ast_sip_session_media_read_callback_state *callback_state;
1212
1213 callback_state = AST_VECTOR_GET_ADDR(&session->pending_media_state->read_callbacks, i);
1214 ast_channel_internal_fd_set(session->channel, i + AST_EXTENDED_FDS, callback_state->fd);
1215 }
1216
1217 /* Active and pending flip flop as needed */
1218 ast_sip_session_media_stats_save(session, session->active_media_state);
1219 SWAP(session->active_media_state, session->pending_media_state);
1220 ast_sip_session_media_state_reset(session->pending_media_state);
1221
1222 ast_channel_unlock(session->channel);
1223
1224 if (changed == 1) {
1226
1227 ast_queue_frame(session->channel, &f);
1228 } else if (changed == 2) {
1230 } else {
1232 }
1233
1235}
#define AST_EXTENDED_FDS
Definition: channel.h:195
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.
#define ast_channel_lock(chan)
Definition: channel.h:2922
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1139
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:11008
void ast_channel_internal_fd_clear(struct ast_channel *chan, int which)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
@ AST_MEDIA_TYPE_IMAGE
Definition: codec.h:34
@ AST_FRAME_CONTROL
@ AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED
struct ast_frame ast_null_frame
Definition: main/frame.c:79
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 ast_sip_session_media_state * ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state)
Clone a media state.
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
Data structure associated with a single frame of data.
unsigned int changed
The underlying session has been changed in some fashion.

References 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_ELEM_CLEANUP_NOOP, AST_VECTOR_GET, AST_VECTOR_GET_ADDR, AST_VECTOR_RESET, AST_VECTOR_SIZE, ast_sip_session_media::changed, ast_sip_session_media_read_callback_state::fd, handle_negotiated_sdp_session_media(), ast_sip_session_media::handler, LOG_WARNING, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_media_set_handler(), and SWAP.

Referenced by session_inv_on_media_update().

◆ 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 973 of file res_pjsip_session.c.

976{
977 /* See if there are registered handlers for this media stream type */
978 struct pjmedia_sdp_media *local_stream = local->media[index];
979 char media[20];
981 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
982 int res;
983 SCOPE_ENTER(1, "%s\n", session ? ast_sip_session_get_name(session) : "unknown");
984
985 /* We need a null-terminated version of the media string */
986 ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media));
987
988 /* For backwards compatibility we only reflect the stream state correctly on
989 * the non-default streams and any non-audio streams. This is because the stream
990 * state of the default audio stream is also used for signaling that someone has
991 * placed us on hold. This situation is not handled currently and can result in
992 * the remote side being sorted of placed on hold too.
993 */
994 if (!ast_sip_session_is_pending_stream_default(session, asterisk_stream) || strcmp(media, "audio")) {
995 /* Determine the state of the stream based on our local SDP */
996 if (pjmedia_sdp_media_find_attr2(local_stream, "sendonly", NULL)) {
998 } else if (pjmedia_sdp_media_find_attr2(local_stream, "recvonly", NULL)) {
1000 } else if (pjmedia_sdp_media_find_attr2(local_stream, "inactive", NULL)) {
1002 } else {
1004 }
1005 } else {
1007 }
1008
1009 set_mid_and_bundle_group(session, session_media, remote, remote->media[index]);
1010 set_remote_mslabel_and_stream_group(session, session_media, remote, remote->media[index], asterisk_stream);
1011
1012 handler = session_media->handler;
1013 if (handler) {
1014 ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1016 handler->id);
1017 res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
1018 if (res >= 0) {
1019 ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1021 handler->id);
1022 SCOPE_EXIT_RTN_VALUE(0, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1024 handler->id);
1025 }
1026 SCOPE_EXIT_RTN_VALUE(-1, "%s: Failed to apply negotiated SDP media stream '%s' using %s SDP handler\n",
1028 handler->id);
1029 }
1030
1031 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
1032 if (!handler_list) {
1033 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
1034 return -1;
1035 }
1036 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
1037 if (handler == session_media->handler) {
1038 continue;
1039 }
1040 ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1042 handler->id);
1043 res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
1044 if (res < 0) {
1045 /* Catastrophic failure. Abort! */
1046 SCOPE_EXIT_RTN_VALUE(-1, "%s: Handler '%s' returned %d\n",
1048 }
1049 if (res > 0) {
1050 ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1052 handler->id);
1053 /* Handled by this handler. Move to the next stream */
1054 session_media_set_handler(session_media, handler);
1055 SCOPE_EXIT_RTN_VALUE(0, "%s: Handler '%s' handled this sdp stream\n",
1057 }
1058 }
1059
1060 res = 0;
1061 if (session_media->handler && session_media->handler->stream_stop) {
1062 ast_debug(4, "%s: Stopping SDP media stream '%s' as it is not currently negotiated\n",
1064 session_media->handler->stream_stop(session_media);
1065 }
1066
1067 SCOPE_EXIT_RTN_VALUE(0, "%s: Media type '%s' %s\n",
1069 res ? "not negotiated. Stopped" : "handled");
1070}
void(* stream_stop)(struct ast_sip_session_media *session_media)
Stop a session_media created by this handler but do not destroy resources.

References ao2_cleanup, ao2_find, 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, ast_sip_session_media::handler, handler(), ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, sdp_handlers, session, 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().

◆ handle_new_invite_request()

static void handle_new_invite_request ( pjsip_rx_data *  rdata)
static

Definition at line 4132 of file res_pjsip_session.c.

4133{
4134 RAII_VAR(struct ast_sip_endpoint *, endpoint,
4136 pjsip_inv_session *inv_session = NULL;
4137 struct ast_sip_session *session;
4138 struct new_invite invite;
4139 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4140 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4141 SCOPE_ENTER(1, "Request: %s\n", res ? req_uri : "");
4142
4143 ast_assert(endpoint != NULL);
4144
4145 inv_session = pre_session_setup(rdata, endpoint);
4146 if (!inv_session) {
4147 /* pre_session_setup() returns a response on failure */
4148 SCOPE_EXIT_RTN("Failure in pre session setup\n");
4149 }
4150
4151 /*
4152 * Upon a successful pre_session_setup the associated dialog is returned locked
4153 * and with an added reference. Well actually two references. One added when the
4154 * dialog itself was created, and another added when the pjsip invite session was
4155 * created and the dialog was added to it.
4156 *
4157 * In order to ensure the dialog's, and any of its internal attributes, lifetimes
4158 * we'll hold the lock and maintain the reference throughout the entire new invite
4159 * handling process. See ast_sip_create_dialog_uas_locked for more details but,
4160 * basically we do this to make sure a transport failure does not destroy the dialog
4161 * and/or transaction out from underneath us between pjsip calls. Alternatively, we
4162 * could probably release the lock if we needed to, but then we'd have to re-lock and
4163 * check the dialog and transaction prior to every pjsip call.
4164 *
4165 * That means any off nominal/failure paths in this function must remove the associated
4166 * dialog reference added at dialog creation, and remove the lock. As well the
4167 * referenced pjsip invite session must be "cleaned up", which should also then
4168 * remove its reference to the dialog at that time.
4169 *
4170 * Nominally we'll unlock the dialog, and release the reference when all new invite
4171 * process handling has successfully completed.
4172 */
4173
4174 session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
4175 if (!session) {
4176 /* Dialog's lock and reference are removed in new_invite_initial_answer */
4177 if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4178 /* Terminate the session if it wasn't done in the answer */
4179 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
4180 }
4181 SCOPE_EXIT_RTN("Couldn't create session\n");
4182 }
4183 session->call_direction = AST_SIP_SESSION_INCOMING_CALL;
4184
4185 /*
4186 * The current thread is supposed be the session serializer to prevent
4187 * any initial INVITE retransmissions from trying to setup the same
4188 * call again.
4189 */
4191
4192 invite.session = session;
4193 invite.rdata = rdata;
4194 new_invite(&invite);
4195
4196 /*
4197 * The dialog lock and reference added at dialog creation time must be
4198 * maintained throughout the new invite process. Since we're pretty much
4199 * done at this point with things it's safe to go ahead and remove the lock
4200 * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
4201 *
4202 * Note, any future functionality added that does work using the dialog must
4203 * be done before this.
4204 */
4205 pjsip_dlg_dec_lock(inv_session->dlg);
4206
4207 SCOPE_EXIT("Request: %s Session: %s\n", req_uri, ast_sip_session_get_name(session));
4208 ao2_ref(session, -1);
4209}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define TRACE_ATLEAST(level)
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.
static int new_invite(struct new_invite *invite)
static pjsip_inv_session * pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
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)
@ AST_SIP_SESSION_INCOMING_CALL
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
pjsip_rx_data * rdata
INVITE request itself.

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::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, new_invite::session, session, and TRACE_ATLEAST.

Referenced by session_on_rx_request().

◆ handle_outgoing_request()

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

Definition at line 4575 of file res_pjsip_session.c.

4576{
4577 struct ast_sip_session_supplement *supplement;
4578 struct pjsip_request_line req = tdata->msg->line.req;
4579 SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4580 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4581
4582 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4583
4584 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4585 if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
4586 supplement->outgoing_request(session, tdata);
4587 }
4588 }
4590}
void ast_sip_message_apply_transport(const char *transport_name, pjsip_tx_data *tdata)
Apply the configuration for a transport to an outgoing message.
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.

References AST_LIST_TRAVERSE, ast_sip_message_apply_transport(), ast_sip_session_get_name(), does_method_match(), ast_sip_session_supplement::method, ast_sip_session_supplement::outgoing_request, SCOPE_ENTER, SCOPE_EXIT, and session.

Referenced by ast_sip_session_send_request_with_cb().

◆ handle_outgoing_response()

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

Definition at line 4592 of file res_pjsip_session.c.

4593{
4594 struct ast_sip_session_supplement *supplement;
4595 struct pjsip_status_line status = tdata->msg->line.status;
4596 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
4597 SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4598 (int) pj_strlen(&cseq->method.name),
4599 pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
4600 pj_strbuf(&status.reason));
4601
4602
4603 if (!cseq) {
4604 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4606 }
4607
4608 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4609
4610 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4611 if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
4612 supplement->outgoing_response(session, tdata);
4613 }
4614 }
4615
4617}
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
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.

References AST_LIST_TRAVERSE, ast_sip_message_apply_transport(), ast_sip_session_get_name(), does_method_match(), LOG_ERROR, ast_sip_session_supplement::method, NULL, ast_sip_session_supplement::outgoing_response, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_LOG_RTN, session, and status.

Referenced by ast_sip_session_send_response(), and session_on_tx_response().

◆ handle_session_begin()

static void handle_session_begin ( struct ast_sip_session session)
static

Definition at line 4509 of file res_pjsip_session.c.

4510{
4511 struct ast_sip_session_supplement *iter;
4512
4513 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4514 if (iter->session_begin) {
4515 iter->session_begin(session);
4516 }
4517 }
4518}
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.
struct ast_sip_session_supplement * next

References AST_LIST_TRAVERSE, ast_sip_session_supplement::next, session, and ast_sip_session_supplement::session_begin.

Referenced by ast_sip_session_alloc().

◆ handle_session_destroy()

static void handle_session_destroy ( struct ast_sip_session session)
static

Definition at line 4520 of file res_pjsip_session.c.

4521{
4522 struct ast_sip_session_supplement *iter;
4523
4524 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4525 if (iter->session_destroy) {
4526 iter->session_destroy(session);
4527 }
4528 }
4529}
void(* session_destroy)(struct ast_sip_session *session)
Notification that the session is being destroyed.

References AST_LIST_TRAVERSE, ast_sip_session_supplement::next, session, and ast_sip_session_supplement::session_destroy.

Referenced by session_destructor().

◆ handle_session_end()

static void handle_session_end ( struct ast_sip_session session)
static

Definition at line 4531 of file res_pjsip_session.c.

4532{
4533 struct ast_sip_session_supplement *iter;
4534
4535 /* Session is dead. Notify the supplements. */
4536 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4537 if (iter->session_end) {
4538 iter->session_end(session);
4539 }
4540 }
4541}
void(* session_end)(struct ast_sip_session *session)
Notification that the session has ended.

References AST_LIST_TRAVERSE, ast_sip_session_supplement::next, session, and ast_sip_session_supplement::session_end.

Referenced by session_end().

◆ has_supplement()

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

Definition at line 4224 of file res_pjsip_session.c.

4225{
4226 struct ast_sip_session_supplement *supplement;
4227 struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
4228
4229 if (!session) {
4230 return PJ_FALSE;
4231 }
4232
4233 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4234 if (does_method_match(&method->name, supplement->method)) {
4235 return PJ_TRUE;
4236 }
4237 }
4238 return PJ_FALSE;
4239}

References AST_LIST_TRAVERSE, does_method_match(), ast_sip_session_supplement::method, method, and session.

Referenced by session_on_rx_request().

◆ 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 223 of file res_pjsip_session.c.

225{
226 struct ast_sip_session_media_state *media_state;
227
228 media_state = ast_calloc(1, sizeof(*media_state));
229 if (!media_state) {
230 return NULL;
231 }
232
233 if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) {
234 ast_free(media_state);
235 return NULL;
236 }
237
238 if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) {
239 AST_VECTOR_FREE(&media_state->sessions);
240 ast_free(media_state);
241 return NULL;
242 }
243
244 return media_state;
245}
static struct unistimsession * sessions

References ast_calloc, ast_free, AST_VECTOR_FREE, AST_VECTOR_INIT, NULL, ast_sip_session_media_state::read_callbacks, sessions, and ast_sip_session_media_state::sessions.

Referenced by ast_sip_session_media_state_alloc(), and ast_sip_session_media_state_clone().

◆ invite_collision_timeout()

static int invite_collision_timeout ( void *  vsession)
static

Definition at line 1549 of file res_pjsip_session.c.

1550{
1551 struct ast_sip_session *session = vsession;
1552 int res;
1554
1555 if (session->inv_session->invite_tsx) {
1556 /*
1557 * INVITE transaction still active. Let it send
1558 * the collision re-INVITE when it terminates.
1559 */
1560 ao2_ref(session, -1);
1561 res = 0;
1562 } else {
1564 }
1565
1567}
static int invite_terminated(void *vsession)

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

Referenced by resend_reinvite().

◆ invite_proceeding()

static int invite_proceeding ( void *  vsession)
static

Definition at line 1451 of file res_pjsip_session.c.

1452{
1453 struct ast_sip_session *session = vsession;
1454 struct ast_sip_session_delayed_request *delay;
1455 int found = 0;
1456 int res = 0;
1458
1459 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1460 switch (delay->method) {
1462 break;
1465 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1466 delayed_method2str(delay->method));
1467 res = send_delayed_request(session, delay);
1468 delayed_request_free(delay);
1469 if (!res) {
1470 found = 1;
1471 }
1472 break;
1473 case DELAYED_METHOD_BYE:
1474 /* A BYE is pending so don't bother anymore. */
1475 found = 1;
1476 break;
1477 }
1478 if (found) {
1479 break;
1480 }
1481 }
1483
1484 ao2_ref(session, -1);
1486}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
static const char * delayed_method2str(enum delayed_method method)
static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)

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_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().

◆ invite_terminated()

static int invite_terminated ( void *  vsession)
static

Definition at line 1498 of file res_pjsip_session.c.

1499{
1500 struct ast_sip_session *session = vsession;
1501 struct ast_sip_session_delayed_request *delay;
1502 int found = 0;
1503 int res = 0;
1504 int timer_running;
1506
1507 /* re-INVITE collision timer running? */
1508 timer_running = pj_timer_entry_running(&session->rescheduled_reinvite);
1509
1510 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1511 switch (delay->method) {
1513 if (!timer_running) {
1514 found = 1;
1515 }
1516 break;
1518 case DELAYED_METHOD_BYE:
1519 found = 1;
1520 break;
1521 }
1522 if (found) {
1524 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1525 delayed_method2str(delay->method));
1526 res = send_delayed_request(session, delay);
1527 delayed_request_free(delay);
1528 if (!res) {
1529 break;
1530 }
1531 }
1532 }
1534
1535 ao2_ref(session, -1);
1537}

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_request::method, ast_sip_session_delayed_request::next, 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().

◆ 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 1763 of file res_pjsip_session.c.

1764{
1765 int stream_count = ast_stream_topology_get_count(state->topology);
1766 int session_count = AST_VECTOR_SIZE(&state->sessions);
1767 int i;
1768 int res = 0;
1769 SCOPE_ENTER(3, "%s: Topology: %s\n", session_name,
1770 ast_str_tmp(256, ast_stream_topology_to_str(state->topology, &STR_TMP)));
1771
1772 if (session_count != stream_count) {
1773 SCOPE_EXIT_RTN_VALUE(0, "%s: %d media sessions but %d streams\n", session_name,
1774 session_count, stream_count);
1775 }
1776
1777 for (i = 0; i < stream_count; i++) {
1778 struct ast_sip_session_media *media = NULL;
1779 struct ast_stream *stream = ast_stream_topology_get_stream(state->topology, i);
1780 const char *stream_name = NULL;
1781 int j;
1782 SCOPE_ENTER(4, "%s: Checking stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1783
1784 if (!stream) {
1785 SCOPE_EXIT_EXPR(goto end, "%s: stream %d is null\n", session_name, i);
1786 }
1787 stream_name = ast_stream_get_name(stream);
1788
1789 for (j = 0; j < stream_count; j++) {
1790 struct ast_stream *possible_dup = ast_stream_topology_get_stream(state->topology, j);
1791 if (j == i || !possible_dup) {
1792 continue;
1793 }
1794 if (!STREAM_REMOVED(stream) && ast_strings_equal(stream_name, GET_STREAM_NAME_SAFE(possible_dup))) {
1795 SCOPE_EXIT_EXPR(goto end, "%s: stream %i %s is duplicated to %d\n", session_name,
1796 i, stream_name, j);
1797 }
1798 }
1799
1800 media = AST_VECTOR_GET(&state->sessions, i);
1801 if (!media) {
1802 SCOPE_EXIT_EXPR(continue, "%s: media %d is null\n", session_name, i);
1803 }
1804
1805 for (j = 0; j < session_count; j++) {
1806 struct ast_sip_session_media *possible_dup = AST_VECTOR_GET(&state->sessions, j);
1807 if (j == i || !possible_dup) {
1808 continue;
1809 }
1810 if (!ast_strlen_zero(media->label) && !ast_strlen_zero(possible_dup->label)
1811 && ast_strings_equal(media->label, possible_dup->label)) {
1812 SCOPE_EXIT_EXPR(goto end, "%s: media %d %s is duplicated to %d\n", session_name,
1813 i, media->label, j);
1814 }
1815 }
1816
1817 if (media->stream_num != i) {
1818 SCOPE_EXIT_EXPR(goto end, "%s: media %d has stream_num %d\n", session_name,
1819 i, media->stream_num);
1820 }
1821
1822 if (media->type != ast_stream_get_type(stream)) {
1823 SCOPE_EXIT_EXPR(goto end, "%s: media %d has type %s but stream has type %s\n", stream_name,
1825 }
1826 SCOPE_EXIT("%s: Done with stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1827 }
1828
1829 res = 1;
1830end:
1831 SCOPE_EXIT_RTN_VALUE(res, "%s: %s\n", session_name, res ? "Valid" : "NOT Valid");
1832}
static int session_count
Definition: http.c:109
#define GET_STREAM_NAME_SAFE(_stream)
#define STREAM_REMOVED(_stream)
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238
char label[AST_UUID_STR_LEN]
Track label.

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_name, ast_sip_session_media::stream_num, STREAM_REMOVED, and ast_sip_session_media::type.

Referenced by resolve_refresh_media_states().

◆ 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 601 of file res_pjsip_session.c.

602{
603 switch (type) {
605 return !(type_streams[type] < endpoint->media.max_audio_streams);
607 return !(type_streams[type] < endpoint->media.max_video_streams);
609 /* We don't have an option for image (T.38) streams so cap it to one. */
610 return (type_streams[type] > 0);
613 default:
614 /* We don't want any unknown or "other" streams on our endpoint,
615 * so always just say we've reached the limit
616 */
617 return 1;
618 }
619}
@ AST_MEDIA_TYPE_AUDIO
Definition: codec.h:32
@ AST_MEDIA_TYPE_UNKNOWN
Definition: codec.h:31
@ AST_MEDIA_TYPE_VIDEO
Definition: codec.h:33
@ AST_MEDIA_TYPE_TEXT
Definition: codec.h:35

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().

◆ load_module()

static int load_module ( void  )
static

Definition at line 6217 of file res_pjsip_session.c.

6218{
6219 pjsip_endpoint *endpt;
6220
6223 }
6224 if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
6226 }
6231 if (!sdp_handlers) {
6233 }
6235 pjsip_inv_usage_init(endpt, &inv_callback);
6236 pjsip_100rel_init_module(endpt);
6237 pjsip_timer_init_module(endpt);
6240 }
6243
6245
6247#ifdef TEST_FRAMEWORK
6248 AST_TEST_REGISTER(test_resolve_refresh_media_states);
6249#endif
6251}
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
void pjsip_reason_header_load(void)
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int sdp_handler_list_cmp(void *obj, void *arg, int flags)
static pjsip_module session_reinvite_module
#define SDP_HANDLER_BUCKETS
static pjsip_module outbound_invite_auth_module
static pjsip_inv_callback inv_callback
static struct ast_sip_nat_hook * nat_hook
NAT hook for modifying outgoing messages with SDP.
static int sdp_handler_list_hash(const void *obj, int flags)
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.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2062
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
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:333
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

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, inv_callback, nat_hook, NULL, outbound_invite_auth_module, ast_sip_nat_hook::outgoing_external_message, pjsip_reason_header_load(), SDP_HANDLER_BUCKETS, sdp_handler_list_cmp(), sdp_handler_list_hash(), sdp_handlers, ast_module_info::self, session_module, session_outgoing_nat_hook(), and session_reinvite_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 213 of file res_pjsip_session.c.

215{
216 if (vec_elem->local_ssrc == srch->local_ssrc) {
217 return 1;
218 }
219
220 return 0;
221}
unsigned int local_ssrc
Definition: rtp_engine.h:447

References ast_rtp_instance_stats::local_ssrc.

Referenced by ast_sip_session_media_stats_save().

◆ new_invite()

static int new_invite ( struct new_invite invite)
static

Definition at line 3988 of file res_pjsip_session.c.

3989{
3990 pjsip_tx_data *tdata = NULL;
3991 pjsip_timer_setting timer;
3992 pjsip_rdata_sdp_info *sdp_info;
3993 pjmedia_sdp_session *local = NULL;
3994 char buffer[AST_SOCKADDR_BUFLEN];
3995 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(invite->session));
3996
3997
3998 /* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
3999 * so that we will be notified so we can destroy the session properly
4000 */
4001
4002 if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
4003 ast_trace_log(-1, LOG_ERROR, "%s: Session already DISCONNECTED [reason=%d (%s)]\n",
4005 invite->session->inv_session->cause,
4006 pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
4008 }
4009
4010 switch (get_destination(invite->session, invite->rdata)) {
4012 /* Things worked. Keep going */
4013 break;
4015 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - unsupported uri\n",
4017 invite->rdata->tp_info.transport->type_name,
4018 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4019 invite->session->exten);
4020 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
4021 ast_sip_session_send_response(invite->session, tdata);
4022 } else {
4023 pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
4024 }
4025 goto end;
4027 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - partial match\n",
4029 invite->rdata->tp_info.transport->type_name,
4030 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4031 invite->session->exten);
4032
4033 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) {
4034 ast_sip_session_send_response(invite->session, tdata);
4035 } else {
4036 pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE);
4037 }
4038 goto end;
4040 default:
4041 ast_trace_log(-1, LOG_NOTICE, "%s: Call (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",
4043 invite->rdata->tp_info.transport->type_name,
4044 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4045 invite->session->exten,
4046 invite->session->endpoint->context);
4047
4048 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) {
4049 ast_sip_session_send_response(invite->session, tdata);
4050 } else {
4051 pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
4052 }
4053 goto end;
4054 };
4055
4056 if (check_content_disposition(invite->rdata)) {
4057 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 415, NULL, NULL, &tdata) == PJ_SUCCESS) {
4058 ast_sip_session_send_response(invite->session, tdata);
4059 } else {
4060 pjsip_inv_terminate(invite->session->inv_session, 415, PJ_TRUE);
4061 }
4062 goto end;
4063 }
4064
4065 pjsip_timer_setting_default(&timer);
4066 timer.min_se = invite->session->endpoint->extensions.timer.min_se;
4067 timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires;
4068 pjsip_timer_init_session(invite->session->inv_session, &timer);
4069
4070 /*
4071 * At this point, we've verified what we can that won't take awhile,
4072 * so let's go ahead and send a 100 Trying out to stop any
4073 * retransmissions.
4074 */
4075 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
4076 if (tdata) {
4077 pjsip_inv_send_msg(invite->session->inv_session, tdata);
4078 } else {
4079 pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
4080 }
4081 goto end;
4082 }
4083
4084 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' sending 100 Trying\n",
4086 invite->rdata->tp_info.transport->type_name,
4087 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4088 invite->session->exten);
4089 ast_sip_session_send_response(invite->session, tdata);
4090
4091 sdp_info = pjsip_rdata_get_sdp_info(invite->rdata);
4092 if (sdp_info && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
4093 if (handle_incoming_sdp(invite->session, sdp_info->sdp)) {
4094 tdata = NULL;
4095 if (pjsip_inv_end_session(invite->session->inv_session, 488, NULL, &tdata) == PJ_SUCCESS
4096 && tdata) {
4097 ast_sip_session_send_response(invite->session, tdata);
4098 }
4099 goto end;
4100 }
4101 /* We are creating a local SDP which is an answer to their offer */
4102 local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp, 0);
4103 } else {
4104 /* We are creating a local SDP which is an offer */
4105 local = create_local_sdp(invite->session->inv_session, invite->session, NULL, 0);
4106 }
4107
4108 /* If we were unable to create a local SDP terminate the session early, it won't go anywhere */
4109 if (!local) {
4110 tdata = NULL;
4111 if (pjsip_inv_end_session(invite->session->inv_session, 500, NULL, &tdata) == PJ_SUCCESS
4112 && tdata) {
4113 ast_sip_session_send_response(invite->session, tdata);
4114 }
4115 goto end;
4116 }
4117
4118 pjsip_inv_set_local_sdp(invite->session->inv_session, local);
4119 pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
4120#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
4121 if (!invite->session->endpoint->preferred_codec_only) {
4122 pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE);
4123 }
4124#endif
4125
4126 handle_incoming_request(invite->session, invite->rdata);
4127
4128end:
4130}
#define ast_trace_log(__level, __log_level,...)
#define LOG_NOTICE
#define AST_SOCKADDR_BUFLEN
Definition: netsock2.h:46
static int check_content_disposition(pjsip_rx_data *rdata)
static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
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.
unsigned int preferred_codec_only
Definition: res_pjsip.h:1044
const ast_string_field context
Definition: res_pjsip.h:992
char exten[AST_MAX_EXTENSION]
struct ast_sip_session * session
Session created for the new INVITE.

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().

◆ 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 3805 of file res_pjsip_session.c.

3807{
3808 pjsip_tx_data *tdata = NULL;
3809 int res = 0;
3810
3811 if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3812 if (pjsip_inv_initial_answer(
3813 inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
3814
3815 pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
3816 res = -1;
3817 } else {
3818 pjsip_inv_send_msg(inv_session, tdata);
3819 }
3820 }
3821
3822 if (answer_code >= 300) {
3823 /*
3824 * A session is ending. The dialog has a reference that needs to be
3825 * removed and holds a lock that needs to be unlocked before returning.
3826 */
3827 pjsip_dlg_dec_lock(inv_session->dlg);
3828 }
3829
3830 return res;
3831}

References NULL.

Referenced by handle_new_invite_request(), and pre_session_setup().

◆ outbound_invite_auth()

static pj_bool_t outbound_invite_auth ( pjsip_rx_data *  rdata)
static

Definition at line 3251 of file res_pjsip_session.c.

3252{
3253 pjsip_transaction *tsx;
3254 pjsip_dialog *dlg;
3255 pjsip_inv_session *inv;
3256 pjsip_tx_data *tdata;
3257 struct ast_sip_session *session;
3258
3259 if (rdata->msg_info.msg->line.status.code != 401
3260 && rdata->msg_info.msg->line.status.code != 407) {
3261 /* Doesn't pertain to us. Move on */
3262 return PJ_FALSE;
3263 }
3264
3265 tsx = pjsip_rdata_get_tsx(rdata);
3266 dlg = pjsip_rdata_get_dlg(rdata);
3267 if (!dlg || !tsx) {
3268 return PJ_FALSE;
3269 }
3270
3271 if (tsx->method.id != PJSIP_INVITE_METHOD) {
3272 /* Not an INVITE that needs authentication */
3273 return PJ_FALSE;
3274 }
3275
3276 inv = pjsip_dlg_get_inv_session(dlg);
3277 session = inv->mod_data[session_module.id];
3278
3279 if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {
3280 /*
3281 * We cannot handle reINVITE authentication at this
3282 * time because the reINVITE transaction is still in
3283 * progress.
3284 */
3285 ast_debug(3, "%s: A reINVITE is being challenged\n", ast_sip_session_get_name(session));
3286 return PJ_FALSE;
3287 }
3288 ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));
3289
3290 if (++session->authentication_challenge_count > MAX_RX_CHALLENGES) {
3291 ast_debug(3, "%s: Initial INVITE reached maximum number of auth attempts.\n", ast_sip_session_get_name(session));
3292 return PJ_FALSE;
3293 }
3294
3295 if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata,
3296 tsx->last_tx, &tdata)) {
3297 return PJ_FALSE;
3298 }
3299
3300 /*
3301 * Restart the outgoing initial INVITE transaction to deal
3302 * with authentication.
3303 */
3304 pjsip_inv_uac_restart(inv, PJ_FALSE);
3305
3307 return PJ_TRUE;
3308}
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:214
#define MAX_RX_CHALLENGES
Definition: res_pjsip.h:110

References ast_debug, ast_sip_create_request_with_auth(), ast_sip_session_get_name(), ast_sip_session_send_request(), MAX_RX_CHALLENGES, session, and session_module.

◆ pre_session_setup()

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

Definition at line 3852 of file res_pjsip_session.c.

3853{
3854 pjsip_tx_data *tdata;
3855 pjsip_dialog *dlg;
3856 pjsip_inv_session *inv_session;
3857 unsigned int options = endpoint->extensions.flags;
3858 const pj_str_t STR_100REL = { "100rel", 6};
3859 unsigned int i;
3860 pj_status_t dlg_status = PJ_EUNKNOWN;
3861
3862 /*
3863 * If 100rel is set to "peer_supported" on the endpoint and the peer indicated support for 100rel
3864 * in the Supported header, send 1xx responses reliably by adding PJSIP_INV_REQUIRE_100REL to pjsip_inv_options flags.
3865 */
3866 if (endpoint->rel100 == AST_SIP_100REL_PEER_SUPPORTED && rdata->msg_info.supported != NULL) {
3867 for (i = 0; i < rdata->msg_info.supported->count; ++i) {
3868 if (pj_stricmp(&rdata->msg_info.supported->values[i], &STR_100REL) == 0) {
3869 options |= PJSIP_INV_REQUIRE_100REL;
3870 break;
3871 }
3872 }
3873 }
3874
3875 if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
3876 if (tdata) {
3877 if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
3878 pjsip_tx_data_dec_ref(tdata);
3879 }
3880 } else {
3881 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3882 }
3883 return NULL;
3884 }
3885
3886 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, &dlg_status);
3887 if (!dlg) {
3888 if (dlg_status != PJ_EEXISTS) {
3889 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3890 }
3891 return NULL;
3892 }
3893
3894 /*
3895 * The returned dialog holds a lock and has a reference added. Any paths where the
3896 * dialog invite session is not returned must unlock the dialog and remove its reference.
3897 */
3898
3899 if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
3900 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3901 /*
3902 * The acquired dialog holds a lock, and a reference. Since the dialog is not
3903 * going to be returned here it must first be unlocked and de-referenced. This
3904 * must be done prior to calling dialog termination.
3905 */
3906 pjsip_dlg_dec_lock(dlg);
3907 pjsip_dlg_terminate(dlg);
3908 return NULL;
3909 }
3910
3911#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3912 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3913#endif
3914 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3915 /* Dialog's lock and a reference are removed in new_invite_initial_answer */
3916 new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE);
3917 /* Remove 2nd reference added at inv_session creation */
3918 pjsip_dlg_dec_session(inv_session->dlg, &session_module);
3919 return NULL;
3920 }
3921
3922 return inv_session;
3923}
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:1192
@ AST_SIP_100REL_PEER_SUPPORTED
Definition: res_pjsip.h:535
enum ast_sip_100rel_mode rel100
Definition: res_pjsip.h:1072
static struct test_options options

References AST_SIP_100REL_PEER_SUPPORTED, 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, options, ast_sip_endpoint::rel100, and session_module.

Referenced by handle_new_invite_request().

◆ remove_handler()

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

Definition at line 185 of file res_pjsip_session.c.

186{
187 struct sdp_handler_list *handler_list = obj;
189 struct ast_sip_session_sdp_handler *iter;
190 const char *stream_type = arg;
191
192 AST_LIST_TRAVERSE_SAFE_BEGIN(&handler_list->list, iter, next) {
193 if (!strcmp(iter->id, handler->id)) {
195 ast_debug(1, "Unregistered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
196 }
197 }
199
200 if (AST_LIST_EMPTY(&handler_list->list)) {
201 ast_debug(3, "No more handlers exist for stream type '%s'\n", stream_type);
202 return CMP_MATCH;
203 } else {
204 return CMP_STOP;
205 }
206}
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
struct sdp_handler_list::@465 list

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, and ast_sip_session_sdp_handler::next.

Referenced by ast_sip_session_unregister_sdp_handler().

◆ 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 763 of file res_pjsip_session.c.

765{
767 ast_free(session_media->mid);
768 session_media->mid = NULL;
769 session_media->bundle_group = -1;
770 session_media->bundled = 0;
771}

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().

◆ reschedule_reinvite()

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

Definition at line 4363 of file res_pjsip_session.c.

4364{
4365 pjsip_inv_session *inv = session->inv_session;
4366 pj_time_val tv;
4367 struct ast_sip_session_media_state *pending_media_state = NULL;
4368 struct ast_sip_session_media_state *active_media_state = NULL;
4369 const char *session_name = ast_sip_session_get_name(session);
4370 int use_pending = 0;
4371 int use_active = 0;
4372
4373 SCOPE_ENTER(3, "%s\n", session_name);
4374
4375 /*
4376 * If the two media state topologies are the same this means that the session refresh request
4377 * did not specify a desired topology, so it does not care. If that is the case we don't even
4378 * pass one in here resulting in the current topology being used. It's possible though that
4379 * either one of the topologies could be NULL so we have to test for that before we check for
4380 * equality.
4381 */
4382
4383 /* We only want to clone a media state if its topology is not null */
4384 use_pending = session->pending_media_state->topology != NULL;
4385 use_active = session->active_media_state->topology != NULL;
4386
4387 /*
4388 * If both media states have topologies, we can test for equality. If they're equal we're not going to
4389 * clone either states.
4390 */
4391 if (use_pending && use_active && ast_stream_topology_equal(session->active_media_state->topology, session->pending_media_state->topology)) {
4392 use_pending = 0;
4393 use_active = 0;
4394 }
4395
4396 if (use_pending) {
4397 pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);
4398 if (!pending_media_state) {
4399 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
4400 }
4401 }
4402
4403 if (use_active) {
4404 active_media_state = ast_sip_session_media_state_clone(session->active_media_state);
4405 if (!active_media_state) {
4406 ast_sip_session_media_state_free(pending_media_state);
4407 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
4408 }
4409 }
4410
4411 if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,
4412 active_media_state, 1)) {
4413 ast_sip_session_media_state_free(pending_media_state);
4414 ast_sip_session_media_state_free(active_media_state);
4415 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
4416 }
4417
4418 if (pj_timer_entry_running(&session->rescheduled_reinvite)) {
4419 /* Timer already running. Something weird is going on. */
4420 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
4421 }
4422
4423 tv.sec = 0;
4424 if (inv->role == PJSIP_ROLE_UAC) {
4425 tv.msec = 2100 + ast_random() % 2000;
4426 } else {
4427 tv.msec = ast_random() % 2000;
4428 }
4429 pj_timer_entry_init(&session->rescheduled_reinvite, 0, session, resend_reinvite);
4430
4431 ao2_ref(session, +1);
4432 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
4433 &session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {
4434 ao2_ref(session, -1);
4435 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
4436 }
4437
4439}
static void resend_reinvite(pj_timer_heap_t *timer, pj_timer_entry *entry)

References 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, LOG_ERROR, NULL, resend_reinvite(), SCOPE_ENTER, SCOPE_EXIT_LOG_RTN, SCOPE_EXIT_RTN, and session.

Referenced by session_inv_on_tsx_state_changed().

◆ resend_reinvite()

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

Definition at line 4342 of file res_pjsip_session.c.

4343{
4344 struct ast_sip_session *session = entry->user_data;
4345
4346 ast_debug(3, "%s: re-INVITE collision timer expired.\n",
4348
4349 if (AST_LIST_EMPTY(&session->delayed_requests)) {
4350 /* No delayed request pending, so just return */
4351 ao2_ref(session, -1);
4352 return;
4353 }
4355 /*
4356 * Uh oh. We now have nothing in the foreseeable future
4357 * to trigger sending the delayed requests.
4358 */
4359 ao2_ref(session, -1);
4360 }
4361}
static int invite_collision_timeout(void *vsession)
Definition: search.h:40

References ao2_ref, ast_debug, AST_LIST_EMPTY, ast_sip_push_task(), ast_sip_session_get_name(), invite_collision_timeout(), and session.

Referenced by reschedule_reinvite().

◆ 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 1847 of file res_pjsip_session.c.

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

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().

◆ sdp_handler_list_cmp()

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

Definition at line 138 of file res_pjsip_session.c.

139{
140 struct sdp_handler_list *handler_list1 = obj;
141 struct sdp_handler_list *handler_list2 = arg;
142 const char *stream_type2 = flags & OBJ_KEY ? arg : handler_list2->stream_type;
143
144 return strcmp(handler_list1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
145}

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

Referenced by load_module().

◆ sdp_handler_list_hash()

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

Definition at line 109 of file res_pjsip_session.c.

110{
111 const struct sdp_handler_list *handler_list = obj;
112 const char *stream_type = flags & OBJ_KEY ? obj : handler_list->stream_type;
113
115}

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

Referenced by load_module().

◆ 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 2620 of file res_pjsip_session.c.

2621{
2622 int i;
2623
2624 if (!session->pending_media_state->topology) {
2625 session->pending_media_state->topology = ast_stream_topology_alloc();
2626 if (!session->pending_media_state->topology) {
2627 return -1;
2628 }
2629 }
2630
2631 for (i = 0; i < sdp->media_count; ++i) {
2632 /* See if there are registered handlers for this media stream type */
2633 char media[20];
2635 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
2636 struct ast_stream *existing_stream = NULL;
2637 struct ast_stream *stream;
2638 enum ast_media_type type;
2639 struct ast_sip_session_media *session_media = NULL;
2641 pjmedia_sdp_media *remote_stream = sdp->media[i];
2642
2643 /* We need a null-terminated version of the media string */
2644 ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
2645
2646 if (session->active_media_state->topology &&
2647 (i < ast_stream_topology_get_count(session->active_media_state->topology))) {
2648 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
2649 }
2650
2652 stream = ast_stream_alloc(existing_stream ? ast_stream_get_name(existing_stream) : ast_codec_media_type2str(type), type);
2653 if (!stream) {
2654 return -1;
2655 }
2656
2657 /* As this is only called on an incoming SDP offer before processing it is not possible
2658 * for streams and their media sessions to exist.
2659 */
2660 if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
2661 ast_stream_free(stream);
2662 return -1;
2663 }
2664
2665 if (existing_stream) {
2666 const char *stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
2667
2668 if (!ast_strlen_zero(stream_label)) {
2669 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
2670 }
2671 }
2672
2673 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
2674 if (!session_media) {
2675 return -1;
2676 }
2677
2678 /* For backwards compatibility with the core the default audio stream is always sendrecv */
2679 if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
2680 if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
2681 /* Stream state reflects our state of a stream, so in the case of
2682 * sendonly and recvonly we store the opposite since that is what ours
2683 * is.
2684 */
2686 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
2688 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
2690 } else {
2692 }
2693 } else {
2695 }
2696
2697 if (session_media->handler) {
2698 handler = session_media->handler;
2699 if (handler->defer_incoming_sdp_stream) {
2700 res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2701 sdp->media[i]);
2702 switch (res) {
2704 break;
2706 return 0;
2708 break;
2710 return 1;
2711 }
2712 }
2713 /* Handled by this handler. Move to the next stream */
2714 continue;
2715 }
2716
2717 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
2718 if (!handler_list) {
2719 ast_debug(3, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
2720 continue;
2721 }
2722 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
2723 if (handler == session_media->handler) {
2724 continue;
2725 }
2726 if (!handler->defer_incoming_sdp_stream) {
2727 continue;
2728 }
2729 res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2730 sdp->media[i]);
2731 switch (res) {
2733 continue;
2735 session_media_set_handler(session_media, handler);
2736 return 0;
2738 /* Handled by this handler. */
2739 session_media_set_handler(session_media, handler);
2740 break;
2742 /* Handled by this handler. */
2743 session_media_set_handler(session_media, handler);
2744 return 1;
2745 }
2746 /* Move to the next stream */
2747 break;
2748 }
2749 }
2750 return 0;
2751}
ast_sip_session_sdp_stream_defer
@ AST_SIP_SESSION_SDP_DEFER_NEEDED
@ AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED
@ AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED
@ AST_SIP_SESSION_SDP_DEFER_ERROR

References 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_media::handler, handler(), NULL, OBJ_KEY, RAII_VAR, sdp_handlers, session, session_media_set_handler(), and type.

Referenced by session_reinvite_on_rx_request().

◆ send_delayed_request()

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

Definition at line 1405 of file res_pjsip_session.c.

1406{
1407 int res;
1408 SCOPE_ENTER(3, "%s: sending delayed %s request\n",
1410 delayed_method2str(delay->method));
1411
1412 switch (delay->method) {
1415 delay->on_sdp_creation, delay->on_response,
1417 delay->active_media_state, 1);
1418 /* Ownership of media state transitions to ast_sip_session_refresh */
1419 delay->pending_media_state = NULL;
1420 delay->active_media_state = NULL;
1424 delay->on_sdp_creation, delay->on_response,
1426 delay->active_media_state, 1);
1427 /* Ownership of media state transitions to ast_sip_session_refresh */
1428 delay->pending_media_state = NULL;
1429 delay->active_media_state = NULL;
1431 case DELAYED_METHOD_BYE:
1433 SCOPE_EXIT_RTN_VALUE(0, "%s: Terminating session on delayed BYE\n", ast_sip_session_get_name(session));
1434 }
1435
1436 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",
1438 delayed_method2str(delay->method), delay->method);
1439}
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition: res_pjsip.h:629
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition: res_pjsip.h:627

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, session, and sip_session_refresh().

Referenced by invite_proceeding(), and invite_terminated().

◆ session_datastore_destroy()

static void session_datastore_destroy ( void *  obj)
static

Definition at line 1240 of file res_pjsip_session.c.

1241{
1242 struct ast_datastore *datastore = obj;
1243
1244 /* Using the destroy function (if present) destroy the data */
1245 if (datastore->info->destroy != NULL && datastore->data != NULL) {
1246 datastore->info->destroy(datastore->data);
1247 datastore->data = NULL;
1248 }
1249
1250 ast_free((void *) datastore->uid);
1251 datastore->uid = NULL;
1252}
void(* destroy)(void *data)
Definition: datastore.h:34
void * data
Definition: datastore.h:66

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().

◆ session_destructor()

static void session_destructor ( void *  obj)
static

Definition at line 2920 of file res_pjsip_session.c.

2921{
2922 struct ast_sip_session *session = obj;
2923 struct ast_sip_session_delayed_request *delay;
2924
2925#ifdef TEST_FRAMEWORK
2926 /* We dup the endpoint ID in case the endpoint gets freed out from under us */
2927 const char *endpoint_name = session->endpoint ?
2928 ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>";
2929#endif
2930
2931 ast_debug(3, "%s: Destroying SIP session\n", ast_sip_session_get_name(session));
2932
2933 ast_test_suite_event_notify("SESSION_DESTROYING",
2934 "Endpoint: %s\r\n"
2935 "AOR: %s\r\n"
2936 "Contact: %s"
2937 , endpoint_name
2938 , session->aor ? ast_sorcery_object_get_id(session->aor) : "<none>"
2939 , session->contact ? ast_sorcery_object_get_id(session->contact) : "<none>"
2940 );
2941
2942 /* fire session destroy handler */
2944
2945 /* remove all registered supplements */
2947 AST_LIST_HEAD_DESTROY(&session->supplements);
2948
2949 /* remove all saved media stats */
2950 AST_VECTOR_RESET(&session->media_stats, ast_free);
2951 AST_VECTOR_FREE(&session->media_stats);
2952
2954 ao2_cleanup(session->datastores);
2955 ast_sip_session_media_state_free(session->active_media_state);
2956 ast_sip_session_media_state_free(session->pending_media_state);
2957
2958 while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
2959 delayed_request_free(delay);
2960 }
2962 ao2_cleanup(session->endpoint);
2963 ao2_cleanup(session->aor);
2964 ao2_cleanup(session->contact);
2965 ao2_cleanup(session->direct_media_cap);
2966
2967 ast_dsp_free(session->dsp);
2968
2969 if (session->inv_session) {
2970 struct pjsip_dialog *dlg = session->inv_session->dlg;
2971
2972 /* The INVITE session uses the dialog pool for memory, so we need to
2973 * decrement its reference first before that of the dialog.
2974 */
2975
2976#ifdef HAVE_PJSIP_INV_SESSION_REF
2977 pjsip_inv_dec_ref(session->inv_session);
2978#endif
2979 pjsip_dlg_dec_session(dlg, &session_module);
2980 }
2981
2982 ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name);
2983}
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
static void handle_session_destroy(struct ast_sip_session *session)
void ast_sip_session_remove_supplements(struct ast_sip_session *session)
Remove supplements from a SIP session.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

References ao2_cleanup, 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, delayed_request_free(), handle_session_destroy(), ast_sip_session_delayed_request::next, session, and session_module.

Referenced by ast_sip_session_alloc().

◆ session_end()

static int session_end ( void *  vsession)
static

Definition at line 4619 of file res_pjsip_session.c.

4620{
4621 struct ast_sip_session *session = vsession;
4622
4623 /* Stop the scheduled termination */
4625
4626 /* Session is dead. Notify the supplements. */
4628
4629 return 0;
4630}
static void handle_session_end(struct ast_sip_session *session)

References handle_session_end(), session, and sip_session_defer_termination_stop_timer().

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

◆ session_end_completion()

static int session_end_completion ( void *  vsession)
static

Definition at line 4642 of file res_pjsip_session.c.

4643{
4644 struct ast_sip_session *session = vsession;
4645
4646 ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL);
4647 ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL);
4648
4649 /* Now we can release the ref that was held by session->inv_session */
4651 return 0;
4652}

References ao2_cleanup, ast_sip_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), NULL, and session.

Referenced by ast_sip_session_terminate(), and session_end_if_disconnected().

◆ session_end_if_disconnected()

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

Definition at line 4795 of file res_pjsip_session.c.

4796{
4797 struct ast_sip_session *session;
4798
4799 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
4800 return 0;
4801 }
4802
4803 /*
4804 * We are locking because ast_sip_dialog_get_session() needs
4805 * the dialog locked to get the session by other threads.
4806 */
4807 pjsip_dlg_inc_lock(inv->dlg);
4808 session = inv->mod_data[id];
4809 inv->mod_data[id] = NULL;
4810 pjsip_dlg_dec_lock(inv->dlg);
4811
4812 /*
4813 * Pass the session ref held by session->inv_session to
4814 * session_end_completion().
4815 */
4816 if (session
4818 /* Do it anyway even though this is not the right thread. */
4820 }
4821
4822 return 1;
4823}

References ast_sip_push_task(), id, NULL, session, and session_end_completion().

Referenced by session_inv_on_tsx_state_changed().

◆ 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 5362 of file res_pjsip_session.c.

5363{
5364 struct ast_sip_session *session = inv->mod_data[session_module.id];
5365 const pjmedia_sdp_session *previous_sdp = NULL;
5366 pjmedia_sdp_session *offer;
5367 int i;
5368 unsigned int ignore_active_stream_topology = 0;
5369
5370 /* We allow PJSIP to produce an SDP if no channel is present. This may result
5371 * in an incorrect SDP occurring, but if no channel is present then we are in
5372 * the midst of a BYE and are hanging up. This ensures that all the code to
5373 * produce an SDP doesn't need to worry about a channel being present or not,
5374 * just in case.
5375 */
5377 if (!session->channel) {
5378 SCOPE_EXIT_RTN("%s: No channel\n", ast_sip_session_get_name(session));
5379 }
5380
5381 /* Some devices send a re-INVITE offer with empty SDP. Asterisk by default return
5382 * an answer with the current used codecs, which is not strictly compliant to RFC
5383 * 3261 (SHOULD requirement). So we detect this condition and include all
5384 * configured codecs in the answer if the workaround is activated. The actual
5385 * logic is in the create_local_sdp function. We can't detect here that we have
5386 * no SDP body in the INVITE, as we don't have access to the message.
5387 */
5388 if (inv->invite_tsx && inv->state == PJSIP_INV_STATE_CONFIRMED
5389 && inv->invite_tsx->method.id == PJSIP_INVITE_METHOD) {
5390 ast_trace(-1, "re-INVITE\n");
5391 if (inv->invite_tsx->role == PJSIP_ROLE_UAS
5393 ast_trace(-1, "UAS role, include all codecs in the answer on empty SDP\n");
5394 ignore_active_stream_topology = 1;
5395 }
5396 }
5397
5398 if (inv->neg) {
5399 if (pjmedia_sdp_neg_was_answer_remote(inv->neg)) {
5400 pjmedia_sdp_neg_get_active_remote(inv->neg, &previous_sdp);
5401 } else {
5402 pjmedia_sdp_neg_get_active_local(inv->neg, &previous_sdp);
5403 }
5404 }
5405
5406 if (ignore_active_stream_topology) {
5407 offer = create_local_sdp(inv, session, NULL, 1);
5408 } else {
5409 offer = create_local_sdp(inv, session, previous_sdp, 0);
5410 }
5411 if (!offer) {
5412 SCOPE_EXIT_RTN("%s: create offer failed\n", ast_sip_session_get_name(session));
5413 }
5414
5415 ast_queue_unhold(session->channel);
5416
5417 /*
5418 * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite).
5419 * When hold is initially indicated, we
5420 * - Receive an INVITE with no SDP
5421 * - Send a 200 OK with SDP, indicating sendrecv in the media streams
5422 * - Receive an ACK with SDP, indicating sendonly in the media streams
5423 *
5424 * At this point, the pjmedia negotiator saves the state of the media direction so that
5425 * if we are to send any offers, we'll offer recvonly in the media streams. This is
5426 * problematic if the device is attempting to unhold, though. If the device unholds
5427 * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly.
5428 * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond
5429 * with sendonly or inactive. The result of this is that the stream is not off hold.
5430 *
5431 * Therefore, in this case, when we receive a reinvite while the stream is on hold, we
5432 * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv
5433 * in order to get the stream off hold. If this is actually a different purpose reinvite
5434 * (like a session timer refresh), then the answerer can respond to our sendrecv with
5435 * sendonly, keeping the stream on hold.
5436 */
5437 for (i = 0; i < offer->media_count; ++i) {
5438 pjmedia_sdp_media *m = offer->media[i];
5439 pjmedia_sdp_attr *recvonly;
5440 pjmedia_sdp_attr *inactive;
5441 pjmedia_sdp_attr *sendonly;
5442
5443 recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL);
5444 inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL);
5445 sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL);
5446 if (recvonly || inactive || sendonly) {
5447 pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly;
5448 pjmedia_sdp_attr *sendrecv;
5449
5450 pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove);
5451
5452 sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL);
5453 pjmedia_sdp_media_add_attr(m, sendrecv);
5454 }
5455 }
5456
5457 *p_offer = offer;
5458 SCOPE_EXIT_RTN("%s: offer created\n", ast_sip_session_get_name(session));
5459}
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1216
unsigned int ast_sip_get_all_codecs_on_empty_reinvite(void)
Retrieve the system setting 'all_codecs_on_empty_reinvite'.

References ast_queue_unhold(), ast_sip_get_all_codecs_on_empty_reinvite(), ast_sip_session_get_name(), ast_trace, create_local_sdp(), NULL, SCOPE_ENTER, SCOPE_EXIT_RTN, session, and session_module.

◆ session_inv_on_media_update()

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

Definition at line 5461 of file res_pjsip_session.c.

5462{
5463 struct ast_sip_session *session = inv->mod_data[session_module.id];
5464 const pjmedia_sdp_session *local, *remote;
5466
5467 if (ast_shutdown_final()) {
5468 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5469 }
5470
5471 session = inv->mod_data[session_module.id];
5472 if (!session || !session->channel) {
5473 /*
5474 * If we don't have a session or channel then we really
5475 * don't care about media updates.
5476 * Just ignore
5477 */
5478 SCOPE_EXIT_RTN("%s: No channel or session\n", ast_sip_session_get_name(session));
5479 }
5480
5481 if (session->endpoint) {
5482 int bail = 0;
5483
5484 /*
5485 * If following_fork is set, then this is probably the result of a
5486 * forked INVITE and SDP asnwers coming from the different fork UAS
5487 * destinations. In this case updated_sdp_answer will also be set.
5488 *
5489 * If only updated_sdp_answer is set, then this is the non-forking
5490 * scenario where the same UAS just needs to change something like
5491 * the media port.
5492 */
5493
5494 if (inv->following_fork) {
5495 if (session->endpoint->media.rtp.follow_early_media_fork) {
5496 ast_trace(-1, "%s: Following early media fork with different To tags\n", ast_sip_session_get_name(session));
5497 } else {
5498 ast_trace(-1, "%s: Not following early media fork with different To tags\n", ast_sip_session_get_name(session));
5499 bail = 1;
5500 }
5501 }
5502#ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS
5503 else if (inv->updated_sdp_answer) {
5504 if (session->endpoint->media.rtp.accept_multiple_sdp_answers) {
5505 ast_trace(-1, "%s: Accepting updated SDP with same To tag\n", ast_sip_session_get_name(session));
5506 } else {
5507 ast_trace(-1, "%s: Ignoring updated SDP answer with same To tag\n", ast_sip_session_get_name(session));
5508 bail = 1;
5509 }
5510 }
5511#endif
5512 if (bail) {
5514 }
5515 }
5516
5517 if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||
5518 (pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {
5520 ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
5521 ast_queue_hangup(session->channel);
5522 SCOPE_EXIT_RTN("%s: Couldn't get active or local or remote negotiator. Hanging up\n", ast_sip_session_get_name(session));
5523 }
5524
5525 if (handle_negotiated_sdp(session, local, remote)) {
5526 ast_sip_session_media_state_reset(session->pending_media_state);
5527 SCOPE_EXIT_RTN("%s: handle_negotiated_sdp failed. Resetting pending media state\n", ast_sip_session_get_name(session));
5528 }
5530}
int ast_shutdown_final(void)
Definition: asterisk.c:1867
#define AST_CAUSE_BEARERCAPABILITY_NOTAVAIL
Definition: causes.h:130
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Definition: channel.c:2499
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)

References 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, handle_negotiated_sdp(), SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_module, and status.

◆ session_inv_on_new_session()

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

Definition at line 4790 of file res_pjsip_session.c.

4791{
4792 /* XXX STUB */
4793}

◆ 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 5532 of file res_pjsip_session.c.

5533{
5534 struct ast_sip_session *session;
5535 const pjsip_sip_uri *uri;
5536
5537 if (ast_shutdown_final()) {
5538 return PJSIP_REDIRECT_STOP;
5539 }
5540
5541 session = inv->mod_data[session_module.id];
5542 if (!session || !session->channel) {
5543 return PJSIP_REDIRECT_STOP;
5544 }
5545
5546 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_PJSIP) {
5547 return PJSIP_REDIRECT_ACCEPT;
5548 }
5549
5550 if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
5551 return PJSIP_REDIRECT_STOP;
5552 }
5553
5555
5556 uri = pjsip_uri_get_uri(target);
5557
5558 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
5560
5561 ast_copy_pj_str(exten, &uri->user, sizeof(exten));
5562
5563 /*
5564 * We may want to match in the dialplan without any user
5565 * options getting in the way.
5566 */
5568
5569 ast_channel_call_forward_set(session->channel, exten);
5570 } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
5571 char target_uri[PJSIP_MAX_URL_SIZE];
5572 /* PJSIP/ + endpoint length + / + max URL size */
5573 char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
5574
5575 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
5576 sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
5577 ast_channel_call_forward_set(session->channel, forward);
5578 }
5579
5580 return PJSIP_REDIRECT_STOP;
5581}
#define AST_MAX_EXTENSION
Definition: channel.h:134
@ AST_SIP_REDIRECT_URI_CORE
Definition: res_pjsip.h:660
@ AST_SIP_REDIRECT_URI_PJSIP
Definition: res_pjsip.h:662
@ AST_SIP_REDIRECT_USER
Definition: res_pjsip.h:658
@ AST_SIP_SESSION_BEFORE_REDIRECTING

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::exten, handle_incoming(), session, and session_module.

◆ 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 5339 of file res_pjsip_session.c.

5340{
5341 struct ast_sip_session *session = inv->mod_data[session_module.id];
5342 pjmedia_sdp_session *answer;
5344
5345 if (ast_shutdown_final()) {
5346 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5347 }
5348
5349 session = inv->mod_data[session_module.id];
5350 if (handle_incoming_sdp(session, offer)) {
5351 ast_sip_session_media_state_reset(session->pending_media_state);
5352 SCOPE_EXIT_RTN("%s: handle_incoming_sdp failed\n", ast_sip_session_get_name(session));
5353 }
5354
5355 if ((answer = create_local_sdp(inv, session, offer, 0))) {
5356 pjsip_inv_set_sdp_answer(inv, answer);
5357 SCOPE_EXIT_RTN("%s: Set SDP answer\n", ast_sip_session_get_name(session));
5358 }
5359 SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));
5360}

References answer(), ast_shutdown_final(), ast_sip_session_get_name(), ast_sip_session_media_state_reset(), create_local_sdp(), handle_incoming_sdp(), SCOPE_ENTER, SCOPE_EXIT_RTN, session, and session_module.

◆ session_inv_on_state_changed()

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

Definition at line 4709 of file res_pjsip_session.c.

4710{
4711 pjsip_event_id_e type;
4712 struct ast_sip_session *session = inv->mod_data[session_module.id];
4713 SCOPE_ENTER(1, "%s Event: %s Inv State: %s\n", ast_sip_session_get_name(session),
4714 pjsip_event_str(e->type), pjsip_inv_state_name(inv->state));
4715
4716 if (ast_shutdown_final()) {
4717 SCOPE_EXIT_RTN("Shutting down\n");
4718 }
4719
4720 if (e) {
4721 print_debug_details(inv, NULL, e);
4722 type = e->type;
4723 } else {
4724 type = PJSIP_EVENT_UNKNOWN;
4725 }
4726
4727 session = inv->mod_data[session_module.id];
4728 if (!session) {
4729 SCOPE_EXIT_RTN("No session\n");
4730 }
4731
4732 switch(type) {
4733 case PJSIP_EVENT_TX_MSG:
4734 break;
4735 case PJSIP_EVENT_RX_MSG:
4736 handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);
4737 break;
4738 case PJSIP_EVENT_TSX_STATE:
4739 ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),
4740 pjsip_event_str(e->body.tsx_state.type));
4741 /* Transaction state changes are prompted by some other underlying event. */
4742 switch(e->body.tsx_state.type) {
4743 case PJSIP_EVENT_TX_MSG:
4744 break;
4745 case PJSIP_EVENT_RX_MSG:
4746 if (!check_request_status(inv, e)) {
4747 handle_incoming_before_media(inv, session, e->body.tsx_state.src.rdata);
4748 }
4749 break;
4750 case PJSIP_EVENT_TRANSPORT_ERROR:
4751 case PJSIP_EVENT_TIMER:
4752 /*
4753 * Check the request status on transport error or timeout. A transport
4754 * error can occur when a TCP socket closes and that can be the result
4755 * of a 503. Also we may need to failover on a timeout (408).
4756 */
4757 check_request_status(inv, e);
4758 break;
4759 case PJSIP_EVENT_USER:
4760 case PJSIP_EVENT_UNKNOWN:
4761 case PJSIP_EVENT_TSX_STATE:
4762 /* Inception? */
4763 break;
4764 }
4765 break;
4766 case PJSIP_EVENT_TRANSPORT_ERROR:
4767 case PJSIP_EVENT_TIMER:
4768 case PJSIP_EVENT_UNKNOWN:
4769 case PJSIP_EVENT_USER:
4770 default:
4771 break;
4772 }
4773
4774 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
4775 if (session->defer_end) {
4776 ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));
4777 session->ended_while_deferred = 1;
4778 SCOPE_EXIT_RTN("Deferring\n");
4779 }
4780
4781 if (ast_sip_push_task(session->serializer, session_end, session)) {
4782 /* Do it anyway even though this is not the right thread. */
4784 }
4785 }
4786
4788}
#define print_debug_details(inv, tsx, e)
static void handle_incoming_before_media(pjsip_inv_session *inv, struct ast_sip_session *session, pjsip_rx_data *rdata)
static int check_request_status(pjsip_inv_session *inv, pjsip_event *e)

References ast_debug, ast_shutdown_final(), ast_sip_push_task(), ast_sip_session_get_name(), check_request_status(), handle_incoming_before_media(), NULL, print_debug_details, SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end(), session_module, and type.

◆ 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 4825 of file res_pjsip_session.c.

4826{
4828 int id = session_module.id;
4829 pjsip_tx_data *tdata;
4830 struct ast_sip_session *session = inv->mod_data[session_module.id];
4831 SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4832 pjsip_tsx_state_str(tsx->state), pjsip_inv_state_name(inv->state));
4833
4834 if (ast_shutdown_final()) {
4835 SCOPE_EXIT_RTN("Shutting down\n");
4836 }
4837
4838 session = inv->mod_data[id];
4839
4840 print_debug_details(inv, tsx, e);
4841 if (!session) {
4842 /* The session has ended. Ignore the transaction change. */
4843 SCOPE_EXIT_RTN("Session ended\n");
4844 }
4845
4846 /*
4847 * If the session is disconnected really nothing else to do unless currently transacting
4848 * a BYE. If a BYE then hold off destruction until the transaction timeout occurs. This
4849 * has to be done for BYEs because sometimes the dialog can be in a disconnected
4850 * state but the BYE request transaction has not yet completed.
4851 */
4852 if (tsx->method.id != PJSIP_BYE_METHOD && session_end_if_disconnected(id, inv)) {
4853 SCOPE_EXIT_RTN("Disconnected\n");
4854 }
4855
4856 switch (e->body.tsx_state.type) {
4857 case PJSIP_EVENT_TX_MSG:
4858 /* When we create an outgoing request, we do not have access to the transaction that
4859 * is created. Instead, We have to place transaction-specific data in the tdata. Here,
4860 * we transfer the data into the transaction. This way, when we receive a response, we
4861 * can dig this data out again
4862 */
4863 tsx->mod_data[id] = e->body.tsx_state.src.tdata->mod_data[id];
4864 break;
4865 case PJSIP_EVENT_RX_MSG:
4866 cb = ast_sip_mod_data_get(tsx->mod_data, id, MOD_DATA_ON_RESPONSE);
4867 /* As the PJSIP invite session implementation responds with a 200 OK before we have a
4868 * chance to be invoked session supplements for BYE requests actually end up executing
4869 * in the invite session state callback as well. To prevent session supplements from
4870 * running on the BYE request again we explicitly squash invocation of them here.
4871 */
4872 if ((e->body.tsx_state.src.rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) ||
4873 (tsx->method.id != PJSIP_BYE_METHOD)) {
4874 handle_incoming(session, e->body.tsx_state.src.rdata,
4876 }
4877 if (tsx->method.id == PJSIP_INVITE_METHOD) {
4878 if (tsx->role == PJSIP_ROLE_UAC) {
4879 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
4880 /* This means we got a non 2XX final response to our outgoing INVITE */
4881 if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
4883 SCOPE_EXIT_RTN("Non 2XX final response\n");
4884 }
4885 if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
4886 ast_debug(1, "%s: reINVITE received final response code %d\n",
4888 tsx->status_code);
4889 if ((tsx->status_code == 401 || tsx->status_code == 407
4890 || (session->endpoint->security_negotiation && tsx->status_code == 494))
4891 && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
4893 &session->endpoint->outbound_auths,
4894 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
4895 /* Send authed reINVITE */
4897 SCOPE_EXIT_RTN("Sending authed reinvite\n");
4898 }
4899 /* Per RFC3261 14.1 a response to a re-INVITE should only terminate
4900 * the dialog if a 481 or 408 occurs. All other responses should leave
4901 * the dialog untouched.
4902 */
4903 if (tsx->status_code == 481 || tsx->status_code == 408) {
4904 if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
4905 && tdata) {
4907 }
4908 }
4909 }
4910 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
4911 if (!inv->cancelling
4912 && inv->role == PJSIP_ROLE_UAC
4913 && inv->state == PJSIP_INV_STATE_CONFIRMED
4914 && pjmedia_sdp_neg_was_answer_remote(inv->neg)
4915 && pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE
4917 ) {
4918 /*
4919 * We didn't send a CANCEL but the UAS sent us the 200 OK with an invalid or unacceptable codec SDP.
4920 * In this case the SDP negotiation is incomplete and PJPROJECT has already sent the ACK.
4921 * So, we send the BYE with 503 status code here. And the actual hangup cause code is already set
4922 * to AST_CAUSE_BEARERCAPABILITY_NOTAVAIL by the session_inv_on_media_update(), setting the 503
4923 * status code doesn't affect to hangup cause code.
4924 */
4925 ast_debug(1, "Endpoint '%s(%s)': Ending session due to 200 OK with incomplete SDP negotiation. %s\n",
4927 session->channel ? ast_channel_name(session->channel) : "",
4928 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4929 pjsip_inv_end_session(session->inv_session, 503, NULL, &tdata);
4930 SCOPE_EXIT_RTN("Incomplete SDP negotiation\n");
4931 }
4932
4933 if (inv->cancelling && tsx->status_code == PJSIP_SC_OK) {
4934 int sdp_negotiation_done =
4935 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE;
4936
4937 /*
4938 * We can get here for the following reasons.
4939 *
4940 * 1) The race condition detailed in RFC5407 section 3.1.2.
4941 * We sent a CANCEL at the same time that the UAS sent us a
4942 * 200 OK with a valid SDP for the original INVITE. As a
4943 * result, we have now received a 200 OK for a cancelled
4944 * call and the SDP negotiation is complete. We need to
4945 * immediately send a BYE to end the dialog.
4946 *
4947 * 2) We sent a CANCEL and hit the race condition but the
4948 * UAS sent us an invalid SDP with the 200 OK. In this case
4949 * the SDP negotiation is incomplete and PJPROJECT has
4950 * already sent the BYE for us because of the invalid SDP.
4951 */
4952 ast_test_suite_event_notify("PJSIP_SESSION_CANCELED",
4953 "Endpoint: %s\r\n"
4954 "Channel: %s\r\n"
4955 "Message: %s\r\n"
4956 "SDP: %s",
4958 session->channel ? ast_channel_name(session->channel) : "",
4959 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata),
4960 sdp_negotiation_done ? "complete" : "incomplete");
4961 if (!sdp_negotiation_done) {
4962 ast_debug(1, "%s: Incomplete SDP negotiation cancelled session. %s\n",
4964 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4965 } else if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
4966 && tdata) {
4967 ast_debug(1, "%s: Ending session due to RFC5407 race condition. %s\n",
4969 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4971 }
4972 }
4973 }
4974 }
4975 } else {
4976 /* All other methods */
4977 if (tsx->role == PJSIP_ROLE_UAC) {
4978 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
4979 /* This means we got a final response to our outgoing method */
4980 ast_debug(1, "%s: %.*s received final response code %d\n",
4982 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4983 tsx->status_code);
4984 if ((tsx->status_code == 401 || tsx->status_code == 407 || tsx->status_code == 494)
4985 && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
4987 &session->endpoint->outbound_auths,
4988 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
4989 /* Send authed version of the method */
4991 SCOPE_EXIT_RTN("Sending authed %.*s\n",
4992 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name));
4993 }
4994 }
4995 }
4996 }
4997 if (cb) {
4998 cb(session, e->body.tsx_state.src.rdata);
4999 }
5000 break;
5001 case PJSIP_EVENT_TRANSPORT_ERROR:
5002 case PJSIP_EVENT_TIMER:
5003 /*
5004 * The timer event is run by the pjsip monitor thread and not
5005 * by the session serializer.
5006 */
5007 if (session_end_if_disconnected(id, inv)) {
5008 SCOPE_EXIT_RTN("Disconnected\n");
5009 }
5010 break;
5011 case PJSIP_EVENT_USER:
5012 case PJSIP_EVENT_UNKNOWN:
5013 case PJSIP_EVENT_TSX_STATE:
5014 /* Inception? */
5015 break;
5016 }
5017
5018 if (AST_LIST_EMPTY(&session->delayed_requests)) {
5019 /* No delayed request pending, so just return */
5020 SCOPE_EXIT_RTN("Nothing delayed\n");
5021 }
5022
5023 if (tsx->method.id == PJSIP_INVITE_METHOD) {
5024 if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
5025 ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
5027 pjsip_tsx_state_str(tsx->state));
5029 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
5030 /*
5031 * Terminated INVITE transactions always should result in
5032 * queuing delayed requests, no matter what event caused
5033 * the transaction to terminate.
5034 */
5035 ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
5037 pjsip_tsx_state_str(tsx->state));
5039 }
5040 } else if (tsx->role == PJSIP_ROLE_UAC
5041 && tsx->state == PJSIP_TSX_STATE_COMPLETED
5042 && !pj_strcmp2(&tsx->method.name, "UPDATE")) {
5043 ast_debug(3, "%s: UPDATE delay check. tsx-state:%s\n",
5045 pjsip_tsx_state_str(tsx->state));
5047 }
5048
5050}
int ast_channel_hangupcause(const struct ast_channel *chan)
#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:2948
static int invite_proceeding(void *vsession)
static int update_completed(void *vsession)
static void check_delayed_requests(struct ast_sip_session *session, int(*cb)(void *vsession))
static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session_response_cb on_response)
static int session_end_if_disconnected(int id, pjsip_inv_session *inv)
@ AST_SIP_SESSION_AFTER_MEDIA
int(* ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata)

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, check_delayed_requests(), handle_incoming(), id, invite_proceeding(), invite_terminated(), MAX_RX_CHALLENGES, MOD_DATA_ON_RESPONSE, NULL, print_debug_details, reschedule_reinvite(), SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end_if_disconnected(), session_module, and update_completed().

◆ session_media_dtor()

static void session_media_dtor ( void *  obj)
static

Definition at line 478 of file res_pjsip_session.c.

479{
480 struct ast_sip_session_media *session_media = obj;
481
482 /* It is possible for multiple handlers to have allocated memory on the
483 * session media (usually through a stream changing types). Therefore, we
484 * traverse all the SDP handlers and let them all call stream_destroy on
485 * the session_media
486 */
487 ao2_callback(sdp_handlers, 0, stream_destroy, session_media);
488
489 if (session_media->srtp) {
490 ast_sdp_srtp_destroy(session_media->srtp);
491 }
492
493 ast_free(session_media->mid);
494 ast_free(session_media->remote_mslabel);
495 ast_free(session_media->remote_label);
496 ast_free(session_media->stream_name);
497}
static int stream_destroy(void *obj, void *arg, int flags)
void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp)
free a ast_sdp_srtp structure
Definition: sdp_srtp.c:51
struct ast_sdp_srtp * srtp
Holds SRTP information.
char * remote_label
Remote stream label.
char * remote_mslabel
Remote media stream label.

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, sdp_handlers, ast_sip_session_media::srtp, stream_destroy(), and ast_sip_session_media::stream_name.

Referenced by ast_sip_session_media_state_add().

◆ 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 454 of file res_pjsip_session.c.

456{
457 ast_assert(session_media->handler != handler);
458
459 if (session_media->handler) {
460 session_media->handler->stream_destroy(session_media);
461 }
462 session_media->handler = handler;
463}
void(* stream_destroy)(struct ast_sip_session_media *session_media)
Destroy a session_media created by this handler.

References ast_assert, ast_sip_session_media::handler, 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().

◆ 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 4297 of file res_pjsip_session.c.

4298{
4299 pj_status_t handled = PJ_FALSE;
4300 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4301 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4302 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4303 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4304 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4305 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4306 SCOPE_ENTER(1, "%s Request: %.*s %s\n", ast_sip_session_get_name(session),
4307 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), res ? req_uri : "");
4308
4309 switch (req.method.id) {
4310 case PJSIP_INVITE_METHOD:
4311 if (dlg) {
4312 ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
4313 break;
4314 }
4315 handled = PJ_TRUE;
4317 break;
4318 default:
4319 /* Handle other in-dialog methods if their supplements have been registered */
4320 handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
4321 has_supplement(inv_session->mod_data[session_module.id], rdata);
4322 break;
4323 }
4324
4325 SCOPE_EXIT_RTN_VALUE(handled, "%s Handled request %.*s %s ? %s\n", ast_sip_session_get_name(session),
4326 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), req_uri,
4327 handled == PJ_TRUE ? "yes" : "no");
4328}
static void handle_new_invite_request(pjsip_rx_data *rdata)
static pj_bool_t has_supplement(const struct ast_sip_session *session, const pjsip_rx_data *rdata)

References ast_alloca, ast_log, ast_sip_session_get_name(), handle_new_invite_request(), has_supplement(), ast_sip_session::inv_session, LOG_WARNING, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_module, and TRACE_ATLEAST.

◆ session_on_rx_response()

static pj_bool_t session_on_rx_response ( pjsip_rx_data *  rdata)
static

Definition at line 4267 of file res_pjsip_session.c.

4268{
4269
4270 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4271 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4272 pjsip_inv_session *inv_session = dlg ? pjsip_dlg_get_inv_session(dlg) : NULL;
4273 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4274 SCOPE_ENTER(1, "%s Method: %.*s Status: %d\n", ast_sip_session_get_name(session),
4275 (int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
4276
4277 SCOPE_EXIT_RTN_VALUE(PJ_FALSE);
4278}

References ast_sip_session_get_name(), ast_sip_session::inv_session, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_module, and status.

◆ session_on_tsx_state()

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

Definition at line 4245 of file res_pjsip_session.c.

4246{
4247
4248 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
4249 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4250 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4251 SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4252 pjsip_tsx_state_str(tsx->state), inv_session ? pjsip_inv_state_name(inv_session->state) : "unknown");
4253
4254 if (session) {
4255 ast_trace(2, "Topology: Pending: %s Active: %s\n",
4256 ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)),
4257 ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
4258 }
4259
4261}

References ast_sip_session_get_name(), ast_str_tmp, ast_stream_topology_to_str(), ast_trace, ast_sip_session::inv_session, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN, session, and session_module.

◆ session_on_tx_response()

static pj_bool_t session_on_tx_response ( pjsip_tx_data *  tdata)
static

Definition at line 4331 of file res_pjsip_session.c.

4332{
4333 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
4335 if (session) {
4337 }
4338
4339 return PJ_SUCCESS;
4340}

References ao2_cleanup, ast_sip_dialog_get_session(), handle_outgoing_response(), NULL, RAII_VAR, and session.

◆ 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 5594 of file res_pjsip_session.c.

5595{
5598 tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK);
5599 pjsip_sdp_info *sdp_info;
5600 pjmedia_sdp_session *sdp;
5601 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
5603 int stream;
5604
5605 /*
5606 * If there's no transport_state or body, or the hook
5607 * has already been run, just return.
5608 */
5609 if (ast_strlen_zero(transport->external_media_address) || !transport_state || hook || !tdata->msg->body) {
5610 return;
5611 }
5612
5613 sdp_info = pjsip_get_sdp_info(tdata->pool, tdata->msg->body, NULL, &pjsip_media_type_application_sdp);
5614 if (sdp_info->sdp_err != PJ_SUCCESS || !sdp_info->sdp) {
5615 return;
5616 }
5617 sdp = sdp_info->sdp;
5618
5619 if (sdp->conn) {
5620 char host[NI_MAXHOST];
5621 struct ast_sockaddr our_sdp_addr = { { 0, } };
5622
5623 ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
5624 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
5625
5626 /* Reversed check here. We don't check the remote
5627 * endpoint being in our local net, but whether our
5628 * outgoing session IP is local. If it is, we'll do
5629 * rewriting. No localnet configured? Always rewrite. */
5630 if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {
5631 ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),
5632 ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5633 pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5634 pj_strassign(&sdp->origin.addr, &sdp->conn->addr);
5635 }
5636 }
5637
5638 for (stream = 0; stream < sdp->media_count; ++stream) {
5639 /* See if there are registered handlers for this media stream type */
5640 char media[20];
5642 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5643
5644 /* We need a null-terminated version of the media string */
5645 ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
5646
5647 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
5648 if (!handler_list) {
5649 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session),
5650 media);
5651 continue;
5652 }
5653 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5654 if (handler->change_outgoing_sdp_stream_media_address) {
5655 handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
5656 }
5657 }
5658 }
5659
5660 /* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
5661 ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK, nat_hook);
5662}
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
static char * ast_sockaddr_stringify_addr_remote(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:313
pjsip_media_type pjsip_media_type_application_sdp
Definition: res_pjsip.c:3916
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
#define ast_sip_transport_is_local(transport_state, addr)
Definition: res_pjsip.h:215
#define MOD_DATA_NAT_HOOK
Structure for SIP nat hook information.
Definition: res_pjsip.h:329
Structure for SIP transport information.
Definition: res_pjsip.h:119
const ast_string_field external_media_address
Definition: res_pjsip.h:241
Socket address structure.
Definition: netsock2.h:97

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_mod_data_get, ast_sip_mod_data_set, ast_sip_session_get_name(), ast_sip_transport_is_local, ast_sockaddr_parse(), ast_sockaddr_stringify_addr_remote(), ast_sorcery_object_get_id(), ast_strlen_zero(), ast_sip_transport::external_media_address, handler(), MOD_DATA_NAT_HOOK, nat_hook, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, PARSE_PORT_FORBID, pjsip_media_type_application_sdp, RAII_VAR, sdp_handlers, session, and session_module.

Referenced by load_module().

◆ session_reinvite_on_rx_request()

static pj_bool_t session_reinvite_on_rx_request ( pjsip_rx_data *  rdata)
static

Definition at line 2753 of file res_pjsip_session.c.

2754{
2755 pjsip_dialog *dlg;
2757 pjsip_rdata_sdp_info *sdp_info;
2758 int deferred;
2759
2760 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
2761 !(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
2763 !session->channel) {
2764 return PJ_FALSE;
2765 }
2766
2767 if (session->inv_session->invite_tsx) {
2768 /* There's a transaction in progress so bail now and let pjproject send 491 */
2769 return PJ_FALSE;
2770 }
2771
2772 if (session->deferred_reinvite) {
2773 pj_str_t key, deferred_key;
2774 pjsip_tx_data *tdata;
2775
2776 /* We use memory from the new request on purpose so the deferred reinvite pool does not grow uncontrollably */
2777 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &rdata->msg_info.cseq->method, rdata);
2778 pjsip_tsx_create_key(rdata->tp_info.pool, &deferred_key, PJSIP_ROLE_UAS, &session->deferred_reinvite->msg_info.cseq->method,
2779 session->deferred_reinvite);
2780
2781 /* If this is a retransmission ignore it */
2782 if (!pj_strcmp(&key, &deferred_key)) {
2783 return PJ_TRUE;
2784 }
2785
2786 /* Otherwise this is a new re-invite, so reject it */
2787 if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) {
2788 if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
2789 pjsip_tx_data_dec_ref(tdata);
2790 }
2791 }
2792
2793 return PJ_TRUE;
2794 }
2795
2796 if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
2797 (sdp_info->sdp_err != PJ_SUCCESS)) {
2798 return PJ_FALSE;
2799 }
2800
2801 if (!sdp_info->sdp) {
2802 return PJ_FALSE;
2803 }
2804
2805 deferred = sdp_requires_deferral(session, sdp_info->sdp);
2806 if (deferred == -1) {
2807 ast_sip_session_media_state_reset(session->pending_media_state);
2808 return PJ_FALSE;
2809 } else if (!deferred) {
2810 return PJ_FALSE;
2811 }
2812
2813 pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
2814
2815 return PJ_TRUE;
2816}
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.

References ao2_cleanup, ast_sip_dialog_get_session(), ast_sip_get_pjsip_endpoint(), ast_sip_session_media_state_reset(), NULL, RAII_VAR, sdp_requires_deferral(), and session.

◆ session_termination_cb()

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

Definition at line 3565 of file res_pjsip_session.c.

3566{
3567 struct ast_sip_session *session = entry->user_data;
3568
3571 }
3572}
static int session_termination_task(void *data)

References ao2_cleanup, ast_sip_push_task(), session, and session_termination_task().

Referenced by ast_sip_session_defer_termination().

◆ session_termination_task()

static int session_termination_task ( void *  data)
static

Definition at line 3550 of file res_pjsip_session.c.

3551{
3552 struct ast_sip_session *session = data;
3553
3554 if (session->defer_terminate) {
3555 session->defer_terminate = 0;
3556 if (session->inv_session) {
3558 }
3559 }
3560
3561 ao2_ref(session, -1);
3562 return 0;
3563}

References ao2_ref, ast_sip_session_terminate(), and session.

Referenced by session_termination_cb().

◆ set_from_header()

static void set_from_header ( struct ast_sip_session session)
static

Definition at line 1648 of file res_pjsip_session.c.

1649{
1650 struct ast_party_id effective_id;
1651 struct ast_party_id connected_id;
1652 pj_pool_t *dlg_pool;
1653 pjsip_fromto_hdr *dlg_info;
1654 pjsip_contact_hdr *dlg_contact;
1655 pjsip_name_addr *dlg_info_name_addr;
1656 pjsip_sip_uri *dlg_info_uri;
1657 pjsip_sip_uri *dlg_contact_uri;
1658 int restricted;
1659 const char *pjsip_from_domain;
1660
1661 if (!session->channel || session->saved_from_hdr) {
1662 return;
1663 }
1664
1665 /* We need to save off connected_id for RPID/PAI generation */
1666 ast_party_id_init(&connected_id);
1667 ast_channel_lock(session->channel);
1668 effective_id = ast_channel_connected_effective_id(session->channel);
1669 ast_party_id_copy(&connected_id, &effective_id);
1670 ast_channel_unlock(session->channel);
1671
1672 restricted =
1674
1675 /* Now set up dlg->local.info so pjsip can correctly generate From */
1676
1677 dlg_pool = session->inv_session->dlg->pool;
1678 dlg_info = session->inv_session->dlg->local.info;
1679 dlg_contact = session->inv_session->dlg->local.contact;
1680 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1681 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1682 dlg_contact_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(dlg_contact->uri);
1683
1684 if (session->endpoint->id.trust_outbound || !restricted) {
1685 ast_sip_modify_id_header(dlg_pool, dlg_info, &connected_id);
1686 if (ast_sip_get_use_callerid_contact() && ast_strlen_zero(session->endpoint->contact_user)) {
1687 pj_strdup2(dlg_pool, &dlg_contact_uri->user, S_COR(connected_id.number.valid, connected_id.number.str, ""));
1688 }
1689 }
1690
1691 ast_party_id_free(&connected_id);
1692
1693 if (!ast_strlen_zero(session->endpoint->fromuser)) {
1694 dlg_info_name_addr->display.ptr = NULL;
1695 dlg_info_name_addr->display.slen = 0;
1696 pj_strdup2(dlg_pool, &dlg_info_uri->user, session->endpoint->fromuser);
1697 }
1698
1699 if (!ast_strlen_zero(session->endpoint->fromdomain)) {
1700 pj_strdup2(dlg_pool, &dlg_info_uri->host, session->endpoint->fromdomain);
1701 }
1702
1703 /*
1704 * Channel variable for compatibility with chan_sip SIPFROMDOMAIN
1705 */
1706 ast_channel_lock(session->channel);
1707 pjsip_from_domain = pbx_builtin_getvar_helper(session->channel, "SIPFROMDOMAIN");
1708 if (!ast_strlen_zero(pjsip_from_domain)) {
1709 ast_debug(3, "%s: From header domain reset by channel variable SIPFROMDOMAIN (%s)\n",
1710 ast_sip_session_get_name(session), pjsip_from_domain);
1711 pj_strdup2(dlg_pool, &dlg_info_uri->host, pjsip_from_domain);
1712 }
1713 ast_channel_unlock(session->channel);
1714
1715 /* We need to save off the non-anonymized From for RPID/PAI generation (for domain) */
1716 session->saved_from_hdr = pjsip_hdr_clone(dlg_pool, dlg_info);
1717 ast_sip_add_usereqphone(session->endpoint, dlg_pool, session->saved_from_hdr->uri);
1718
1719 /* In chan_sip, fromuser and fromdomain trump restricted so we only
1720 * anonymize if they're not set.
1721 */
1722 if (restricted) {
1723 /* fromuser doesn't provide a display name so we always set it */
1724 pj_strdup2(dlg_pool, &dlg_info_name_addr->display, "Anonymous");
1725
1726 if (ast_strlen_zero(session->endpoint->fromuser)) {
1727 pj_strdup2(dlg_pool, &dlg_info_uri->user, "anonymous");
1728 }
1729
1730 if (ast_sip_get_use_callerid_contact() && ast_strlen_zero(session->endpoint->contact_user)) {
1731 pj_strdup2(dlg_pool, &dlg_contact_uri->user, "anonymous");
1732 }
1733
1734 if (ast_strlen_zero(session->endpoint->fromdomain)) {
1735 pj_strdup2(dlg_pool, &dlg_info_uri->host, "anonymous.invalid");
1736 }
1737 } else {
1738 ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri);
1739 }
1740}
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri)
Add 'user=phone' parameter to URI if enabled and user is a phone number.
Definition: res_pjsip.c:930
unsigned int ast_sip_get_use_callerid_contact(void)
Retrieve the global setting 'use_callerid_contact'.
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:2850

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(), NULL, ast_party_id::number, pbx_builtin_getvar_helper(), S_COR, session, ast_party_number::str, and ast_party_number::valid.

Referenced by ast_sip_session_create_invite().

◆ 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 655 of file res_pjsip_session.c.

659{
660 pjmedia_sdp_attr *attr;
661
662 if (!session->endpoint->media.bundle) {
663 return 0;
664 }
665
666 /* By default on an incoming negotiation we assume no mid and bundle group is present */
667 ast_free(session_media->mid);
668 session_media->mid = NULL;
669 session_media->bundle_group = -1;
670 session_media->bundled = 0;
671
672 /* Grab the media identifier for the stream */
673 attr = pjmedia_sdp_media_find_attr2(stream, "mid", NULL);
674 if (!attr) {
675 return 0;
676 }
677
678 session_media->mid = ast_calloc(1, attr->value.slen + 1);
679 if (!session_media->mid) {
680 return 0;
681 }
682 ast_copy_pj_str(session_media->mid, &attr->value, attr->value.slen + 1);
683
684 /* Determine what bundle group this is part of */
685 session_media->bundle_group = get_mid_bundle_group(sdp, session_media->mid);
686
687 /* If this is actually part of a bundle group then the other side requested or accepted the bundle request */
688 session_media->bundled = session_media->bundle_group != -1;
689
690 return 0;
691}
static int get_mid_bundle_group(const pjmedia_sdp_session *sdp, const char *mid)

References ast_calloc, ast_copy_pj_str(), ast_free, ast_sip_session_media::bundle_group, ast_sip_session_media::bundled, get_mid_bundle_group(), ast_sip_session_media::mid, NULL, and session.

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

◆ 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 693 of file res_pjsip_session.c.

698{
699 int index;
700
701 ast_free(session_media->remote_mslabel);
702 session_media->remote_mslabel = NULL;
703 ast_free(session_media->remote_label);
704 session_media->remote_label = NULL;
705
706 for (index = 0; index < stream->attr_count; ++index) {
707 pjmedia_sdp_attr *attr = stream->attr[index];
708 char attr_value[pj_strlen(&attr->value) + 1];
709 char *ssrc_attribute_name, *ssrc_attribute_value = NULL;
710 char *msid, *tmp = attr_value;
711 static const pj_str_t STR_msid = { "msid", 4 };
712 static const pj_str_t STR_ssrc = { "ssrc", 4 };
713 static const pj_str_t STR_label = { "label", 5 };
714
715 if (!pj_strcmp(&attr->name, &STR_label)) {
716 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
717 session_media->remote_label = ast_strdup(attr_value);
718 } else if (!pj_strcmp(&attr->name, &STR_msid)) {
719 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
720 msid = strsep(&tmp, " ");
721 session_media->remote_mslabel = ast_strdup(msid);
722 break;
723 } else if (!pj_strcmp(&attr->name, &STR_ssrc)) {
724 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
725
726 if ((ssrc_attribute_name = strchr(attr_value, ' '))) {
727 /* This has an actual attribute */
728 *ssrc_attribute_name++ = '\0';
729 ssrc_attribute_value = strchr(ssrc_attribute_name, ':');
730 if (ssrc_attribute_value) {
731 /* Values are actually optional according to the spec */
732 *ssrc_attribute_value++ = '\0';
733 }
734
735 if (!strcasecmp(ssrc_attribute_name, "mslabel") && !ast_strlen_zero(ssrc_attribute_value)) {
736 session_media->remote_mslabel = ast_strdup(ssrc_attribute_value);
737 break;
738 }
739 }
740 }
741 }
742
743 if (ast_strlen_zero(session_media->remote_mslabel)) {
744 return;
745 }
746
747 /* Iterate through the existing streams looking for a match and if so then group this with it */
748 for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
749 struct ast_sip_session_media *group_session_media;
750
751 group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
752
753 if (ast_strlen_zero(group_session_media->remote_mslabel) ||
754 strcmp(group_session_media->remote_mslabel, session_media->remote_mslabel)) {
755 continue;
756 }
757
758 ast_stream_set_group(asterisk_stream, index);
759 break;
760 }
761}
static int tmp()
Definition: bt_open.c:389
void ast_stream_set_group(struct ast_stream *stream, int group)
Set the stream group for a stream.
Definition: stream.c:1084

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_media::remote_label, ast_sip_session_media::remote_mslabel, session, strsep(), and tmp().

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

◆ setup_outbound_invite_auth()

static int setup_outbound_invite_auth ( pjsip_dialog *  dlg)
static

Definition at line 3326 of file res_pjsip_session.c.

3327{
3328 pj_status_t status;
3329
3330 ++dlg->sess_count;
3331 status = pjsip_dlg_add_usage(dlg, &outbound_invite_auth_module, NULL);
3332 --dlg->sess_count;
3333
3334 return status != PJ_SUCCESS ? -1 : 0;
3335}

References NULL, outbound_invite_auth_module, and status.

Referenced by ast_sip_session_create_outgoing().

◆ sip_channel_destroy()

static void sip_channel_destroy ( void *  obj)
static

Destructor for SIP channel.

Definition at line 2986 of file res_pjsip_session.c.

2987{
2988 struct ast_sip_channel_pvt *channel = obj;
2989
2990 ao2_cleanup(channel->pvt);
2991 ao2_cleanup(channel->session);
2992}

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

Referenced by ast_sip_channel_pvt_alloc().

◆ sip_session_defer_termination_stop_timer()

static void sip_session_defer_termination_stop_timer ( struct ast_sip_session session)
static

Definition at line 3606 of file res_pjsip_session.c.

3607{
3608 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
3609 &session->scheduled_termination, session->scheduled_termination.id)) {
3610 ao2_ref(session, -1);
3611 }
3612}

References ao2_ref, ast_sip_get_pjsip_endpoint(), and session.

Referenced by ast_sip_session_defer_termination_cancel(), and session_end().

◆ 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 2196 of file res_pjsip_session.c.

2204{
2205 pjsip_inv_session *inv_session = session->inv_session;
2206 pjmedia_sdp_session *new_sdp = NULL;
2207 pjsip_tx_data *tdata;
2208 int res = -1;
2209 SCOPE_ENTER(3, "%s: New SDP? %s Queued? %s DP: %s DA: %s\n", ast_sip_session_get_name(session),
2210 generate_new_sdp ? "yes" : "no", queued ? "yes" : "no",
2211 pending_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)) : "none",
2212 active_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)) : "none");
2213
2214 if (pending_media_state && (!pending_media_state->topology || !generate_new_sdp)) {
2215
2216 ast_sip_session_media_state_free(pending_media_state);
2217 ast_sip_session_media_state_free(active_media_state);
2218 SCOPE_EXIT_RTN_VALUE(-1, "%s: Not sending reinvite because %s%s\n", ast_sip_session_get_name(session),
2219 pending_media_state->topology == NULL ? "pending topology is null " : "",
2220 !generate_new_sdp ? "generate_new_sdp is false" : "");
2221 }
2222
2223 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
2224 /* Don't try to do anything with a hung-up call */
2225 ast_sip_session_media_state_free(pending_media_state);
2226 ast_sip_session_media_state_free(active_media_state);
2227 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because of disconnected state\n",
2229 }
2230
2231 /* If the dialog has not yet been established we have to defer until it has */
2232 if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
2233 res = delay_request(session, on_request_creation, on_sdp_creation, on_response,
2234 generate_new_sdp,
2237 pending_media_state, active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2238 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because dialog has not been established\n",
2240 }
2241
2243 if (inv_session->invite_tsx) {
2244 /* We can't send a reinvite yet, so delay it */
2245 res = delay_request(session, on_request_creation, on_sdp_creation,
2246 on_response, generate_new_sdp, DELAYED_METHOD_INVITE, pending_media_state,
2247 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2248 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding transaction\n",
2250 } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {
2251 /* Initial INVITE transaction failed to progress us to a confirmed state
2252 * which means re-invites are not possible
2253 */
2254 ast_sip_session_media_state_free(pending_media_state);
2255 ast_sip_session_media_state_free(active_media_state);
2256 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because not in confirmed state\n",
2258 }
2259 }
2260
2261 if (generate_new_sdp) {
2262 /* SDP can only be generated if current negotiation has already completed */
2263 if (inv_session->neg
2264 && pjmedia_sdp_neg_get_state(inv_session->neg)
2265 != PJMEDIA_SDP_NEG_STATE_DONE) {
2266 res = delay_request(session, on_request_creation, on_sdp_creation,
2267 on_response, generate_new_sdp,
2269 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2270 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2271 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay session refresh with new SDP because SDP negotiation is not yet done\n",
2273 }
2274
2275 /* If an explicitly requested media state has been provided use it instead of any pending one */
2276 if (pending_media_state) {
2277 int index;
2278 int type_streams[AST_MEDIA_TYPE_END] = {0};
2279
2280 ast_trace(-1, "%s: Pending media state exists\n", ast_sip_session_get_name(session));
2281
2282 /* Media state conveys a desired media state, so if there are outstanding
2283 * delayed requests we need to ensure we go into the queue and not jump
2284 * ahead. If we sent this media state now then updates could go out of
2285 * order.
2286 */
2287 if (!queued && !AST_LIST_EMPTY(&session->delayed_requests)) {
2288 res = delay_request(session, on_request_creation, on_sdp_creation,
2289 on_response, generate_new_sdp,
2291 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2292 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2293 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding requests\n",
2295 }
2296
2297 /*
2298 * Attempt to resolve only if objects are available, and it's not
2299 * switching to or from an image type.
2300 */
2301 if (active_media_state && active_media_state->topology &&
2302 (!active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] ==
2303 !pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE])) {
2304
2305 struct ast_sip_session_media_state *new_pending_state;
2306
2307 ast_trace(-1, "%s: Active media state exists and is%s equal to pending\n", ast_sip_session_get_name(session),
2308 !ast_stream_topology_equal(active_media_state->topology,pending_media_state->topology) ? " not" : "");
2309 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)));
2310 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)));
2311 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)));
2312 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)));
2313
2315 pending_media_state, active_media_state, session->active_media_state, 1);
2316 if (new_pending_state) {
2317 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)));
2318 ast_sip_session_media_state_free(pending_media_state);
2319 pending_media_state = new_pending_state;
2320 } else {
2321 ast_sip_session_media_state_reset(pending_media_state);
2322 ast_sip_session_media_state_free(active_media_state);
2323 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Unable to merge media states\n", ast_sip_session_get_name(session));
2324 }
2325 }
2326
2327 /* Prune the media state so the number of streams fit within the configured limits - we do it here
2328 * so that the index of the resulting streams in the SDP match. If we simply left the streams out
2329 * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that
2330 * are configurable on the endpoint.
2331 */
2332 ast_trace(-1, "%s: Pruning and checking formats of streams\n", ast_sip_session_get_name(session));
2333
2334 for (index = 0; index < ast_stream_topology_get_count(pending_media_state->topology); ++index) {
2335 struct ast_stream *existing_stream = NULL;
2336 struct ast_stream *stream = ast_stream_topology_get_stream(pending_media_state->topology, index);
2337 SCOPE_ENTER(4, "%s: Checking stream %s\n", ast_sip_session_get_name(session),
2338 ast_stream_get_name(stream));
2339
2340 if (session->active_media_state->topology &&
2341 index < ast_stream_topology_get_count(session->active_media_state->topology)) {
2342 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2343 ast_trace(-1, "%s: Found existing stream %s\n", ast_sip_session_get_name(session),
2344 ast_stream_get_name(existing_stream));
2345 }
2346
2347 if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {
2348 if (index < AST_VECTOR_SIZE(&pending_media_state->sessions)) {
2349 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&pending_media_state->sessions, index);
2350
2351 ao2_cleanup(session_media);
2352 AST_VECTOR_REMOVE(&pending_media_state->sessions, index, 1);
2353 }
2354
2355 ast_stream_topology_del_stream(pending_media_state->topology, index);
2356 ast_trace(-1, "%s: Dropped overlimit stream %s\n", ast_sip_session_get_name(session),
2357 ast_stream_get_name(stream));
2358
2359 /* A stream has potentially moved into our spot so we need to jump back so we process it */
2360 index -= 1;
2361 SCOPE_EXIT_EXPR(continue);
2362 }
2363
2364 /* No need to do anything with stream if it's media state is removed */
2366 /* If there is no existing stream we can just not have this stream in the topology at all. */
2367 if (!existing_stream) {
2368 ast_trace(-1, "%s: Dropped removed stream %s\n", ast_sip_session_get_name(session),
2369 ast_stream_get_name(stream));
2370 ast_stream_topology_del_stream(pending_media_state->topology, index);
2371 /* TODO: Do we need to remove the corresponding media state? */
2372 index -= 1;
2373 }
2374 SCOPE_EXIT_EXPR(continue);
2375 }
2376
2377 /* Enforce the configured allowed codecs on audio and video streams */
2379 !ast_stream_get_metadata(stream, "pjsip_session_refresh")) {
2380 struct ast_format_cap *joint_cap;
2381
2383 if (!joint_cap) {
2384 ast_sip_session_media_state_free(pending_media_state);
2385 ast_sip_session_media_state_free(active_media_state);
2386 res = -1;
2387 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to alloc format caps\n", ast_sip_session_get_name(session));
2388 }
2389 ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap);
2390 if (!ast_format_cap_count(joint_cap)) {
2391 ao2_ref(joint_cap, -1);
2392
2393 if (!existing_stream) {
2394 /* If there is no existing stream we can just not have this stream in the topology
2395 * at all.
2396 */
2397 ast_stream_topology_del_stream(pending_media_state->topology, index);
2398 index -= 1;
2399 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2401 } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) ||
2402 strcmp(ast_stream_get_name(stream), ast_stream_get_name(existing_stream))) {
2403 /* If the underlying stream is a different type or different name then we have to
2404 * mark it as removed, as it is replacing an existing stream. We do this so order
2405 * is preserved.
2406 */
2408 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2410 } else {
2411 /* However if the stream is otherwise remaining the same we can keep the formats
2412 * that exist on it already which allows media to continue to flow. We don't modify
2413 * the format capabilities but do need to cast it so that ao2_bump can raise the
2414 * reference count.
2415 */
2416 joint_cap = ao2_bump((struct ast_format_cap *)ast_stream_get_formats(existing_stream));
2417 }
2418 }
2419 ast_stream_set_formats(stream, joint_cap);
2420 ao2_cleanup(joint_cap);
2421 }
2422
2423 ++type_streams[ast_stream_get_type(stream)];
2424
2425 SCOPE_EXIT();
2426 }
2427
2428 if (session->active_media_state->topology) {
2429 /* SDP is a fun thing. Take for example the fact that streams are never removed. They just become
2430 * declined. To better handle this in the case where something requests a topology change for fewer
2431 * streams than are currently present we fill in the topology to match the current number of streams
2432 * that are active.
2433 */
2434
2435 for (index = ast_stream_topology_get_count(pending_media_state->topology);
2436 index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) {
2437 struct ast_stream *stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2438 struct ast_stream *cloned;
2439 int position;
2440 SCOPE_ENTER(4, "%s: Stream %s not in pending\n", ast_sip_session_get_name(session),
2441 ast_stream_get_name(stream));
2442
2443 cloned = ast_stream_clone(stream, NULL);
2444 if (!cloned) {
2445 ast_sip_session_media_state_free(pending_media_state);
2446 ast_sip_session_media_state_free(active_media_state);
2447 res = -1;
2448 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to clone stream %s\n",
2450 }
2451
2453 position = ast_stream_topology_append_stream(pending_media_state->topology, cloned);
2454 if (position < 0) {
2455 ast_stream_free(cloned);
2456 ast_sip_session_media_state_free(pending_media_state);
2457 ast_sip_session_media_state_free(active_media_state);
2458 res = -1;
2459 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to append cloned stream\n",
2461 }
2462 SCOPE_EXIT("%s: Appended empty stream in position %d to make counts match\n",
2464 }
2465
2466 /*
2467 * We can suppress this re-invite if the pending topology is equal to the currently
2468 * active topology.
2469 */
2470 if (ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
2471 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)));
2472 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)));
2473 ast_sip_session_media_state_free(pending_media_state);
2474 ast_sip_session_media_state_free(active_media_state);
2475 /* For external consumers we return 0 to say success, but internally for
2476 * send_delayed_request we return a separate value to indicate that this
2477 * session refresh would be redundant so we didn't send it
2478 */
2479 SCOPE_EXIT_RTN_VALUE(queued ? 1 : 0, "%s: Topologies are equal. Not sending re-invite\n",
2481 }
2482 }
2483
2484 ast_sip_session_media_state_free(session->pending_media_state);
2485 session->pending_media_state = pending_media_state;
2486 }
2487
2489 if (!new_sdp) {
2490 ast_sip_session_media_state_reset(session->pending_media_state);
2491 ast_sip_session_media_state_free(active_media_state);
2492 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to generate session refresh SDP. Not sending session refresh\n",
2494 }
2495 if (on_sdp_creation) {
2496 if (on_sdp_creation(session, new_sdp)) {
2497 ast_sip_session_media_state_reset(session->pending_media_state);
2498 ast_sip_session_media_state_free(active_media_state);
2499 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_sdp_creation failed\n", ast_sip_session_get_name(session));
2500 }
2501 }
2502 }
2503
2505 if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
2506 if (generate_new_sdp) {
2507 ast_sip_session_media_state_reset(session->pending_media_state);
2508 }
2509 ast_sip_session_media_state_free(active_media_state);
2510 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create reinvite properly\n", ast_sip_session_get_name(session));
2511 }
2512 } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
2513 if (generate_new_sdp) {
2514 ast_sip_session_media_state_reset(session->pending_media_state);
2515 }
2516 ast_sip_session_media_state_free(active_media_state);
2517 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create UPDATE properly\n", ast_sip_session_get_name(session));
2518 }
2519 if (on_request_creation) {
2520 if (on_request_creation(session, tdata)) {
2521 if (generate_new_sdp) {
2522 ast_sip_session_media_state_reset(session->pending_media_state);
2523 }
2524 ast_sip_session_media_state_free(active_media_state);
2525 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));
2526 }
2527 }
2528 ast_sip_session_send_request_with_cb(session, tdata, on_response);
2529 ast_sip_session_media_state_free(active_media_state);
2530
2531end:
2532 SCOPE_EXIT_RTN_VALUE(res, "%s: Sending session refresh SDP via %s\n", ast_sip_session_get_name(session),
2533 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE");
2534}
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:628
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
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 pjmedia_sdp_session * generate_session_refresh_sdp(struct ast_sip_session *session)
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
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
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
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
unsigned int position
The position of the stream in the topology.
Definition: stream.c:90
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412

References 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_session_media_state::default_session, delay_request(), DELAYED_METHOD_INVITE, DELAYED_METHOD_UPDATE, end, generate_session_refresh_sdp(), is_stream_limitation_reached(), LOG_ERROR, LOG_WARNING, method, NULL, 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, session, ast_sip_session_media_state::sessions, and ast_sip_session_media_state::topology.

Referenced by ast_sip_session_refresh(), and send_delayed_request().

◆ sip_session_suspend_task()

static int sip_session_suspend_task ( void *  data)
static

Definition at line 3154 of file res_pjsip_session.c.

3155{
3156 struct ast_sip_session_suspender *suspender = data;
3157
3158 ao2_lock(suspender);
3159
3160 /* Signal that the serializer task is now suspended. */
3161 suspender->suspended = 1;
3162 ast_cond_signal(&suspender->cond_suspended);
3163
3164 /* Wait for the serializer suspension to be completed. */
3165 while (!suspender->complete) {
3166 ast_cond_wait(&suspender->cond_complete, ao2_object_get_lockaddr(suspender));
3167 }
3168
3169 ao2_unlock(suspender);
3170 ao2_ref(suspender, -1);
3171
3172 return 0;
3173}

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().

◆ sip_session_suspender_dtor()

static void sip_session_suspender_dtor ( void *  vdoomed)
static

Definition at line 3138 of file res_pjsip_session.c.

3139{
3140 struct ast_sip_session_suspender *doomed = vdoomed;
3141
3144}
#define ast_cond_destroy(cond)
Definition: lock.h:202

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

Referenced by ast_sip_session_suspend().

◆ stream_destroy()

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

Definition at line 465 of file res_pjsip_session.c.

466{
467 struct sdp_handler_list *handler_list = obj;
468 struct ast_sip_session_media *session_media = arg;
470
471 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
472 handler->stream_destroy(session_media);
473 }
474
475 return 0;
476}

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

Referenced by session_media_dtor().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6253 of file res_pjsip_session.c.

6254{
6256
6257#ifdef TEST_FRAMEWORK
6258 AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6259#endif
6266 return 0;
6267}
void pjsip_reason_header_unload(void)
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References ao2_cleanup, ast_sip_get_sorcery(), ast_sip_unregister_service(), ast_sorcery_delete(), AST_TEST_UNREGISTER, nat_hook, outbound_invite_auth_module, pjsip_reason_header_unload(), sdp_handlers, session_module, and session_reinvite_module.

◆ update_completed()

static int update_completed ( void *  vsession)
static

Definition at line 1579 of file res_pjsip_session.c.

1580{
1581 struct ast_sip_session *session = vsession;
1582 int res;
1583
1584 if (session->inv_session->invite_tsx) {
1586 } else {
1588 }
1589
1590 return res;
1591}

References invite_proceeding(), invite_terminated(), and session.

Referenced by session_inv_on_tsx_state_changed().

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 = AST_BUILDOPT_SUM, .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 6275 of file res_pjsip_session.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6275 of file res_pjsip_session.c.

◆ inv_callback

pjsip_inv_callback inv_callback
static

Definition at line 5583 of file res_pjsip_session.c.

Referenced by load_module().

◆ nat_hook

struct ast_sip_nat_hook* nat_hook
static

NAT hook for modifying outgoing messages with SDP.

Definition at line 86 of file res_pjsip_session.c.

Referenced by load_module(), session_outgoing_nat_hook(), and unload_module().

◆ 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 3310 of file res_pjsip_session.c.

Referenced by load_module(), setup_outbound_invite_auth(), and unload_module().

◆ 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 95 of file res_pjsip_session.c.

Referenced by add_sdp_streams(), ast_sip_session_register_sdp_handler(), ast_sip_session_unregister_sdp_handler(), handle_incoming_sdp(), handle_negotiated_sdp_session_media(), load_module(), sdp_requires_deferral(), session_media_dtor(), session_outgoing_nat_hook(), and unload_module().

◆ session_module

pjsip_module session_module
static

◆ 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 2832 of file res_pjsip_session.c.

Referenced by load_module(), and unload_module().