Asterisk - The Open Source Telephony Project GIT-master-5467495
Loading...
Searching...
No Matches
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/taskpool.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  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_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.
 
struct ast_sip_channel_pvtast_sip_channel_pvt_alloc (void *pvt, struct ast_sip_session *session)
 Allocate a new SIP channel pvt structure.
 
struct ast_sip_sessionast_sip_dialog_get_session (pjsip_dialog *dlg)
 Retrieves a session from a dialog.
 
int ast_sip_session_add_datastore (struct ast_sip_session *session, struct ast_datastore *datastore)
 Add a datastore to a SIP session.
 
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.
 
struct ast_datastoreast_sip_session_alloc_datastore (const struct ast_datastore_info *info, const char *uid)
 Alternative for ast_datastore_alloc()
 
int ast_sip_session_create_invite (struct ast_sip_session *session, pjsip_tx_data **tdata)
 Creates an INVITE request.
 
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.
 
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.
 
void ast_sip_session_defer_termination_cancel (struct ast_sip_session *session)
 Cancel a pending deferred termination.
 
void ast_sip_session_end_if_deferred (struct ast_sip_session *session)
 End the session if it had been previously deferred.
 
struct ast_datastoreast_sip_session_get_datastore (struct ast_sip_session *session, const char *name)
 Retrieve a session datastore.
 
pjsip_dialog * ast_sip_session_get_dialog (const struct ast_sip_session *session)
 Retrieves a dialog from a session.
 
const char * ast_sip_session_get_name (const struct ast_sip_session *session)
 Get the channel or endpoint name associated with the session.
 
pjsip_inv_state ast_sip_session_get_pjsip_inv_state (const struct ast_sip_session *session)
 Retrieves the pjsip_inv_state from a session.
 
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.
 
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.
 
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.
 
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.
 
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.
 
struct ast_sip_session_media_stateast_sip_session_media_state_alloc (void)
 Allocate a session media state structure.
 
struct ast_sip_session_media_stateast_sip_session_media_state_clone (const struct ast_sip_session_media_state *media_state)
 Clone a media state.
 
void ast_sip_session_media_state_free (struct ast_sip_session_media_state *media_state)
 Free a session media state structure.
 
void ast_sip_session_media_state_reset (struct ast_sip_session_media_state *media_state)
 Reset a media state to a clean state.
 
void ast_sip_session_media_stats_save (struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
 Save a media stats.
 
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.
 
int ast_sip_session_regenerate_answer (struct ast_sip_session *session, ast_sip_session_sdp_creation_cb on_sdp_creation)
 Regenerate SDP Answer.
 
int ast_sip_session_register_sdp_handler (struct ast_sip_session_sdp_handler *handler, const char *stream_type)
 Register an SDP handler.
 
void ast_sip_session_remove_datastore (struct ast_sip_session *session, const char *name)
 Remove a session datastore from the session.
 
void ast_sip_session_resume_reinvite (struct ast_sip_session *session)
 Resumes processing of a deferred incoming re-invite.
 
void ast_sip_session_send_request (struct ast_sip_session *session, pjsip_tx_data *tdata)
 Send a SIP request.
 
void ast_sip_session_send_request_with_cb (struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response)
 Send a SIP request and get called back when a response is received.
 
void ast_sip_session_send_response (struct ast_sip_session *session, pjsip_tx_data *tdata)
 Send a SIP response.
 
void ast_sip_session_suspend (struct ast_sip_session *session)
 Request and wait for the session serializer to be suspended.
 
void ast_sip_session_terminate (struct ast_sip_session *session, int response)
 Terminate a session and, if possible, send the provided response code.
 
void ast_sip_session_unregister_sdp_handler (struct ast_sip_session_sdp_handler *handler, const char *stream_type)
 Unregister an SDP handler.
 
void ast_sip_session_unsuspend (struct ast_sip_session *session)
 Request the session serializer be unsuspended.
 
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.
 
static void flush_delayed_requests (struct ast_sip_session *session)
 
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.
 
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.
 
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.
 
static pj_bool_t session_on_rx_request (pjsip_rx_data *rdata)
 Called when a new SIP request comes into PJSIP.
 
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.
 
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 int set_outstanding_invite_timeout (struct ast_sip_session *session)
 
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.
 
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 stream_destroy (void *obj, void *arg, int flags)
 
static int uac_invite_tsx_terminates_dialog (pjsip_transaction *tsx)
 
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 = ASTERISK_GPL_KEY , .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.
 
static pjsip_module outbound_invite_auth_module
 
static struct ao2_containersdp_handlers
 Registered SDP stream handlers.
 
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 1816 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 1814 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 1815 of file res_pjsip_session.c.

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1238 of file res_pjsip_session.c.

◆ MOD_DATA_ON_RESPONSE

#define MOD_DATA_ON_RESPONSE   "on_response"

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

◆ SDP_HANDLER_BUCKETS

#define SDP_HANDLER_BUCKETS   11

Definition at line 58 of file res_pjsip_session.c.

◆ STATE_NONE

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

Definition at line 1813 of file res_pjsip_session.c.

◆ STATE_REMOVED

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

Definition at line 1812 of file res_pjsip_session.c.

◆ STREAM_REMOVED

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

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

3672 {
3673 /*! The extension was successfully found */
3675 /*! The extension specified in the RURI was not found */
3677 /*! The extension specified in the RURI was a partial match */
3679 /*! The RURI is of an unsupported scheme */
3681};
@ 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 4413 of file res_pjsip_session.c.

4414{
4415 int id = session_module.id;
4416 struct ast_sip_session *session = NULL;
4417
4418 if (!DEBUG_ATLEAST(5)) {
4419 /* Debug not spamy enough */
4420 return;
4421 }
4422
4423 ast_log(LOG_DEBUG, "Function %s called on event %s\n",
4424 function, pjsip_event_str(e->type));
4425 if (!inv) {
4426 ast_log(LOG_DEBUG, "Transaction %p does not belong to an inv_session?\n", tsx);
4427 ast_log(LOG_DEBUG, "The transaction state is %s\n",
4428 pjsip_tsx_state_str(tsx->state));
4429 return;
4430 }
4431 if (id > -1) {
4432 session = inv->mod_data[session_module.id];
4433 }
4434 if (!session) {
4435 ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv);
4436 } else {
4437 ast_log(LOG_DEBUG, "The state change pertains to the endpoint '%s(%s)'\n",
4439 session->channel ? ast_channel_name(session->channel) : "");
4440 }
4441 if (inv->invite_tsx) {
4442 ast_log(LOG_DEBUG, "The inv session still has an invite_tsx (%p)\n",
4443 inv->invite_tsx);
4444 } else {
4445 ast_log(LOG_DEBUG, "The inv session does NOT have an invite_tsx\n");
4446 }
4447 if (tsx) {
4448 ast_log(LOG_DEBUG, "The %s %.*s transaction involved in this state change is %p\n",
4449 pjsip_role_name(tsx->role),
4450 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4451 tsx);
4452 ast_log(LOG_DEBUG, "The current transaction state is %s\n",
4453 pjsip_tsx_state_str(tsx->state));
4454 ast_log(LOG_DEBUG, "The transaction state change event is %s\n",
4455 pjsip_event_str(e->body.tsx_state.type));
4456 } else {
4457 ast_log(LOG_DEBUG, "There is no transaction involved in this state change\n");
4458 }
4459 ast_log(LOG_DEBUG, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
4460}
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:2381
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 6257 of file res_pjsip_session.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

5094{
5095 pj_str_t stmp;
5096 pjmedia_sdp_attr *attr;
5097 struct sip_session_media_bundle_group bundle_groups[PJMEDIA_MAX_SDP_MEDIA];
5098 int index, mid_id;
5099 struct sip_session_media_bundle_group *bundle_group;
5100
5101 if (session->endpoint->media.webrtc) {
5102 attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
5103 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5104 }
5105
5106 if (!session->endpoint->media.bundle) {
5107 return 0;
5108 }
5109
5110 memset(bundle_groups, 0, sizeof(bundle_groups));
5111
5112 /* Build the bundle group layout so we can then add it to the SDP */
5113 for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
5114 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
5115
5116 /* If this stream is not part of a bundle group we can't add it */
5117 if (session_media->bundle_group == -1) {
5118 continue;
5119 }
5120
5121 bundle_group = &bundle_groups[session_media->bundle_group];
5122
5123 /* If this is the first mid then we need to allocate the attribute string and place BUNDLE in front */
5124 if (!bundle_group->mids[0]) {
5125 bundle_group->mids[0] = session_media->mid;
5126 bundle_group->attr_string = ast_str_create(64);
5127 if (!bundle_group->attr_string) {
5128 continue;
5129 }
5130
5131 ast_str_set(&bundle_group->attr_string, 0, "BUNDLE %s", session_media->mid);
5132 continue;
5133 }
5134
5135 for (mid_id = 1; mid_id < PJMEDIA_MAX_SDP_MEDIA; ++mid_id) {
5136 if (!bundle_group->mids[mid_id]) {
5137 bundle_group->mids[mid_id] = session_media->mid;
5138 ast_str_append(&bundle_group->attr_string, 0, " %s", session_media->mid);
5139 break;
5140 } else if (!strcmp(bundle_group->mids[mid_id], session_media->mid)) {
5141 break;
5142 }
5143 }
5144 }
5145
5146 /* Add all bundle groups that have mids to the SDP */
5147 for (index = 0; index < PJMEDIA_MAX_SDP_MEDIA; ++index) {
5148 bundle_group = &bundle_groups[index];
5149
5150 if (!bundle_group->attr_string) {
5151 continue;
5152 }
5153
5154 attr = pjmedia_sdp_attr_create(pool, "group", pj_cstr(&stmp, ast_str_buffer(bundle_group->attr_string)));
5155 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5156
5157 ast_free(bundle_group->attr_string);
5158 }
5159
5160 return 0;
5161}
#define ast_free(a)
Definition astmm.h:180
static int answer(void *data)
Definition chan_pjsip.c:687
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
#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
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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:637
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708

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, sip_session_media_bundle_group::mids, 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 5039 of file res_pjsip_session.c.

5043{
5044 struct ast_sip_session_sdp_handler *handler = session_media->handler;
5045 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5046 int res = 0;
5047 SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
5048 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5049
5050 if (handler) {
5051 /* if an already assigned handler reports a catastrophic error, fail */
5052 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
5053 if (res < 0) {
5054 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5055 }
5056 SCOPE_EXIT_RTN_VALUE(0, "Had handler\n");
5057 }
5058
5059 handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY);
5060 if (!handler_list) {
5061 SCOPE_EXIT_RTN_VALUE(0, "No handlers\n");
5062 }
5063
5064 /* no handler for this stream type and we have a list to search */
5065 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5066 if (handler == session_media->handler) {
5067 continue;
5068 }
5069 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
5070 if (res < 0) {
5071 /* catastrophic error */
5072 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5073 }
5074 if (res > 0) {
5075 /* Handled by this handler. Move to the next stream */
5076 session_media_set_handler(session_media, handler);
5077 SCOPE_EXIT_RTN_VALUE(0, "Handled\n");
5078 }
5079 }
5080
5081 /* streams that weren't handled won't be included in generated outbound SDP */
5082 SCOPE_EXIT_RTN_VALUE(0, "Not handled\n");
5083}
#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.
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:981

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 6257 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:1808

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

3058{
3059 struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
3060
3061 if (!channel) {
3062 return NULL;
3063 }
3064
3065 ao2_ref(pvt, +1);
3066 channel->pvt = pvt;
3067 ao2_ref(session, +1);
3068 channel->session = session;
3069
3070 return channel;
3071}
#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 3620 of file res_pjsip_session.c.

3621{
3622 pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3623 struct ast_sip_session *session;
3624
3625 if (!inv_session ||
3626 !(session = inv_session->mod_data[session_module.id])) {
3627 return NULL;
3628 }
3629
3630 ao2_ref(session, +1);
3631
3632 return session;
3633}
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_ari_request(), 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:779

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(), outgoing_request(), 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 3073 of file res_pjsip_session.c.

3075{
3077 struct ast_sip_session *ret_session;
3078 int dsp_features = 0;
3079
3081 if (!session) {
3082 return NULL;
3083 }
3084
3085 AST_LIST_HEAD_INIT(&session->supplements);
3086 AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
3088
3090 if (!session->direct_media_cap) {
3091 return NULL;
3092 }
3095 if (!session->datastores) {
3096 return NULL;
3097 }
3098 session->active_media_state = ast_sip_session_media_state_alloc();
3099 if (!session->active_media_state) {
3100 return NULL;
3101 }
3102 session->pending_media_state = ast_sip_session_media_state_alloc();
3103 if (!session->pending_media_state) {
3104 return NULL;
3105 }
3106 if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
3107 return NULL;
3108 }
3109
3111 dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3112 }
3113 if (endpoint->faxdetect) {
3114 dsp_features |= DSP_FEATURE_FAX_DETECT;
3115 }
3116 if (dsp_features) {
3117 session->dsp = ast_dsp_new();
3118 if (!session->dsp) {
3119 return NULL;
3120 }
3121
3122 ast_dsp_set_features(session->dsp, dsp_features);
3123 }
3124
3125 session->endpoint = ao2_bump(endpoint);
3126
3127 if (rdata) {
3128 /*
3129 * We must continue using the serializer that the original
3130 * INVITE came in on for the dialog. There may be
3131 * retransmissions already enqueued in the original
3132 * serializer that can result in reentrancy and message
3133 * sequencing problems.
3134 */
3135 session->serializer = ast_sip_get_distributor_serializer(rdata);
3136 } else {
3137 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
3138
3139 /* Create name with seq number appended. */
3140 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outsess/%s",
3142
3143 session->serializer = ast_sip_create_serializer(tps_name);
3144 }
3145 if (!session->serializer) {
3146 return NULL;
3147 }
3150
3151 /* When a PJSIP INVITE session is created it is created with a reference
3152 * count of 1, with that reference being managed by the underlying state
3153 * of the INVITE session itself. When the INVITE session transitions to
3154 * a DISCONNECTED state that reference is released. This means we can not
3155 * rely on that reference to ensure the INVITE session remains for the
3156 * lifetime of our session. To ensure it does we add our own reference
3157 * and release it when our own session goes away, ensuring that the INVITE
3158 * session remains for the lifetime of session.
3159 */
3160
3161#ifdef HAVE_PJSIP_INV_SESSION_REF
3162 if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
3163 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3164 return NULL;
3165 }
3166#endif
3167
3168 pjsip_dlg_inc_session(inv_session->dlg, &session_module);
3169 inv_session->mod_data[session_module.id] = ao2_bump(session);
3170 session->contact = ao2_bump(contact);
3171 session->inv_session = inv_session;
3172
3173 session->dtmf = endpoint->dtmf;
3174 session->moh_passthrough = endpoint->moh_passthrough;
3175
3177 /* Release the ref held by session->inv_session */
3178 ao2_ref(session, -1);
3179 return NULL;
3180 }
3181
3182 session->authentication_challenge_count = 0;
3183
3184 /* Fire session begin handlers */
3186
3187 /* Avoid unnecessary ref manipulation to return a session */
3188 ret_session = session;
3189 session = NULL;
3190 return ret_session;
3191}
@ 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:1744
#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:1953
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1943
@ 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:2092
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.
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
@ AST_SIP_DTMF_AUTO
Definition res_pjsip.h:558
@ AST_SIP_DTMF_INBAND
Definition res_pjsip.h:554
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.
unsigned int moh_passthrough
Definition res_pjsip.h:1140
enum ast_sip_dtmf_mode dtmf
Definition res_pjsip.h:1116
unsigned int faxdetect
Definition res_pjsip.h:1128
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).
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124

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
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, ast_datastore::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(), outgoing_request(), 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 2933 of file res_pjsip_session.c.

2934{
2935 pjmedia_sdp_session *offer;
2937
2938 if (!(offer = create_local_sdp(session->inv_session, session, NULL, 0))) {
2939 pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
2940 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create offer\n");
2941 }
2942
2943 pjsip_inv_set_local_sdp(session->inv_session, offer);
2944 pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
2945#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
2946 if (!session->endpoint->preferred_codec_only) {
2947 pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
2948 }
2949#endif
2950
2951 /*
2952 * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the
2953 * From in the initial INVITE will be wrong but the rest of the messages will be OK.
2954 */
2956
2957 if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
2958 SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
2959 }
2960
2962}
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 3299 of file res_pjsip_session.c.

3302{
3303 const char *uri = NULL;
3304 RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup);
3305 RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
3306 pjsip_timer_setting timer;
3307 pjsip_dialog *dlg;
3308 struct pjsip_inv_session *inv_session;
3310 struct ast_sip_session *ret_session;
3311 SCOPE_ENTER(1, "%s %s Topology: %s\n", ast_sorcery_object_get_id(endpoint), request_user,
3312 ast_str_tmp(256, ast_stream_topology_to_str(req_topology, &STR_TMP)));
3313
3315 request_user, req_topology)) {
3316 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Session creation blocked by supplement\n",
3318 }
3319
3320 /* If no location has been provided use the AOR list from the endpoint itself */
3321 if (location || !contact) {
3322 location = S_OR(location, endpoint->aors);
3323
3325 &found_aor, &found_contact);
3326 if (!found_contact || ast_strlen_zero(found_contact->uri)) {
3327 uri = location;
3328 } else {
3329 uri = found_contact->uri;
3330 }
3331 } else {
3332 uri = contact->uri;
3333 }
3334
3335 /* If we still have no URI to dial fail to create the session */
3336 if (ast_strlen_zero(uri)) {
3337 ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
3339 SCOPE_EXIT_RTN_VALUE(NULL, "No URI\n");
3340 }
3341
3342 if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
3343 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create dialog\n");
3344 }
3345
3346 if (setup_outbound_invite_auth(dlg)) {
3347 pjsip_dlg_terminate(dlg);
3348 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't setup auth\n");
3349 }
3350
3351 if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
3352 pjsip_dlg_terminate(dlg);
3353 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create uac\n");
3354 }
3355#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3356 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3357#endif
3358
3359 pjsip_timer_setting_default(&timer);
3361 timer.sess_expires = endpoint->extensions.timer.sess_expires;
3362 pjsip_timer_init_session(inv_session, &timer);
3363
3364 session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact,
3365 inv_session, NULL);
3366 if (!session) {
3367 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3368 return NULL;
3369 }
3370 session->aor = ao2_bump(found_aor);
3371 session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;
3372
3374
3375 if (ast_stream_topology_get_count(req_topology) > 0) {
3376 /* get joint caps between req_topology and endpoint topology */
3377 int i;
3378
3379 for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {
3380 struct ast_stream *req_stream;
3381 struct ast_stream *clone_stream;
3382
3383 req_stream = ast_stream_topology_get_stream(req_topology, i);
3384
3386 continue;
3387 }
3388
3389 clone_stream = ast_sip_session_create_joint_call_stream(session, req_stream);
3390 if (!clone_stream || ast_stream_get_format_count(clone_stream) == 0) {
3391 ast_stream_free(clone_stream);
3392 continue;
3393 }
3394
3395 if (!session->pending_media_state->topology) {
3396 session->pending_media_state->topology = ast_stream_topology_alloc();
3397 if (!session->pending_media_state->topology) {
3398 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3399 ao2_ref(session, -1);
3400 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create topology\n");
3401 }
3402 }
3403
3404 if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) {
3405 ast_stream_free(clone_stream);
3406 continue;
3407 }
3408 }
3409 }
3410
3411 if (!session->pending_media_state->topology) {
3412 /* Use the configured topology on the endpoint as the pending one */
3413 session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology);
3414 if (!session->pending_media_state->topology) {
3415 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3416 ao2_ref(session, -1);
3417 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't clone topology\n");
3418 }
3419 }
3420
3421 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3422 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3423 /* Since we are not notifying ourselves that the INVITE session is being terminated
3424 * we need to manually drop its reference to session
3425 */
3426 ao2_ref(session, -1);
3427 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't add usage\n");
3428 }
3429
3430 /* Avoid unnecessary ref manipulation to return a session */
3431 ret_session = session;
3432 session = NULL;
3433 SCOPE_EXIT_RTN_VALUE(ret_session);
3434}
static struct ast_timer * timer
Definition chan_iax2.c:401
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:1752
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:962
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition res_pjsip.h:1443
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
int ast_sip_session_check_supplement_create(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, struct ast_stream_topology *req_topology)
Check registered supplements for permission to create an outgoing session.
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:652
@ 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:751
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:939
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:791
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition stream.c:768
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:670
#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:480
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:821
struct ast_stream_topology * topology
Definition res_pjsip.h:1027
struct ast_sip_endpoint_id_configuration id
Definition res_pjsip.h:1106
const ast_string_field aors
Definition res_pjsip.h:1096
struct ast_sip_endpoint_extensions extensions
Definition res_pjsip.h:1098
struct ast_sip_endpoint_media_configuration media
Definition res_pjsip.h:1100
unsigned int sess_expires
Definition res_pjsip.h:808
unsigned int min_se
Definition res_pjsip.h:806

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_check_supplement_create(), 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 3546 of file res_pjsip_session.c.

3547{
3548 pj_time_val delay = { .sec = 60, };
3549 int res;
3550
3551 /* The session should not have an active deferred termination request. */
3552 ast_assert(!session->defer_terminate);
3553
3554 session->defer_terminate = 1;
3555
3556 session->defer_end = 1;
3557 session->ended_while_deferred = 0;
3558
3559 ao2_ref(session, +1);
3560 pj_timer_entry_init(&session->scheduled_termination, 0, session, session_termination_cb);
3561
3562 res = (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
3563 &session->scheduled_termination, &delay) != PJ_SUCCESS) ? -1 : 0;
3564 if (res) {
3565 session->defer_terminate = 0;
3566 ao2_ref(session, -1);
3567 }
3568 return res;
3569}
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
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 3586 of file res_pjsip_session.c.

3587{
3588 if (!session->defer_terminate) {
3589 /* Already canceled or timer fired. */
3590 return;
3591 }
3592
3593 session->defer_terminate = 0;
3594
3595 if (session->terminate_while_deferred) {
3596 /* Complete the termination started by the upper layer. */
3598 }
3599
3600 /* Stop the termination timer if it is still running. */
3602}
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 3604 of file res_pjsip_session.c.

3605{
3606 if (!session->defer_end) {
3607 return;
3608 }
3609
3610 session->defer_end = 0;
3611
3612 if (session->ended_while_deferred) {
3613 /* Complete the session end started by the remote hangup. */
3614 ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3615 session->ended_while_deferred = 0;
3617 }
3618}
#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 3635 of file res_pjsip_session.c.

3636{
3637 pjsip_inv_session *inv_session = session->inv_session;
3638
3639 if (!inv_session) {
3640 return NULL;
3641 }
3642
3643 return inv_session->dlg;
3644}

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_request(), handle_incoming_response(), handle_incoming_sdp(), handle_negotiated_sdp(), handle_negotiated_sdp_session_media(), handle_new_invite_request(), handle_outgoing_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(), set_outstanding_invite_timeout(), 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 3646 of file res_pjsip_session.c.

3647{
3648 pjsip_inv_session *inv_session = session->inv_session;
3649
3650 if (!inv_session) {
3651 return PJSIP_INV_STATE_NULL;
3652 }
3653
3654 return inv_session->state;
3655}

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}
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
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:267

References AST_VECTOR_APPEND, callback(), ast_sip_session_media_read_callback_state::fd, and session.

Referenced by apply_negotiated_sdp_stream(), and 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 callback(), and ast_sip_session_media::write_callback.

Referenced by apply_negotiated_sdp_stream(), and 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[]
#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 * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
struct ast_sip_session_media_state::@280 sessions
Mapping of stream to media sessions.
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:295

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::@281 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:696

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:185

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:746
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition vector.h:653
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition vector.h:599

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:187
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.
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sip_session::@284 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:516

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

2608{
2609 return sip_session_refresh(session, on_request_creation, on_sdp_creation,
2610 on_response, method, generate_new_sdp, media_state, NULL, 0);
2611}
const char * method
Definition res_pjsip.c:1277
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 2613 of file res_pjsip_session.c.

2615{
2616 pjsip_inv_session *inv_session = session->inv_session;
2617 pjmedia_sdp_session *new_answer = NULL;
2618 const pjmedia_sdp_session *previous_offer = NULL;
2620
2621 /* The SDP answer can only be regenerated if it is still pending to be sent */
2622 if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER &&
2623 pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) {
2624 ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n",
2625 ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg)));
2626 SCOPE_EXIT_RTN_VALUE(-1, "Bad negotiation state\n");
2627 }
2628
2629 pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer);
2630 if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2631 /* Transition the SDP negotiator back to when it received the remote offer */
2632 pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0);
2633 pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer);
2634 }
2635
2636 new_answer = create_local_sdp(inv_session, session, previous_offer, 0);
2637 if (!new_answer) {
2638 ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n",
2639 ast_channel_name(session->channel));
2640 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create new SDP\n");
2641 }
2642
2643 if (on_sdp_creation) {
2644 if (on_sdp_creation(session, new_answer)) {
2645 SCOPE_EXIT_RTN_VALUE(-1, "Callback failed\n");
2646 }
2647 }
2648
2649 pjsip_inv_set_sdp_answer(inv_session, new_answer);
2650
2652}

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:337
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611

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(), and 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 2884 of file res_pjsip_session.c.

2885{
2886 if (!session->deferred_reinvite) {
2887 return;
2888 }
2889
2890 if (session->channel) {
2891 pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(),
2892 session->deferred_reinvite, NULL, NULL);
2893 }
2894 pjsip_rx_data_free_cloned(session->deferred_reinvite);
2895 session->deferred_reinvite = NULL;
2896}

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

2929{
2931}
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 2904 of file res_pjsip_session.c.

2906{
2907 pjsip_inv_session *inv_session = session->inv_session;
2908
2909 /* For every request except BYE we disallow sending of the message when
2910 * the session has been disconnected. A BYE request is special though
2911 * because it can be sent again after the session is disconnected except
2912 * with credentials.
2913 */
2914 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED &&
2915 tdata->msg->line.req.method.id != PJSIP_BYE_METHOD) {
2916 return;
2917 }
2918
2919 ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id,
2920 MOD_DATA_ON_RESPONSE, on_response);
2921
2923 pjsip_inv_send_msg(session->inv_session, tdata);
2924
2925 return;
2926}
#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:3130
#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 2654 of file res_pjsip_session.c.

2655{
2656 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
2657 RAII_VAR(struct ast_sip_session *, dlg_session, dlg ? ast_sip_dialog_get_session(dlg) : NULL, ao2_cleanup);
2658 if (!dlg_session) {
2659 /* If the dialog has a session, handle_outgoing_response will be called
2660 from session_on_tx_response. If it does not, call it from here. */
2662 }
2663 pjsip_inv_send_msg(session->inv_session, tdata);
2664 return;
2665}
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 3193 of file res_pjsip_session.c.

3194{
3196}
int ast_taskpool_serializer_suspend(struct ast_taskprocessor *serializer)
Suspend a serializer, causing tasks to be queued until unsuspended.
Definition taskpool.c:1001

References ast_taskpool_serializer_suspend(), and session.

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

3440{
3441 pj_status_t status;
3442 pjsip_tx_data *packet = NULL;
3443 SCOPE_ENTER(1, "%s Response %d\n", ast_sip_session_get_name(session), response);
3444
3445 if (session->defer_terminate) {
3446 session->terminate_while_deferred = 1;
3447 SCOPE_EXIT_RTN("Deferred\n");
3448 }
3449
3450 if (!response) {
3451 response = 603;
3452 }
3453
3454 /* The media sessions need to exist for the lifetime of the underlying channel
3455 * to ensure that anything (such as bridge_native_rtp) has access to them as
3456 * appropriate. Since ast_sip_session_terminate is called by chan_pjsip and other
3457 * places when the session is to be terminated we terminate any existing
3458 * media sessions here.
3459 */
3460 ast_sip_session_media_stats_save(session, session->active_media_state);
3461 SWAP(session->active_media_state, session->pending_media_state);
3462 ast_sip_session_media_state_reset(session->pending_media_state);
3463
3464 switch (session->inv_session->state) {
3465 case PJSIP_INV_STATE_NULL:
3466 if (!session->inv_session->invite_tsx) {
3467 /*
3468 * Normally, it's pjproject's transaction cleanup that ultimately causes the
3469 * final session reference to be released but if both STATE and invite_tsx are NULL,
3470 * we never created a transaction in the first place. In this case, we need to
3471 * do the cleanup ourselves.
3472 */
3473 /* Transfer the inv_session session reference to the session_end_task */
3474 session->inv_session->mod_data[session_module.id] = NULL;
3475 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3477 /*
3478 * session_end_completion will cleanup the final session reference unless
3479 * ast_sip_session_terminate's caller is holding one.
3480 */
3482 } else {
3483 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3484 }
3485 break;
3486 case PJSIP_INV_STATE_CONFIRMED:
3487 if (session->inv_session->invite_tsx) {
3488 ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",
3490 /*
3491 * If this is delayed the only thing that will happen is a BYE request, so
3492 * no response code needs to be stored. Queue the BYE as before, then arm
3493 * a transaction timeout so a malformed/lost final re-INVITE response
3494 * cannot leave the session and RTP state referenced forever.
3495 */
3497 ast_log(LOG_ERROR, "%s: Unable to delay BYE request\n",
3500 session->terminate_on_invite_timeout = 1;
3501 }
3502 break;
3503 }
3504 /* Fall through */
3505 default:
3506 status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet);
3507 if (status == PJ_SUCCESS && packet) {
3508 /* Flush any delayed requests so they cannot overlap this transaction. */
3510
3511 if (packet->msg->type == PJSIP_RESPONSE_MSG) {
3513 } else {
3515 }
3516 }
3517 break;
3518 }
3520}
jack_status_t status
Definition app_jack.c:149
#define SCOPE_EXIT_RTN(...)
static void flush_delayed_requests(struct ast_sip_session *session)
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 int set_outstanding_invite_timeout(struct ast_sip_session *session)
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.
#define SWAP(a, b)
Definition utils.h:256

References ast_debug, ast_log, 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, flush_delayed_requests(), LOG_ERROR, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end(), session_end_completion(), session_module, set_outstanding_invite_timeout(), 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(), and 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 3198 of file res_pjsip_session.c.

3199{
3201}
int ast_taskpool_serializer_unsuspend(struct ast_taskprocessor *serializer)
Unsuspend a serializer, causing tasks to be executed.
Definition taskpool.c:1050

References ast_taskpool_serializer_unsuspend(), 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 3941 of file res_pjsip_session.c.

3942{
3943 pjsip_msg_body *body = rdata->msg_info.msg->body;
3944 pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3945
3946 if (body && ctype_hdr &&
3949 pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3950 while (part != NULL) {
3952 return 1;
3953 }
3954 part = pjsip_multipart_get_next_part(body, part);
3955 }
3956 }
3957 return 0;
3958}
#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:2203
pjsip_media_type pjsip_media_type_multipart_mixed
Definition res_pjsip.c:3913
pjsip_media_type pjsip_media_type_multipart_alternative
Definition res_pjsip.c:3912
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 3917 of file res_pjsip_session.c.

3918{
3919 pjsip_hdr *hdr = part->hdr.next;
3920 static const pj_str_t str_handling_required = {"handling=required", 16};
3921
3922 while (hdr != &part->hdr) {
3923 if (hdr->type == PJSIP_H_OTHER) {
3924 pjsip_generic_string_hdr *generic_hdr = (pjsip_generic_string_hdr*)hdr;
3925
3926 if (!pj_stricmp2(&hdr->name, "Content-Disposition") &&
3927 pj_stristr(&generic_hdr->hvalue, &str_handling_required) &&
3928 !check_sdp_content_type_supported(&part->body->content_type)) {
3929 return 1;
3930 }
3931 }
3932 hdr = hdr->next;
3933 }
3934
3935 return 0;
3936}
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 1608 of file res_pjsip_session.c.

1610{
1611 ao2_ref(session, +1);
1612 if (ast_sip_push_task(session->serializer, cb, session)) {
1613 ao2_ref(session, -1);
1614 }
1615}
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2100

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

4627{
4628 struct ast_sip_session *session = inv->mod_data[session_module.id];
4629 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4630
4631 if (inv->state == PJSIP_INV_STATE_DISCONNECTED && inv->cancelling) {
4632 return 0;
4633 }
4634
4635 if (tsx->status_code != 503 && tsx->status_code != 408) {
4636 return 0;
4637 }
4638
4639 if (!ast_sip_failover_request(tsx->last_tx)) {
4640 return 0;
4641 }
4642
4643 pjsip_inv_uac_restart(inv, PJ_FALSE);
4644 /*
4645 * Bump the ref since it will be on a new transaction and
4646 * we don't want it to go away along with the old transaction.
4647 */
4648 pjsip_tx_data_add_ref(tsx->last_tx);
4650 return 1;
4651}
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:1814

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

3906{
3907 pjsip_media_type app_sdp;
3908 pjsip_media_type_init2(&app_sdp, "application", "sdp");
3909
3910 if (!pjsip_media_type_cmp(content_type, &app_sdp, 0)) {
3911 return 1;
3912 }
3913
3914 return 0;
3915}

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

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

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

2975{
2976 const struct ast_datastore *datastore1 = obj;
2977 const struct ast_datastore *datastore2 = arg;
2978 const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
2979
2980 ast_assert(datastore1->uid != NULL);
2981 ast_assert(uid2 != NULL);
2982
2983 return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
2984}
@ 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 2964 of file res_pjsip_session.c.

2965{
2966 const struct ast_datastore *datastore = obj;
2967 const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
2968
2969 ast_assert(uid != NULL);
2970
2971 return ast_str_hash(uid);
2972}
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 1617 of file res_pjsip_session.c.

1626{
1631
1632 if (!delay) {
1635 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1636 }
1637
1638 if (method == DELAYED_METHOD_BYE || queue_head) {
1639 /* Send BYE as early as possible */
1640 AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1641 } else {
1642 AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1643 }
1645}
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static struct ast_sip_session_delayed_request * delayed_request_alloc(enum delayed_method method, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state)
Structure used for sending delayed requests.
struct ast_sip_session_delayed_request * next
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:150

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

4184{
4185 pj_str_t method;
4186
4187 if (ast_strlen_zero(supplement_method)) {
4188 return PJ_TRUE;
4189 }
4190
4191 pj_cstr(&method, supplement_method);
4192
4193 return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
4194}
static const pjsip_method message_method
Definition res_pjsip.c:1273

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

3659{
3660 int res = -1;
3661 struct ast_party_id id;
3662
3663 ast_party_id_init(&id);
3664 if (!ast_sip_set_id_from_invite(rdata, &id, &session->endpoint->id.self, session->endpoint->id.trust_inbound)) {
3665 ast_copy_string(buf, id.number.str, len);
3666 res = 0;
3667 }
3668 ast_party_id_free(&id);
3669 return res;
3670}
enum queue_result id
Definition app_queue.c:1790
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition channel.c:1798
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:2802
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:340
Number structure.

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

◆ flush_delayed_requests()

static void flush_delayed_requests ( struct ast_sip_session session)
static

Definition at line 1401 of file res_pjsip_session.c.

1402{
1403 struct ast_sip_session_delayed_request *delay;
1404
1405 while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
1406 delayed_request_free(delay);
1407 }
1408}
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)

References AST_LIST_REMOVE_HEAD, delayed_request_free(), ast_sip_session_delayed_request::next, and session.

Referenced by ast_sip_session_terminate(), session_destructor(), and session_inv_on_tsx_state_changed().

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session * generate_session_refresh_sdp ( struct ast_sip_session session)
static

Definition at line 1698 of file res_pjsip_session.c.

1699{
1700 pjsip_inv_session *inv_session = session->inv_session;
1701 const pjmedia_sdp_session *previous_sdp = NULL;
1703
1704 if (inv_session->neg) {
1705 if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
1706 pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
1707 } else {
1708 pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
1709 }
1710 }
1711 SCOPE_EXIT_RTN_VALUE(create_local_sdp(inv_session, session, previous_sdp, 0));
1712}

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

3694{
3695 char cid_num[AST_CHANNEL_NAME];
3696 pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
3697 struct ast_features_pickup_config *pickup_cfg;
3698 const char *pickupexten;
3699
3700 if (!ast_sip_is_allowed_uri(ruri)) {
3702 }
3703
3704 ast_copy_pj_str(session->exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(session->exten));
3705 if (ast_strlen_zero(session->exten)) {
3706 /* Some SIP devices send an empty extension for PLAR: this should map to s */
3707 ast_debug(1, "RURI contains no user portion: defaulting to extension 's'\n");
3708 ast_copy_string(session->exten, "s", sizeof(session->exten));
3709 }
3710
3711 /*
3712 * We may want to match in the dialplan without any user
3713 * options getting in the way.
3714 */
3716
3717 pickup_cfg = ast_get_chan_features_pickup_config(NULL); /* session->channel doesn't exist yet, using NULL */
3718 if (!pickup_cfg) {
3719 ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",
3721 pickupexten = "";
3722 } else {
3723 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
3724 ao2_ref(pickup_cfg, -1);
3725 }
3726
3727 fetch_callerid_num(session, rdata, cid_num, sizeof(cid_num));
3728
3729 /* If there's an overlap_context override specified, use that; otherwise, just use the endpoint's context */
3730
3731 if (!strcmp(session->exten, pickupexten) ||
3732 ast_exists_extension(NULL, S_OR(session->endpoint->overlap_context, session->endpoint->context), session->exten, 1, S_OR(cid_num, NULL))) {
3733 /*
3734 * Save off the INVITE Request-URI in case it is
3735 * needed: CHANNEL(pjsip,request_uri)
3736 */
3737 session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri);
3738
3740 }
3741
3742 /*
3743 * Check for partial match via overlap dialling (if enabled)
3744 */
3745 if (session->endpoint->allow_overlap && (
3746 !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
3747 ast_canmatch_extension(NULL, S_OR(session->endpoint->overlap_context, session->endpoint->context), session->exten, 1, S_OR(cid_num, NULL)))) {
3748 /* Overlap partial match */
3750 }
3751
3753}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define AST_CHANNEL_NAME
Definition channel.h:173
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:2735
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:2750
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:3452
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition res_pjsip.c:3447
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3535
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:2176
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 4535 of file res_pjsip_session.c.

4537{
4538 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
4540 } else {
4541 handle_incoming_response(session, rdata, response_priority);
4542 }
4543
4544 return 0;
4545}
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 4653 of file res_pjsip_session.c.

4655{
4656 pjsip_msg *msg;
4657 ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4658 "request" : "response");
4659
4660
4662 msg = rdata->msg_info.msg;
4663 if (msg->type == PJSIP_REQUEST_MSG
4664 && msg->line.req.method.id == PJSIP_ACK_METHOD
4665 && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
4666 pjsip_tx_data *tdata;
4667
4668 /*
4669 * SDP negotiation failed on an incoming call that delayed
4670 * negotiation and then gave us an invalid SDP answer. We
4671 * need to send a BYE to end the call because of the invalid
4672 * SDP answer.
4673 */
4674 ast_debug(1,
4675 "%s: Ending session due to incomplete SDP negotiation. %s\n",
4677 pjsip_rx_data_get_info(rdata));
4678 if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
4679 && tdata) {
4681 }
4682 }
4683}
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 4464 of file res_pjsip_session.c.

4465{
4466 struct ast_sip_session_supplement *supplement;
4467 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4468 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));
4469
4470 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4471 if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
4472 if (supplement->incoming_request(session, rdata)) {
4473 break;
4474 }
4475 }
4476 }
4477
4479}
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
A supplement to SIP message processing.
struct ast_module *const char * method
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 4515 of file res_pjsip_session.c.

4517{
4518 struct ast_sip_session_supplement *supplement;
4519 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4520 SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4521 status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4522
4523 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4524 if (!(supplement->response_priority & response_priority)) {
4525 continue;
4526 }
4527 if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4528 supplement->incoming_response(session, rdata);
4529 }
4530 }
4531
4533}
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:799
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:197
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:2983
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:1171
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:11188
void ast_channel_internal_fd_clear(struct ast_channel *chan, int which)
#define ast_channel_unlock(chan)
Definition channel.h:2984
@ 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:699
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
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, ast_frame_subclass::integer, LOG_WARNING, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_media_set_handler(), ast_frame::subclass, 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 4104 of file res_pjsip_session.c.

4105{
4106 RAII_VAR(struct ast_sip_endpoint *, endpoint,
4108 pjsip_inv_session *inv_session = NULL;
4109 struct ast_sip_session *session;
4110 struct new_invite invite;
4111 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4112 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4113 SCOPE_ENTER(1, "Request: %s\n", res ? req_uri : "");
4114
4115 ast_assert(endpoint != NULL);
4116
4117 inv_session = pre_session_setup(rdata, endpoint);
4118 if (!inv_session) {
4119 /* pre_session_setup() returns a response on failure */
4120 SCOPE_EXIT_RTN("Failure in pre session setup\n");
4121 }
4122
4123 /*
4124 * Upon a successful pre_session_setup the associated dialog is returned locked
4125 * and with an added reference. Well actually two references. One added when the
4126 * dialog itself was created, and another added when the pjsip invite session was
4127 * created and the dialog was added to it.
4128 *
4129 * In order to ensure the dialog's, and any of its internal attributes, lifetimes
4130 * we'll hold the lock and maintain the reference throughout the entire new invite
4131 * handling process. See ast_sip_create_dialog_uas_locked for more details but,
4132 * basically we do this to make sure a transport failure does not destroy the dialog
4133 * and/or transaction out from underneath us between pjsip calls. Alternatively, we
4134 * could probably release the lock if we needed to, but then we'd have to re-lock and
4135 * check the dialog and transaction prior to every pjsip call.
4136 *
4137 * That means any off nominal/failure paths in this function must remove the associated
4138 * dialog reference added at dialog creation, and remove the lock. As well the
4139 * referenced pjsip invite session must be "cleaned up", which should also then
4140 * remove its reference to the dialog at that time.
4141 *
4142 * Nominally we'll unlock the dialog, and release the reference when all new invite
4143 * process handling has successfully completed.
4144 */
4145
4146 session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
4147 if (!session) {
4148 /* Dialog's lock and reference are removed in new_invite_initial_answer */
4149 if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4150 /* Terminate the session if it wasn't done in the answer */
4151 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
4152 }
4153 SCOPE_EXIT_RTN("Couldn't create session\n");
4154 }
4155 session->call_direction = AST_SIP_SESSION_INCOMING_CALL;
4156
4157 /*
4158 * The current thread is supposed be the session serializer to prevent
4159 * any initial INVITE retransmissions from trying to setup the same
4160 * call again.
4161 */
4163
4164 invite.session = session;
4165 invite.rdata = rdata;
4166 new_invite(&invite);
4167
4168 /*
4169 * The dialog lock and reference added at dialog creation time must be
4170 * maintained throughout the new invite process. Since we're pretty much
4171 * done at this point with things it's safe to go ahead and remove the lock
4172 * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
4173 *
4174 * Note, any future functionality added that does work using the dialog must
4175 * be done before this.
4176 */
4177 pjsip_dlg_dec_lock(inv_session->dlg);
4178
4179 SCOPE_EXIT("Request: %s Session: %s\n", req_uri, ast_sip_session_get_name(session));
4180 ao2_ref(session, -1);
4181}
#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 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:1067
pjsip_rx_data * rdata
INVITE request itself.
int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
Am I the given taskprocessor's current task.

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

4548{
4549 struct ast_sip_session_supplement *supplement;
4550 struct pjsip_request_line req = tdata->msg->line.req;
4551 SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4552 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4553
4554 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4555
4556 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4557 if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
4558 supplement->outgoing_request(session, tdata);
4559 }
4560 }
4562}
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 4564 of file res_pjsip_session.c.

4565{
4566 struct ast_sip_session_supplement *supplement;
4567 struct pjsip_status_line status = tdata->msg->line.status;
4568 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
4569 SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4570 (int) pj_strlen(&cseq->method.name),
4571 pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
4572 pj_strbuf(&status.reason));
4573
4574
4575 if (!cseq) {
4576 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4578 }
4579
4580 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4581
4582 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4583 if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
4584 supplement->outgoing_response(session, tdata);
4585 }
4586 }
4587
4589}
#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 4481 of file res_pjsip_session.c.

4482{
4483 struct ast_sip_session_supplement *iter;
4484
4485 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4486 if (iter->session_begin) {
4487 iter->session_begin(session);
4488 }
4489 }
4490}
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 4492 of file res_pjsip_session.c.

4493{
4494 struct ast_sip_session_supplement *iter;
4495
4496 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4497 if (iter->session_destroy) {
4498 iter->session_destroy(session);
4499 }
4500 }
4501}
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 4503 of file res_pjsip_session.c.

4504{
4505 struct ast_sip_session_supplement *iter;
4506
4507 /* Session is dead. Notify the supplements. */
4508 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4509 if (iter->session_end) {
4510 iter->session_end(session);
4511 }
4512 }
4513}
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 4196 of file res_pjsip_session.c.

4197{
4198 struct ast_sip_session_supplement *supplement;
4199 struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
4200
4201 if (!session) {
4202 return PJ_FALSE;
4203 }
4204
4205 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4206 if (does_method_match(&method->name, supplement->method)) {
4207 return PJ_TRUE;
4208 }
4209 }
4210 return PJ_FALSE;
4211}

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

1565{
1566 struct ast_sip_session *session = vsession;
1567 int res;
1569
1570 if (session->inv_session->invite_tsx) {
1571 /*
1572 * INVITE transaction still active. Let it send
1573 * the collision re-INVITE when it terminates.
1574 */
1575 ao2_ref(session, -1);
1576 res = 0;
1577 } else {
1579 }
1580
1582}
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 1466 of file res_pjsip_session.c.

1467{
1468 struct ast_sip_session *session = vsession;
1469 struct ast_sip_session_delayed_request *delay;
1470 int found = 0;
1471 int res = 0;
1473
1474 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1475 switch (delay->method) {
1477 break;
1480 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1481 delayed_method2str(delay->method));
1482 res = send_delayed_request(session, delay);
1483 delayed_request_free(delay);
1484 if (!res) {
1485 found = 1;
1486 }
1487 break;
1488 case DELAYED_METHOD_BYE:
1489 /* A BYE is pending so don't bother anymore. */
1490 found = 1;
1491 break;
1492 }
1493 if (found) {
1494 break;
1495 }
1496 }
1498
1499 ao2_ref(session, -1);
1501}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
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 1513 of file res_pjsip_session.c.

1514{
1515 struct ast_sip_session *session = vsession;
1516 struct ast_sip_session_delayed_request *delay;
1517 int found = 0;
1518 int res = 0;
1519 int timer_running;
1521
1522 /* re-INVITE collision timer running? */
1523 timer_running = pj_timer_entry_running(&session->rescheduled_reinvite);
1524
1525 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1526 switch (delay->method) {
1528 if (!timer_running) {
1529 found = 1;
1530 }
1531 break;
1533 case DELAYED_METHOD_BYE:
1534 found = 1;
1535 break;
1536 }
1537 if (found) {
1539 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1540 delayed_method2str(delay->method));
1541 res = send_delayed_request(session, delay);
1542 delayed_request_free(delay);
1543 if (!res) {
1544 break;
1545 }
1546 }
1547 }
1549
1550 ao2_ref(session, -1);
1552}

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

1830{
1831 int stream_count = ast_stream_topology_get_count(state->topology);
1832 int session_count = AST_VECTOR_SIZE(&state->sessions);
1833 int i;
1834 int res = 0;
1835 SCOPE_ENTER(3, "%s: Topology: %s\n", session_name,
1836 ast_str_tmp(256, ast_stream_topology_to_str(state->topology, &STR_TMP)));
1837
1838 if (session_count != stream_count) {
1839 SCOPE_EXIT_RTN_VALUE(0, "%s: %d media sessions but %d streams\n", session_name,
1840 session_count, stream_count);
1841 }
1842
1843 for (i = 0; i < stream_count; i++) {
1844 struct ast_sip_session_media *media = NULL;
1845 struct ast_stream *stream = ast_stream_topology_get_stream(state->topology, i);
1846 const char *stream_name = NULL;
1847 int j;
1848 SCOPE_ENTER(4, "%s: Checking stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1849
1850 if (!stream) {
1851 SCOPE_EXIT_EXPR(goto end, "%s: stream %d is null\n", session_name, i);
1852 }
1853 stream_name = ast_stream_get_name(stream);
1854
1855 for (j = 0; j < stream_count; j++) {
1856 struct ast_stream *possible_dup = ast_stream_topology_get_stream(state->topology, j);
1857 if (j == i || !possible_dup) {
1858 continue;
1859 }
1860 if (!STREAM_REMOVED(stream) && ast_strings_equal(stream_name, GET_STREAM_NAME_SAFE(possible_dup))) {
1861 SCOPE_EXIT_EXPR(goto end, "%s: stream %i %s is duplicated to %d\n", session_name,
1862 i, stream_name, j);
1863 }
1864 }
1865
1866 media = AST_VECTOR_GET(&state->sessions, i);
1867 if (!media) {
1868 SCOPE_EXIT_EXPR(continue, "%s: media %d is null\n", session_name, i);
1869 }
1870
1871 for (j = 0; j < session_count; j++) {
1872 struct ast_sip_session_media *possible_dup = AST_VECTOR_GET(&state->sessions, j);
1873 if (j == i || !possible_dup) {
1874 continue;
1875 }
1876 if (!ast_strlen_zero(media->label) && !ast_strlen_zero(possible_dup->label)
1877 && ast_strings_equal(media->label, possible_dup->label)) {
1878 SCOPE_EXIT_EXPR(goto end, "%s: media %d %s is duplicated to %d\n", session_name,
1879 i, media->label, j);
1880 }
1881 }
1882
1883 if (media->stream_num != i) {
1884 SCOPE_EXIT_EXPR(goto end, "%s: media %d has stream_num %d\n", session_name,
1885 i, media->stream_num);
1886 }
1887
1888 if (media->type != ast_stream_get_type(stream)) {
1889 SCOPE_EXIT_EXPR(goto end, "%s: media %d has type %s but stream has type %s\n", stream_name,
1891 }
1892 SCOPE_EXIT("%s: Done with stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1893 }
1894
1895 res = 1;
1896end:
1897 SCOPE_EXIT_RTN_VALUE(res, "%s: %s\n", session_name, res ? "Valid" : "NOT Valid");
1898}
static int session_count
Definition http.c:110
#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 6199 of file res_pjsip_session.c.

6200{
6201 pjsip_endpoint *endpt;
6202
6205 }
6206 if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
6208 }
6213 if (!sdp_handlers) {
6215 }
6217 pjsip_inv_usage_init(endpt, &inv_callback);
6218 pjsip_100rel_init_module(endpt);
6219 pjsip_timer_init_module(endpt);
6222 }
6225
6227
6229#ifdef TEST_FRAMEWORK
6230 AST_TEST_REGISTER(test_resolve_refresh_media_states);
6231#endif
6233}
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition module.h:478
@ 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:111
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:2126
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition sorcery.c:1808
struct ast_module * self
Definition module.h:356
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:452

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

3961{
3962 pjsip_tx_data *tdata = NULL;
3963 pjsip_timer_setting timer;
3964 pjsip_rdata_sdp_info *sdp_info;
3965 pjmedia_sdp_session *local = NULL;
3966 char buffer[AST_SOCKADDR_BUFLEN];
3967 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(invite->session));
3968
3969
3970 /* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
3971 * so that we will be notified so we can destroy the session properly
3972 */
3973
3974 if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
3975 ast_trace_log(-1, LOG_ERROR, "%s: Session already DISCONNECTED [reason=%d (%s)]\n",
3977 invite->session->inv_session->cause,
3978 pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
3980 }
3981
3982 switch (get_destination(invite->session, invite->rdata)) {
3984 /* Things worked. Keep going */
3985 break;
3987 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - unsupported uri\n",
3989 invite->rdata->tp_info.transport->type_name,
3990 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3991 invite->session->exten);
3992 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
3993 ast_sip_session_send_response(invite->session, tdata);
3994 } else {
3995 pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
3996 }
3997 goto end;
3999 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - partial match\n",
4001 invite->rdata->tp_info.transport->type_name,
4002 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4003 invite->session->exten);
4004
4005 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) {
4006 ast_sip_session_send_response(invite->session, tdata);
4007 } else {
4008 pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE);
4009 }
4010 goto end;
4012 default:
4013 ast_trace_log(-1, LOG_NOTICE, "%s: Call (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",
4015 invite->rdata->tp_info.transport->type_name,
4016 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4017 invite->session->exten,
4018 invite->session->endpoint->context);
4019
4020 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) {
4021 ast_sip_session_send_response(invite->session, tdata);
4022 } else {
4023 pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
4024 }
4025 goto end;
4026 };
4027
4028 if (check_content_disposition(invite->rdata)) {
4029 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 415, NULL, NULL, &tdata) == PJ_SUCCESS) {
4030 ast_sip_session_send_response(invite->session, tdata);
4031 } else {
4032 pjsip_inv_terminate(invite->session->inv_session, 415, PJ_TRUE);
4033 }
4034 goto end;
4035 }
4036
4037 pjsip_timer_setting_default(&timer);
4038 timer.min_se = invite->session->endpoint->extensions.timer.min_se;
4039 timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires;
4040 pjsip_timer_init_session(invite->session->inv_session, &timer);
4041
4042 /*
4043 * At this point, we've verified what we can that won't take awhile,
4044 * so let's go ahead and send a 100 Trying out to stop any
4045 * retransmissions.
4046 */
4047 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
4048 if (tdata) {
4049 pjsip_inv_send_msg(invite->session->inv_session, tdata);
4050 } else {
4051 pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
4052 }
4053 goto end;
4054 }
4055
4056 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' sending 100 Trying\n",
4058 invite->rdata->tp_info.transport->type_name,
4059 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4060 invite->session->exten);
4061 ast_sip_session_send_response(invite->session, tdata);
4062
4063 sdp_info = pjsip_rdata_get_sdp_info(invite->rdata);
4064 if (sdp_info && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
4065 if (handle_incoming_sdp(invite->session, sdp_info->sdp)) {
4066 tdata = NULL;
4067 if (pjsip_inv_end_session(invite->session->inv_session, 488, NULL, &tdata) == PJ_SUCCESS
4068 && tdata) {
4069 ast_sip_session_send_response(invite->session, tdata);
4070 }
4071 goto end;
4072 }
4073 /* We are creating a local SDP which is an answer to their offer */
4074 local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp, 0);
4075 } else {
4076 /* We are creating a local SDP which is an offer */
4077 local = create_local_sdp(invite->session->inv_session, invite->session, NULL, 0);
4078 }
4079
4080 /* If we were unable to create a local SDP terminate the session early, it won't go anywhere */
4081 if (!local) {
4082 tdata = NULL;
4083 if (pjsip_inv_end_session(invite->session->inv_session, 500, NULL, &tdata) == PJ_SUCCESS
4084 && tdata) {
4085 ast_sip_session_send_response(invite->session, tdata);
4086 }
4087 goto end;
4088 }
4089
4090 pjsip_inv_set_local_sdp(invite->session->inv_session, local);
4091 pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
4092#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
4093 if (!invite->session->endpoint->preferred_codec_only) {
4094 pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE);
4095 }
4096#endif
4097
4098 handle_incoming_request(invite->session, invite->rdata);
4099
4100end:
4102}
#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:1150
const ast_string_field context
Definition res_pjsip.h:1096
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.

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

3779{
3780 pjsip_tx_data *tdata = NULL;
3781 int res = 0;
3782
3783 if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3784 if (pjsip_inv_initial_answer(
3785 inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
3786
3787 pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
3788 res = -1;
3789 } else {
3790 pjsip_inv_send_msg(inv_session, tdata);
3791 }
3792 }
3793
3794 if (answer_code >= 300) {
3795 /*
3796 * A session is ending. The dialog has a reference that needs to be
3797 * removed and holds a lock that needs to be unlocked before returning.
3798 */
3799 pjsip_dlg_dec_lock(inv_session->dlg);
3800 }
3801
3802 return res;
3803}

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

3214{
3215 pjsip_transaction *tsx;
3216 pjsip_dialog *dlg;
3217 pjsip_inv_session *inv;
3218 pjsip_tx_data *tdata;
3219 struct ast_sip_session *session;
3220
3221 if (rdata->msg_info.msg->line.status.code != 401
3222 && rdata->msg_info.msg->line.status.code != 407) {
3223 /* Doesn't pertain to us. Move on */
3224 return PJ_FALSE;
3225 }
3226
3227 tsx = pjsip_rdata_get_tsx(rdata);
3228 dlg = pjsip_rdata_get_dlg(rdata);
3229 if (!dlg || !tsx) {
3230 return PJ_FALSE;
3231 }
3232
3233 if (tsx->method.id != PJSIP_INVITE_METHOD) {
3234 /* Not an INVITE that needs authentication */
3235 return PJ_FALSE;
3236 }
3237
3238 inv = pjsip_dlg_get_inv_session(dlg);
3239 session = inv->mod_data[session_module.id];
3240
3241 if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {
3242 /*
3243 * We cannot handle reINVITE authentication at this
3244 * time because the reINVITE transaction is still in
3245 * progress.
3246 */
3247 ast_debug(3, "%s: A reINVITE is being challenged\n", ast_sip_session_get_name(session));
3248 return PJ_FALSE;
3249 }
3250 ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));
3251
3252 if (++session->authentication_challenge_count > MAX_RX_CHALLENGES) {
3253 ast_debug(3, "%s: Initial INVITE reached maximum number of auth attempts.\n", ast_sip_session_get_name(session));
3254 return PJ_FALSE;
3255 }
3256
3257 if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata,
3258 tsx->last_tx, &tdata)) {
3259 return PJ_FALSE;
3260 }
3261
3262 /*
3263 * Restart the outgoing initial INVITE transaction to deal
3264 * with authentication.
3265 */
3266 pjsip_inv_uac_restart(inv, PJ_FALSE);
3267
3269 return PJ_TRUE;
3270}
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:208
#define MAX_RX_CHALLENGES
Definition res_pjsip.h:108

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

3825{
3826 pjsip_tx_data *tdata;
3827 pjsip_dialog *dlg;
3828 pjsip_inv_session *inv_session;
3829 unsigned int options = endpoint->extensions.flags;
3830 const pj_str_t STR_100REL = { "100rel", 6};
3831 unsigned int i;
3832 pj_status_t dlg_status = PJ_EUNKNOWN;
3833
3834 /*
3835 * If 100rel is set to "peer_supported" on the endpoint and the peer indicated support for 100rel
3836 * in the Supported header, send 1xx responses reliably by adding PJSIP_INV_REQUIRE_100REL to pjsip_inv_options flags.
3837 */
3838 if (endpoint->rel100 == AST_SIP_100REL_PEER_SUPPORTED && rdata->msg_info.supported != NULL) {
3839 for (i = 0; i < rdata->msg_info.supported->count; ++i) {
3840 if (pj_stricmp(&rdata->msg_info.supported->values[i], &STR_100REL) == 0) {
3841 options |= PJSIP_INV_REQUIRE_100REL;
3842 break;
3843 }
3844 }
3845 }
3846
3847 if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
3848 if (tdata) {
3849 if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
3850 pjsip_tx_data_dec_ref(tdata);
3851 }
3852 } else {
3853 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3854 }
3855 return NULL;
3856 }
3857
3858 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, &dlg_status);
3859 if (!dlg) {
3860 if (dlg_status != PJ_EEXISTS) {
3861 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3862 }
3863 return NULL;
3864 }
3865
3866 /*
3867 * The returned dialog holds a lock and has a reference added. Any paths where the
3868 * dialog invite session is not returned must unlock the dialog and remove its reference.
3869 */
3870
3871 if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
3872 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3873 /*
3874 * The acquired dialog holds a lock, and a reference. Since the dialog is not
3875 * going to be returned here it must first be unlocked and de-referenced. This
3876 * must be done prior to calling dialog termination.
3877 */
3878 pjsip_dlg_dec_lock(dlg);
3879 pjsip_dlg_terminate(dlg);
3880 return NULL;
3881 }
3882
3883#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3884 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3885#endif
3886 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3887 /* Dialog's lock and a reference are removed in new_invite_initial_answer */
3888 new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE);
3889 /* Remove 2nd reference added at inv_session creation */
3890 pjsip_dlg_dec_session(inv_session->dlg, &session_module);
3891 return NULL;
3892 }
3893
3894 return inv_session;
3895}
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:1190
@ AST_SIP_100REL_PEER_SUPPORTED
Definition res_pjsip.h:539
enum ast_sip_100rel_mode rel100
Definition res_pjsip.h:1178
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.
struct sdp_handler_list::@506 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 4335 of file res_pjsip_session.c.

4336{
4337 pjsip_inv_session *inv = session->inv_session;
4338 pj_time_val tv;
4339 struct ast_sip_session_media_state *pending_media_state = NULL;
4340 struct ast_sip_session_media_state *active_media_state = NULL;
4341 const char *session_name = ast_sip_session_get_name(session);
4342 int use_pending = 0;
4343 int use_active = 0;
4344
4345 SCOPE_ENTER(3, "%s\n", session_name);
4346
4347 /*
4348 * If the two media state topologies are the same this means that the session refresh request
4349 * did not specify a desired topology, so it does not care. If that is the case we don't even
4350 * pass one in here resulting in the current topology being used. It's possible though that
4351 * either one of the topologies could be NULL so we have to test for that before we check for
4352 * equality.
4353 */
4354
4355 /* We only want to clone a media state if its topology is not null */
4356 use_pending = session->pending_media_state->topology != NULL;
4357 use_active = session->active_media_state->topology != NULL;
4358
4359 /*
4360 * If both media states have topologies, we can test for equality. If they're equal we're not going to
4361 * clone either states.
4362 */
4363 if (use_pending && use_active && ast_stream_topology_equal(session->active_media_state->topology, session->pending_media_state->topology)) {
4364 use_pending = 0;
4365 use_active = 0;
4366 }
4367
4368 if (use_pending) {
4369 pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);
4370 if (!pending_media_state) {
4371 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
4372 }
4373 }
4374
4375 if (use_active) {
4376 active_media_state = ast_sip_session_media_state_clone(session->active_media_state);
4377 if (!active_media_state) {
4378 ast_sip_session_media_state_free(pending_media_state);
4379 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
4380 }
4381 }
4382
4383 if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,
4384 active_media_state, 1)) {
4385 ast_sip_session_media_state_free(pending_media_state);
4386 ast_sip_session_media_state_free(active_media_state);
4387 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
4388 }
4389
4390 if (pj_timer_entry_running(&session->rescheduled_reinvite)) {
4391 /* Timer already running. Something weird is going on. */
4392 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
4393 }
4394
4395 tv.sec = 0;
4396 if (inv->role == PJSIP_ROLE_UAC) {
4397 tv.msec = 2100 + ast_random() % 2000;
4398 } else {
4399 tv.msec = ast_random() % 2000;
4400 }
4401 pj_timer_entry_init(&session->rescheduled_reinvite, 0, session, resend_reinvite);
4402
4403 ao2_ref(session, +1);
4404 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
4405 &session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {
4406 ao2_ref(session, -1);
4407 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
4408 }
4409
4411}
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 4314 of file res_pjsip_session.c.

4315{
4316 struct ast_sip_session *session = entry->user_data;
4317
4318 ast_debug(3, "%s: re-INVITE collision timer expired.\n",
4320
4321 if (AST_LIST_EMPTY(&session->delayed_requests)) {
4322 /* No delayed request pending, so just return */
4323 ao2_ref(session, -1);
4324 return;
4325 }
4327 /*
4328 * Uh oh. We now have nothing in the foreseeable future
4329 * to trigger sending the delayed requests.
4330 */
4331 ao2_ref(session, -1);
4332 }
4333}
static int invite_collision_timeout(void *vsession)

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

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

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

2687{
2688 int i;
2689
2690 if (!session->pending_media_state->topology) {
2691 session->pending_media_state->topology = ast_stream_topology_alloc();
2692 if (!session->pending_media_state->topology) {
2693 return -1;
2694 }
2695 }
2696
2697 for (i = 0; i < sdp->media_count; ++i) {
2698 /* See if there are registered handlers for this media stream type */
2699 char media[20];
2701 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
2702 struct ast_stream *existing_stream = NULL;
2703 struct ast_stream *stream;
2704 enum ast_media_type type;
2705 struct ast_sip_session_media *session_media = NULL;
2707 pjmedia_sdp_media *remote_stream = sdp->media[i];
2708
2709 /* We need a null-terminated version of the media string */
2710 ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
2711
2712 if (session->active_media_state->topology &&
2713 (i < ast_stream_topology_get_count(session->active_media_state->topology))) {
2714 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
2715 }
2716
2718 stream = ast_stream_alloc(existing_stream ? ast_stream_get_name(existing_stream) : ast_codec_media_type2str(type), type);
2719 if (!stream) {
2720 return -1;
2721 }
2722
2723 /* As this is only called on an incoming SDP offer before processing it is not possible
2724 * for streams and their media sessions to exist.
2725 */
2726 if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
2727 ast_stream_free(stream);
2728 return -1;
2729 }
2730
2731 if (existing_stream) {
2732 const char *stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
2733
2734 if (!ast_strlen_zero(stream_label)) {
2735 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
2736 }
2737 }
2738
2739 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
2740 if (!session_media) {
2741 return -1;
2742 }
2743
2744 /* For backwards compatibility with the core the default audio stream is always sendrecv */
2745 if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
2746 if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
2747 /* Stream state reflects our state of a stream, so in the case of
2748 * sendonly and recvonly we store the opposite since that is what ours
2749 * is.
2750 */
2752 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
2754 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
2756 } else {
2758 }
2759 } else {
2761 }
2762
2763 if (session_media->handler) {
2764 handler = session_media->handler;
2765 if (handler->defer_incoming_sdp_stream) {
2766 res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2767 sdp->media[i]);
2768 switch (res) {
2770 break;
2772 return 0;
2774 break;
2776 return 1;
2777 }
2778 }
2779 /* Handled by this handler. Move to the next stream */
2780 continue;
2781 }
2782
2783 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
2784 if (!handler_list) {
2785 ast_debug(3, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
2786 continue;
2787 }
2788 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
2789 if (handler == session_media->handler) {
2790 continue;
2791 }
2792 if (!handler->defer_incoming_sdp_stream) {
2793 continue;
2794 }
2795 res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2796 sdp->media[i]);
2797 switch (res) {
2799 continue;
2801 session_media_set_handler(session_media, handler);
2802 return 0;
2804 /* Handled by this handler. */
2805 session_media_set_handler(session_media, handler);
2806 break;
2808 /* Handled by this handler. */
2809 session_media_set_handler(session_media, handler);
2810 return 1;
2811 }
2812 /* Move to the next stream */
2813 break;
2814 }
2815 }
2816 return 0;
2817}
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
enum ast_sip_session_sdp_stream_defer(* defer_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
Determine whether a stream requires that the re-invite be deferred. If a stream can not be immediatel...

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_sdp_handler::defer_incoming_sdp_stream, 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 1418 of file res_pjsip_session.c.

1419{
1420 int res;
1421 SCOPE_ENTER(3, "%s: sending delayed %s request\n",
1423 delayed_method2str(delay->method));
1424
1425 switch (delay->method) {
1428 delay->on_sdp_creation, delay->on_response,
1430 delay->active_media_state, 1);
1431 /* Ownership of media state transitions to ast_sip_session_refresh */
1432 delay->pending_media_state = NULL;
1433 delay->active_media_state = NULL;
1437 delay->on_sdp_creation, delay->on_response,
1439 delay->active_media_state, 1);
1440 /* Ownership of media state transitions to ast_sip_session_refresh */
1441 delay->pending_media_state = NULL;
1442 delay->active_media_state = NULL;
1444 case DELAYED_METHOD_BYE:
1445 /* The delayed BYE is being sent now; timeout cleanup is no longer needed. */
1446 session->terminate_on_invite_timeout = 0;
1448 SCOPE_EXIT_RTN_VALUE(0, "%s: Terminating session on delayed BYE\n", ast_sip_session_get_name(session));
1449 }
1450
1451 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",
1453 delayed_method2str(delay->method), delay->method);
1454}
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition res_pjsip.h:719
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition res_pjsip.h:717

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

2987{
2988 struct ast_sip_session *session = obj;
2989
2990#ifdef TEST_FRAMEWORK
2991 /* We dup the endpoint ID in case the endpoint gets freed out from under us */
2992 const char *endpoint_name = session->endpoint ?
2993 ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>";
2994#endif
2995
2996 ast_debug(3, "%s: Destroying SIP session\n", ast_sip_session_get_name(session));
2997
2998 ast_test_suite_event_notify("SESSION_DESTROYING",
2999 "Endpoint: %s\r\n"
3000 "AOR: %s\r\n"
3001 "Contact: %s"
3002 , endpoint_name
3003 , session->aor ? ast_sorcery_object_get_id(session->aor) : "<none>"
3005 );
3006
3007 /* fire session destroy handler */
3009
3010 /* remove all registered supplements */
3012 AST_LIST_HEAD_DESTROY(&session->supplements);
3013
3014 /* remove all saved media stats */
3015 AST_VECTOR_RESET(&session->media_stats, ast_free);
3016 AST_VECTOR_FREE(&session->media_stats);
3017
3019 ao2_cleanup(session->datastores);
3020 ast_sip_session_media_state_free(session->active_media_state);
3021 ast_sip_session_media_state_free(session->pending_media_state);
3022
3025 ao2_cleanup(session->endpoint);
3026 ao2_cleanup(session->aor);
3027 ao2_cleanup(session->contact);
3028 ao2_cleanup(session->direct_media_cap);
3029
3030 ast_dsp_free(session->dsp);
3031
3032 if (session->inv_session) {
3033 struct pjsip_dialog *dlg = session->inv_session->dlg;
3034
3035 /* The INVITE session uses the dialog pool for memory, so we need to
3036 * decrement its reference first before that of the dialog.
3037 */
3038
3039#ifdef HAVE_PJSIP_INV_SESSION_REF
3040 pjsip_inv_dec_ref(session->inv_session);
3041#endif
3042 pjsip_dlg_dec_session(dlg, &session_module);
3043 }
3044
3045 ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name);
3046}
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1968
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
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_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, flush_delayed_requests(), handle_session_destroy(), session, and session_module.

Referenced by ast_sip_session_alloc().

◆ session_end()

static int session_end ( void *  vsession)
static

Definition at line 4591 of file res_pjsip_session.c.

4592{
4593 struct ast_sip_session *session = vsession;
4594
4595 /* Stop the scheduled termination */
4597
4598 /* Session is dead. Notify the supplements. */
4600
4601 return 0;
4602}
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 4614 of file res_pjsip_session.c.

4615{
4616 struct ast_sip_session *session = vsession;
4617
4618 ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL);
4619 ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL);
4620
4621 /* Now we can release the ref that was held by session->inv_session */
4623 return 0;
4624}

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

4772{
4773 struct ast_sip_session *session;
4774
4775 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
4776 return 0;
4777 }
4778
4779 /*
4780 * We are locking because ast_sip_dialog_get_session() needs
4781 * the dialog locked to get the session by other threads.
4782 */
4783 pjsip_dlg_inc_lock(inv->dlg);
4784 session = inv->mod_data[id];
4785 inv->mod_data[id] = NULL;
4786 pjsip_dlg_dec_lock(inv->dlg);
4787
4788 /*
4789 * Pass the session ref held by session->inv_session to
4790 * session_end_completion().
4791 */
4792 if (session
4794 /* Do it anyway even though this is not the right thread. */
4796 }
4797
4798 return 1;
4799}

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

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

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

4767{
4768 /* XXX STUB */
4769}

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

5520{
5521 struct ast_sip_session *session;
5522 const pjsip_sip_uri *uri;
5523
5524 if (ast_shutdown_final()) {
5525 return PJSIP_REDIRECT_STOP;
5526 }
5527
5528 session = inv->mod_data[session_module.id];
5529 if (!session || !session->channel) {
5530 return PJSIP_REDIRECT_STOP;
5531 }
5532
5533 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_PJSIP) {
5534 return PJSIP_REDIRECT_ACCEPT;
5535 }
5536
5537 if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
5538 return PJSIP_REDIRECT_STOP;
5539 }
5540
5542
5543 uri = pjsip_uri_get_uri(target);
5544
5545 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
5547
5548 ast_copy_pj_str(exten, &uri->user, sizeof(exten));
5549
5550 /*
5551 * We may want to match in the dialplan without any user
5552 * options getting in the way.
5553 */
5555
5556 ast_channel_call_forward_set(session->channel, exten);
5557 } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
5558 char target_uri[PJSIP_MAX_URL_SIZE];
5559 /* PJSIP/ + endpoint length + / + max URL size */
5560 char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
5561
5562 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
5563 sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
5564 ast_channel_call_forward_set(session->channel, forward);
5565 }
5566
5567 return PJSIP_REDIRECT_STOP;
5568}
#define AST_MAX_EXTENSION
Definition channel.h:134
@ AST_SIP_REDIRECT_URI_CORE
Definition res_pjsip.h:750
@ AST_SIP_REDIRECT_URI_PJSIP
Definition res_pjsip.h:752
@ AST_SIP_REDIRECT_USER
Definition res_pjsip.h:748
@ 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 5326 of file res_pjsip_session.c.

5327{
5328 struct ast_sip_session *session = inv->mod_data[session_module.id];
5329 pjmedia_sdp_session *answer;
5331
5332 if (ast_shutdown_final()) {
5333 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5334 }
5335
5336 session = inv->mod_data[session_module.id];
5337 if (handle_incoming_sdp(session, offer)) {
5338 ast_sip_session_media_state_reset(session->pending_media_state);
5339 SCOPE_EXIT_RTN("%s: handle_incoming_sdp failed\n", ast_sip_session_get_name(session));
5340 }
5341
5342 if ((answer = create_local_sdp(inv, session, offer, 0))) {
5343 pjsip_inv_set_sdp_answer(inv, answer);
5344 SCOPE_EXIT_RTN("%s: Set SDP answer\n", ast_sip_session_get_name(session));
5345 }
5346 SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));
5347}

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

4686{
4687 pjsip_event_id_e type;
4688 struct ast_sip_session *session = inv->mod_data[session_module.id];
4689 SCOPE_ENTER(1, "%s Event: %s Inv State: %s\n", ast_sip_session_get_name(session),
4690 pjsip_event_str(e->type), pjsip_inv_state_name(inv->state));
4691
4692 if (ast_shutdown_final()) {
4693 SCOPE_EXIT_RTN("Shutting down\n");
4694 }
4695
4696 if (e) {
4697 print_debug_details(inv, NULL, e);
4698 type = e->type;
4699 } else {
4700 type = PJSIP_EVENT_UNKNOWN;
4701 }
4702
4703 session = inv->mod_data[session_module.id];
4704 if (!session) {
4705 SCOPE_EXIT_RTN("No session\n");
4706 }
4707
4708 switch(type) {
4709 case PJSIP_EVENT_TX_MSG:
4710 break;
4711 case PJSIP_EVENT_RX_MSG:
4712 handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);
4713 break;
4714 case PJSIP_EVENT_TSX_STATE:
4715 ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),
4716 pjsip_event_str(e->body.tsx_state.type));
4717 /* Transaction state changes are prompted by some other underlying event. */
4718 switch(e->body.tsx_state.type) {
4719 case PJSIP_EVENT_TX_MSG:
4720 break;
4721 case PJSIP_EVENT_RX_MSG:
4722 if (!check_request_status(inv, e)) {
4723 handle_incoming_before_media(inv, session, e->body.tsx_state.src.rdata);
4724 }
4725 break;
4726 case PJSIP_EVENT_TRANSPORT_ERROR:
4727 case PJSIP_EVENT_TIMER:
4728 /*
4729 * Check the request status on transport error or timeout. A transport
4730 * error can occur when a TCP socket closes and that can be the result
4731 * of a 503. Also we may need to failover on a timeout (408).
4732 */
4733 check_request_status(inv, e);
4734 break;
4735 case PJSIP_EVENT_USER:
4736 case PJSIP_EVENT_UNKNOWN:
4737 case PJSIP_EVENT_TSX_STATE:
4738 /* Inception? */
4739 break;
4740 }
4741 break;
4742 case PJSIP_EVENT_TRANSPORT_ERROR:
4743 case PJSIP_EVENT_TIMER:
4744 case PJSIP_EVENT_UNKNOWN:
4745 case PJSIP_EVENT_USER:
4746 default:
4747 break;
4748 }
4749
4750 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
4751 if (session->defer_end) {
4752 ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));
4753 session->ended_while_deferred = 1;
4754 SCOPE_EXIT_RTN("Deferring\n");
4755 }
4756
4757 if (ast_sip_push_task(session->serializer, session_end, session)) {
4758 /* Do it anyway even though this is not the right thread. */
4760 }
4761 }
4762
4764}
#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 4801 of file res_pjsip_session.c.

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

4270{
4271 pj_status_t handled = PJ_FALSE;
4272 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4273 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4274 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4275 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4276 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4277 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4278 SCOPE_ENTER(1, "%s Request: %.*s %s\n", ast_sip_session_get_name(session),
4279 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), res ? req_uri : "");
4280
4281 switch (req.method.id) {
4282 case PJSIP_INVITE_METHOD:
4283 if (dlg) {
4284 ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
4285 break;
4286 }
4287 handled = PJ_TRUE;
4289 break;
4290 default:
4291 /* Handle other in-dialog methods if their supplements have been registered */
4292 handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
4293 has_supplement(inv_session->mod_data[session_module.id], rdata);
4294 break;
4295 }
4296
4297 SCOPE_EXIT_RTN_VALUE(handled, "%s Handled request %.*s %s ? %s\n", ast_sip_session_get_name(session),
4298 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), req_uri,
4299 handled == PJ_TRUE ? "yes" : "no");
4300}
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 4239 of file res_pjsip_session.c.

4240{
4241
4242 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4243 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4244 pjsip_inv_session *inv_session = dlg ? pjsip_dlg_get_inv_session(dlg) : NULL;
4245 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4246 SCOPE_ENTER(1, "%s Method: %.*s Status: %d\n", ast_sip_session_get_name(session),
4247 (int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
4248
4249 SCOPE_EXIT_RTN_VALUE(PJ_FALSE);
4250}

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

4218{
4219
4220 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
4221 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4222 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4223 SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4224 pjsip_tsx_state_str(tsx->state), inv_session ? pjsip_inv_state_name(inv_session->state) : "unknown");
4225
4226 if (session) {
4227 ast_trace(2, "Topology: Pending: %s Active: %s\n",
4228 ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)),
4229 ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
4230 }
4231
4233}

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

4304{
4305 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
4307 if (session) {
4309 }
4310
4311 return PJ_SUCCESS;
4312}

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

5582{
5584 pjsip_sdp_info *sdp_info;
5585 pjmedia_sdp_session *sdp;
5586 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
5588 int stream;
5589
5590 /*
5591 * If there's no transport_state or body, just return.
5592 */
5593 if (ast_strlen_zero(transport->external_media_address) || !transport_state || !tdata->msg->body) {
5594 return;
5595 }
5596
5597 sdp_info = pjsip_get_sdp_info(tdata->pool, tdata->msg->body, NULL, &pjsip_media_type_application_sdp);
5598 if (sdp_info->sdp_err != PJ_SUCCESS || !sdp_info->sdp) {
5599 return;
5600 }
5601 sdp = sdp_info->sdp;
5602
5603 if (sdp->conn) {
5604 char host[NI_MAXHOST];
5605 struct ast_sockaddr our_sdp_addr = { { 0, } };
5606
5607 ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
5608 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
5609
5610 /* Reversed check here. We don't check the remote
5611 * endpoint being in our local net, but whether our
5612 * outgoing session IP is local. If it is, we'll do
5613 * rewriting. No localnet configured? Always rewrite. */
5614 if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {
5615 ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),
5616 ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5617 pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5618 pj_strassign(&sdp->origin.addr, &sdp->conn->addr);
5619 }
5620 }
5621
5622 for (stream = 0; stream < sdp->media_count; ++stream) {
5623 /* See if there are registered handlers for this media stream type */
5624 char media[20];
5626 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5627
5628 /* We need a null-terminated version of the media string */
5629 ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
5630
5631 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
5632 if (!handler_list) {
5633 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session),
5634 media);
5635 continue;
5636 }
5637 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5638 if (handler->change_outgoing_sdp_stream_media_address) {
5639 handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
5640 }
5641 }
5642 }
5643
5644}
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:3911
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:213
Structure for SIP transport information.
Definition res_pjsip.h:117
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_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(), ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, PARSE_PORT_FORBID, pjsip_media_type_application_sdp, RAII_VAR, sdp_handlers, and session.

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

2820{
2821 pjsip_dialog *dlg;
2823 pjsip_rdata_sdp_info *sdp_info;
2824 int deferred;
2825
2826 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
2827 !(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
2829 !session->channel) {
2830 return PJ_FALSE;
2831 }
2832
2833 if (session->inv_session->invite_tsx) {
2834 /* There's a transaction in progress so bail now and let pjproject send 491 */
2835 return PJ_FALSE;
2836 }
2837
2838 if (session->deferred_reinvite) {
2839 pj_str_t key, deferred_key;
2840 pjsip_tx_data *tdata;
2841
2842 /* We use memory from the new request on purpose so the deferred reinvite pool does not grow uncontrollably */
2843 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &rdata->msg_info.cseq->method, rdata);
2844 pjsip_tsx_create_key(rdata->tp_info.pool, &deferred_key, PJSIP_ROLE_UAS, &session->deferred_reinvite->msg_info.cseq->method,
2845 session->deferred_reinvite);
2846
2847 /* If this is a retransmission ignore it */
2848 if (!pj_strcmp(&key, &deferred_key)) {
2849 return PJ_TRUE;
2850 }
2851
2852 /* Otherwise this is a new re-invite, so reject it */
2853 if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) {
2854 if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
2855 pjsip_tx_data_dec_ref(tdata);
2856 }
2857 }
2858
2859 return PJ_TRUE;
2860 }
2861
2862 if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
2863 (sdp_info->sdp_err != PJ_SUCCESS)) {
2864 return PJ_FALSE;
2865 }
2866
2867 if (!sdp_info->sdp) {
2868 return PJ_FALSE;
2869 }
2870
2871 deferred = sdp_requires_deferral(session, sdp_info->sdp);
2872 if (deferred == -1) {
2873 ast_sip_session_media_state_reset(session->pending_media_state);
2874 return PJ_FALSE;
2875 } else if (!deferred) {
2876 return PJ_FALSE;
2877 }
2878
2879 pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
2880
2881 return PJ_TRUE;
2882}
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 3537 of file res_pjsip_session.c.

3538{
3539 struct ast_sip_session *session = entry->user_data;
3540
3543 }
3544}
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 3522 of file res_pjsip_session.c.

3523{
3524 struct ast_sip_session *session = data;
3525
3526 if (session->defer_terminate) {
3527 session->defer_terminate = 0;
3528 if (session->inv_session) {
3530 }
3531 }
3532
3533 ao2_ref(session, -1);
3534 return 0;
3535}

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

1715{
1716 struct ast_party_id effective_id;
1717 struct ast_party_id connected_id;
1718 pj_pool_t *dlg_pool;
1719 pjsip_fromto_hdr *dlg_info;
1720 pjsip_contact_hdr *dlg_contact;
1721 pjsip_name_addr *dlg_info_name_addr;
1722 pjsip_sip_uri *dlg_info_uri;
1723 pjsip_sip_uri *dlg_contact_uri;
1724 int restricted;
1725 const char *pjsip_from_domain;
1726
1727 if (!session->channel || session->saved_from_hdr) {
1728 return;
1729 }
1730
1731 /* We need to save off connected_id for RPID/PAI generation */
1732 ast_party_id_init(&connected_id);
1733 ast_channel_lock(session->channel);
1734 effective_id = ast_channel_connected_effective_id(session->channel);
1735 ast_party_id_copy(&connected_id, &effective_id);
1736 ast_channel_unlock(session->channel);
1737
1738 restricted =
1740
1741 /* Now set up dlg->local.info so pjsip can correctly generate From */
1742
1743 dlg_pool = session->inv_session->dlg->pool;
1744 dlg_info = session->inv_session->dlg->local.info;
1745 dlg_contact = session->inv_session->dlg->local.contact;
1746 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1747 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1748 dlg_contact_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(dlg_contact->uri);
1749
1750 if (session->endpoint->id.trust_outbound || !restricted) {
1751 ast_sip_modify_id_header(dlg_pool, dlg_info, &connected_id);
1752 if (ast_sip_get_use_callerid_contact() && ast_strlen_zero(session->endpoint->contact_user)) {
1753 pj_strdup2(dlg_pool, &dlg_contact_uri->user, S_COR(connected_id.number.valid, connected_id.number.str, ""));
1754 }
1755 }
1756
1757 ast_party_id_free(&connected_id);
1758
1759 if (!ast_strlen_zero(session->endpoint->fromuser)) {
1760 dlg_info_name_addr->display.ptr = NULL;
1761 dlg_info_name_addr->display.slen = 0;
1762 pj_strdup2(dlg_pool, &dlg_info_uri->user, session->endpoint->fromuser);
1763 }
1764
1765 if (!ast_strlen_zero(session->endpoint->fromdomain)) {
1766 pj_strdup2(dlg_pool, &dlg_info_uri->host, session->endpoint->fromdomain);
1767 }
1768
1769 /*
1770 * Channel variable for compatibility with chan_sip SIPFROMDOMAIN
1771 */
1772 ast_channel_lock(session->channel);
1773 pjsip_from_domain = pbx_builtin_getvar_helper(session->channel, "SIPFROMDOMAIN");
1774 if (!ast_strlen_zero(pjsip_from_domain)) {
1775 ast_debug(3, "%s: From header domain reset by channel variable SIPFROMDOMAIN (%s)\n",
1776 ast_sip_session_get_name(session), pjsip_from_domain);
1777 pj_strdup2(dlg_pool, &dlg_info_uri->host, pjsip_from_domain);
1778 }
1779 ast_channel_unlock(session->channel);
1780
1781 /* We need to save off the non-anonymized From for RPID/PAI generation (for domain) */
1782 session->saved_from_hdr = pjsip_hdr_clone(dlg_pool, dlg_info);
1783 ast_sip_add_usereqphone(session->endpoint, dlg_pool, session->saved_from_hdr->uri);
1784
1785 /* In chan_sip, fromuser and fromdomain trump restricted so we only
1786 * anonymize if they're not set.
1787 */
1788 if (restricted) {
1789 /* fromuser doesn't provide a display name so we always set it */
1790 pj_strdup2(dlg_pool, &dlg_info_name_addr->display, "Anonymous");
1791
1792 if (ast_strlen_zero(session->endpoint->fromuser)) {
1793 pj_strdup2(dlg_pool, &dlg_info_uri->user, "anonymous");
1794 }
1795
1796 if (ast_sip_get_use_callerid_contact() && ast_strlen_zero(session->endpoint->contact_user)) {
1797 pj_strdup2(dlg_pool, &dlg_contact_uri->user, "anonymous");
1798 }
1799
1800 if (ast_strlen_zero(session->endpoint->fromdomain)) {
1801 pj_strdup2(dlg_pool, &dlg_info_uri->host, "anonymous.invalid");
1802 }
1803 } else {
1804 ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri);
1805 }
1806}
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:928
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:2825

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

static int set_outstanding_invite_timeout ( struct ast_sip_session session)
static

Definition at line 1653 of file res_pjsip_session.c.

1654{
1655 pjsip_transaction *tsx;
1656 pj_status_t status;
1657
1658 if (!session->inv_session || !session->inv_session->invite_tsx) {
1659 return 0;
1660 }
1661
1662 tsx = session->inv_session->invite_tsx;
1663 if (tsx->role != PJSIP_ROLE_UAC || tsx->method.id != PJSIP_INVITE_METHOD
1664 || tsx->state >= PJSIP_TSX_STATE_COMPLETED) {
1665 return 0;
1666 }
1667
1668 status = pjsip_tsx_set_timeout(tsx, pjsip_cfg()->tsx.td);
1669 if (status != PJ_SUCCESS && status != PJ_EEXISTS) {
1670 char errmsg[PJ_ERR_MSG_SIZE];
1671
1672 pj_strerror(status, errmsg, sizeof(errmsg));
1673 ast_log(LOG_WARNING, "%s: Failed to set timeout on outstanding INVITE transaction: %s\n",
1675 return 0;
1676 }
1677
1678 return 1;
1679}

References ast_log, ast_sip_session_get_name(), LOG_WARNING, session, and status.

Referenced by ast_sip_session_terminate().

◆ 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}
void ast_stream_set_group(struct ast_stream *stream, int group)
Set the stream group for a stream.
Definition stream.c:1087

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

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

3289{
3290 pj_status_t status;
3291
3292 ++dlg->sess_count;
3293 status = pjsip_dlg_add_usage(dlg, &outbound_invite_auth_module, NULL);
3294 --dlg->sess_count;
3295
3296 return status != PJ_SUCCESS ? -1 : 0;
3297}

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

3050{
3051 struct ast_sip_channel_pvt *channel = obj;
3052
3053 ao2_cleanup(channel->pvt);
3054 ao2_cleanup(channel->session);
3055}

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

3579{
3580 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
3581 &session->scheduled_termination, session->scheduled_termination.id)) {
3582 ao2_ref(session, -1);
3583 }
3584}

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

2270{
2271 pjsip_inv_session *inv_session = session->inv_session;
2272 pjmedia_sdp_session *new_sdp = NULL;
2273 pjsip_tx_data *tdata;
2274 int res = -1;
2275 SCOPE_ENTER(3, "%s: New SDP? %s Queued? %s DP: %s DA: %s\n", ast_sip_session_get_name(session),
2276 generate_new_sdp ? "yes" : "no", queued ? "yes" : "no",
2277 pending_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)) : "none",
2278 active_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)) : "none");
2279
2280 if (pending_media_state && (!pending_media_state->topology || !generate_new_sdp)) {
2281
2282 ast_sip_session_media_state_free(pending_media_state);
2283 ast_sip_session_media_state_free(active_media_state);
2284 SCOPE_EXIT_RTN_VALUE(-1, "%s: Not sending reinvite because %s%s\n", ast_sip_session_get_name(session),
2285 pending_media_state->topology == NULL ? "pending topology is null " : "",
2286 !generate_new_sdp ? "generate_new_sdp is false" : "");
2287 }
2288
2289 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
2290 /* Don't try to do anything with a hung-up call */
2291 ast_sip_session_media_state_free(pending_media_state);
2292 ast_sip_session_media_state_free(active_media_state);
2293 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because of disconnected state\n",
2295 }
2296
2297 /* If the dialog has not yet been established we have to defer until it has */
2298 if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
2299 res = delay_request(session, on_request_creation, on_sdp_creation, on_response,
2300 generate_new_sdp,
2303 pending_media_state, active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2304 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because dialog has not been established\n",
2306 }
2307
2309 if (inv_session->invite_tsx) {
2310 /* We can't send a reinvite yet, so delay it */
2311 res = delay_request(session, on_request_creation, on_sdp_creation,
2312 on_response, generate_new_sdp, DELAYED_METHOD_INVITE, pending_media_state,
2313 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2314 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding transaction\n",
2316 } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {
2317 /* Initial INVITE transaction failed to progress us to a confirmed state
2318 * which means re-invites are not possible
2319 */
2320 ast_sip_session_media_state_free(pending_media_state);
2321 ast_sip_session_media_state_free(active_media_state);
2322 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because not in confirmed state\n",
2324 }
2325 }
2326
2327 if (generate_new_sdp) {
2328 /* SDP can only be generated if current negotiation has already completed */
2329 if (inv_session->neg
2330 && pjmedia_sdp_neg_get_state(inv_session->neg)
2331 != PJMEDIA_SDP_NEG_STATE_DONE) {
2332 res = delay_request(session, on_request_creation, on_sdp_creation,
2333 on_response, generate_new_sdp,
2335 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2336 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2337 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay session refresh with new SDP because SDP negotiation is not yet done\n",
2339 }
2340
2341 /* If an explicitly requested media state has been provided use it instead of any pending one */
2342 if (pending_media_state) {
2343 int index;
2344 int type_streams[AST_MEDIA_TYPE_END] = {0};
2345
2346 ast_trace(-1, "%s: Pending media state exists\n", ast_sip_session_get_name(session));
2347
2348 /* Media state conveys a desired media state, so if there are outstanding
2349 * delayed requests we need to ensure we go into the queue and not jump
2350 * ahead. If we sent this media state now then updates could go out of
2351 * order.
2352 */
2353 if (!queued && !AST_LIST_EMPTY(&session->delayed_requests)) {
2354 res = delay_request(session, on_request_creation, on_sdp_creation,
2355 on_response, generate_new_sdp,
2357 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2358 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2359 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding requests\n",
2361 }
2362
2363 /*
2364 * Attempt to resolve only if objects are available, and it's not
2365 * switching to or from an image type.
2366 */
2367 if (active_media_state && active_media_state->topology &&
2368 (!active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] ==
2369 !pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE])) {
2370
2371 struct ast_sip_session_media_state *new_pending_state;
2372
2373 ast_trace(-1, "%s: Active media state exists and is%s equal to pending\n", ast_sip_session_get_name(session),
2374 !ast_stream_topology_equal(active_media_state->topology,pending_media_state->topology) ? " not" : "");
2375 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)));
2376 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)));
2377 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)));
2378 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)));
2379
2381 pending_media_state, active_media_state, session->active_media_state, 1);
2382 if (new_pending_state) {
2383 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)));
2384 ast_sip_session_media_state_free(pending_media_state);
2385 pending_media_state = new_pending_state;
2386 } else {
2387 ast_sip_session_media_state_reset(pending_media_state);
2388 ast_sip_session_media_state_free(active_media_state);
2389 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Unable to merge media states\n", ast_sip_session_get_name(session));
2390 }
2391 }
2392
2393 /* Prune the media state so the number of streams fit within the configured limits - we do it here
2394 * so that the index of the resulting streams in the SDP match. If we simply left the streams out
2395 * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that
2396 * are configurable on the endpoint.
2397 */
2398 ast_trace(-1, "%s: Pruning and checking formats of streams\n", ast_sip_session_get_name(session));
2399
2400 for (index = 0; index < ast_stream_topology_get_count(pending_media_state->topology); ++index) {
2401 struct ast_stream *existing_stream = NULL;
2402 struct ast_stream *stream = ast_stream_topology_get_stream(pending_media_state->topology, index);
2403 SCOPE_ENTER(4, "%s: Checking stream %s\n", ast_sip_session_get_name(session),
2404 ast_stream_get_name(stream));
2405
2406 if (session->active_media_state->topology &&
2407 index < ast_stream_topology_get_count(session->active_media_state->topology)) {
2408 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2409 ast_trace(-1, "%s: Found existing stream %s\n", ast_sip_session_get_name(session),
2410 ast_stream_get_name(existing_stream));
2411 }
2412
2413 if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {
2414 if (index < AST_VECTOR_SIZE(&pending_media_state->sessions)) {
2415 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&pending_media_state->sessions, index);
2416
2417 ao2_cleanup(session_media);
2418 AST_VECTOR_REMOVE(&pending_media_state->sessions, index, 1);
2419 }
2420
2421 ast_stream_topology_del_stream(pending_media_state->topology, index);
2422 ast_trace(-1, "%s: Dropped overlimit stream %s\n", ast_sip_session_get_name(session),
2423 ast_stream_get_name(stream));
2424
2425 /* A stream has potentially moved into our spot so we need to jump back so we process it */
2426 index -= 1;
2427 SCOPE_EXIT_EXPR(continue);
2428 }
2429
2430 /* No need to do anything with stream if it's media state is removed */
2432 /* If there is no existing stream we can just not have this stream in the topology at all. */
2433 if (!existing_stream) {
2434 ast_trace(-1, "%s: Dropped removed stream %s\n", ast_sip_session_get_name(session),
2435 ast_stream_get_name(stream));
2436 ast_stream_topology_del_stream(pending_media_state->topology, index);
2437 /* TODO: Do we need to remove the corresponding media state? */
2438 index -= 1;
2439 }
2440 SCOPE_EXIT_EXPR(continue);
2441 }
2442
2443 /* Enforce the configured allowed codecs on audio and video streams */
2445 !ast_stream_get_metadata(stream, "pjsip_session_refresh")) {
2446 struct ast_format_cap *joint_cap;
2447
2449 if (!joint_cap) {
2450 ast_sip_session_media_state_free(pending_media_state);
2451 ast_sip_session_media_state_free(active_media_state);
2452 res = -1;
2453 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to alloc format caps\n", ast_sip_session_get_name(session));
2454 }
2455 ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap);
2456 if (!ast_format_cap_count(joint_cap)) {
2457 ao2_ref(joint_cap, -1);
2458
2459 if (!existing_stream) {
2460 /* If there is no existing stream we can just not have this stream in the topology
2461 * at all.
2462 */
2463 ast_stream_topology_del_stream(pending_media_state->topology, index);
2464 index -= 1;
2465 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2467 } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) ||
2468 strcmp(ast_stream_get_name(stream), ast_stream_get_name(existing_stream))) {
2469 /* If the underlying stream is a different type or different name then we have to
2470 * mark it as removed, as it is replacing an existing stream. We do this so order
2471 * is preserved.
2472 */
2474 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2476 } else {
2477 /* However if the stream is otherwise remaining the same we can keep the formats
2478 * that exist on it already which allows media to continue to flow. We don't modify
2479 * the format capabilities but do need to cast it so that ao2_bump can raise the
2480 * reference count.
2481 */
2482 joint_cap = ao2_bump((struct ast_format_cap *)ast_stream_get_formats(existing_stream));
2483 }
2484 }
2485 ast_stream_set_formats(stream, joint_cap);
2486 ao2_cleanup(joint_cap);
2487 }
2488
2489 ++type_streams[ast_stream_get_type(stream)];
2490
2491 SCOPE_EXIT();
2492 }
2493
2494 if (session->active_media_state->topology) {
2495 /* SDP is a fun thing. Take for example the fact that streams are never removed. They just become
2496 * declined. To better handle this in the case where something requests a topology change for fewer
2497 * streams than are currently present we fill in the topology to match the current number of streams
2498 * that are active.
2499 */
2500
2501 for (index = ast_stream_topology_get_count(pending_media_state->topology);
2502 index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) {
2503 struct ast_stream *stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2504 struct ast_stream *cloned;
2505 int position;
2506 SCOPE_ENTER(4, "%s: Stream %s not in pending\n", ast_sip_session_get_name(session),
2507 ast_stream_get_name(stream));
2508
2509 cloned = ast_stream_clone(stream, NULL);
2510 if (!cloned) {
2511 ast_sip_session_media_state_free(pending_media_state);
2512 ast_sip_session_media_state_free(active_media_state);
2513 res = -1;
2514 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to clone stream %s\n",
2516 }
2517
2519 position = ast_stream_topology_append_stream(pending_media_state->topology, cloned);
2520 if (position < 0) {
2521 ast_stream_free(cloned);
2522 ast_sip_session_media_state_free(pending_media_state);
2523 ast_sip_session_media_state_free(active_media_state);
2524 res = -1;
2525 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to append cloned stream\n",
2527 }
2528 SCOPE_EXIT("%s: Appended empty stream in position %d to make counts match\n",
2530 }
2531
2532 /*
2533 * We can suppress this re-invite if the pending topology is equal to the currently
2534 * active topology.
2535 */
2536 if (ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
2537 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)));
2538 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)));
2539 ast_sip_session_media_state_free(pending_media_state);
2540 ast_sip_session_media_state_free(active_media_state);
2541 /* For external consumers we return 0 to say success, but internally for
2542 * send_delayed_request we return a separate value to indicate that this
2543 * session refresh would be redundant so we didn't send it
2544 */
2545 SCOPE_EXIT_RTN_VALUE(queued ? 1 : 0, "%s: Topologies are equal. Not sending re-invite\n",
2547 }
2548 }
2549
2550 ast_sip_session_media_state_free(session->pending_media_state);
2551 session->pending_media_state = pending_media_state;
2552 }
2553
2555 if (!new_sdp) {
2556 ast_sip_session_media_state_reset(session->pending_media_state);
2557 ast_sip_session_media_state_free(active_media_state);
2558 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to generate session refresh SDP. Not sending session refresh\n",
2560 }
2561 if (on_sdp_creation) {
2562 if (on_sdp_creation(session, new_sdp)) {
2563 ast_sip_session_media_state_reset(session->pending_media_state);
2564 ast_sip_session_media_state_free(active_media_state);
2565 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_sdp_creation failed\n", ast_sip_session_get_name(session));
2566 }
2567 }
2568 }
2569
2571 if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
2572 if (generate_new_sdp) {
2573 ast_sip_session_media_state_reset(session->pending_media_state);
2574 }
2575 ast_sip_session_media_state_free(active_media_state);
2576 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create reinvite properly\n", ast_sip_session_get_name(session));
2577 }
2578 } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
2579 if (generate_new_sdp) {
2580 ast_sip_session_media_state_reset(session->pending_media_state);
2581 }
2582 ast_sip_session_media_state_free(active_media_state);
2583 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create UPDATE properly\n", ast_sip_session_get_name(session));
2584 }
2585 if (on_request_creation) {
2586 if (on_request_creation(session, tdata)) {
2587 if (generate_new_sdp) {
2588 ast_sip_session_media_state_reset(session->pending_media_state);
2589 }
2590 ast_sip_session_media_state_free(active_media_state);
2591 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));
2592 }
2593 }
2594 ast_sip_session_send_request_with_cb(session, tdata, on_response);
2595 ast_sip_session_media_state_free(active_media_state);
2596
2597end:
2598 SCOPE_EXIT_RTN_VALUE(res, "%s: Sending session refresh SDP via %s\n", ast_sip_session_get_name(session),
2599 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE");
2600}
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:636
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:403
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:828
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:440

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

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

Referenced by session_media_dtor().

◆ uac_invite_tsx_terminates_dialog()

static int uac_invite_tsx_terminates_dialog ( pjsip_transaction *  tsx)
static

Definition at line 1686 of file res_pjsip_session.c.

1687{
1688 if (tsx->role != PJSIP_ROLE_UAC || tsx->method.id != PJSIP_INVITE_METHOD
1689 || tsx->state < PJSIP_TSX_STATE_COMPLETED) {
1690 return 0;
1691 }
1692
1693 return tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST
1694 || (tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT
1695 && !pjsip_cfg()->endpt.keep_inv_after_tsx_timeout);
1696}

Referenced by session_inv_on_tsx_state_changed().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6235 of file res_pjsip_session.c.

6236{
6238
6239#ifdef TEST_FRAMEWORK
6240 AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6241#endif
6248 return 0;
6249}
void pjsip_reason_header_unload(void)
void ast_sip_unregister_service(pjsip_module *module)
Definition res_pjsip.c:127
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition sorcery.c:2302
#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 1594 of file res_pjsip_session.c.

1595{
1596 struct ast_sip_session *session = vsession;
1597 int res;
1598
1599 if (session->inv_session->invite_tsx) {
1601 } else {
1603 }
1604
1605 return res;
1606}

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 = ASTERISK_GPL_KEY , .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 6257 of file res_pjsip_session.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6257 of file res_pjsip_session.c.

◆ inv_callback

pjsip_inv_callback inv_callback
static

Definition at line 5570 of file res_pjsip_session.c.

5570 {
5571 .on_state_changed = session_inv_on_state_changed,
5572 .on_new_session = session_inv_on_new_session,
5573 .on_tsx_state_changed = session_inv_on_tsx_state_changed,
5574 .on_rx_offer = session_inv_on_rx_offer,
5575 .on_create_offer = session_inv_on_create_offer,
5576 .on_media_update = session_inv_on_media_update,
5577 .on_redirected = session_inv_on_redirected,
5578};
static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
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_create_offer(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)

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(), 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 3272 of file res_pjsip_session.c.

3272 {
3273 .name = {"Outbound INVITE Auth", 20},
3274 .priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
3275 .on_rx_response = outbound_invite_auth,
3276};

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

Definition at line 2672 of file res_pjsip_session.c.

2672 {
2673 .name = {"Session Module", 14},
2674 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
2675 .on_rx_request = session_on_rx_request,
2676 .on_rx_response = session_on_rx_response,
2677 .on_tsx_state = session_on_tsx_state,
2678 .on_tx_response = session_on_tx_response,
2679};
static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata)
Called when a new SIP request comes into PJSIP.
static pj_status_t session_on_tx_response(pjsip_tx_data *tdata)
static void session_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
static pj_bool_t session_on_rx_response(pjsip_rx_data *rdata)

Referenced by __print_debug_details(), ast_sip_dialog_get_session(), ast_sip_session_alloc(), ast_sip_session_create_outgoing(), ast_sip_session_send_request_with_cb(), ast_sip_session_terminate(), check_request_status(), load_module(), outbound_invite_auth(), pre_session_setup(), session_destructor(), session_inv_on_create_offer(), session_inv_on_media_update(), session_inv_on_redirected(), 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(), and unload_module().

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

2898 {
2899 .name = { "Session Re-Invite Module", 24 },
2900 .priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
2901 .on_rx_request = session_reinvite_on_rx_request,
2902};

Referenced by load_module(), and unload_module().