Asterisk - The Open Source Telephony Project GIT-master-4f2b068
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_NAT_HOOK   "nat_hook"
 
#define MOD_DATA_ON_RESPONSE   "on_response"
 
#define print_debug_details(inv, tsx, e)   __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e))
 
#define SDP_HANDLER_BUCKETS   11
 
#define STATE_NONE(_stream_state)   (_stream_state == AST_STREAM_STATE_END)
 
#define STATE_REMOVED(_stream_state)   (_stream_state == AST_STREAM_STATE_REMOVED)
 
#define STREAM_REMOVED(_stream)   (ast_stream_get_state(_stream) == AST_STREAM_STATE_REMOVED)
 

Enumerations

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

Functions

static void __print_debug_details (const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_bundle_groups (struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer)
 
static int add_sdp_streams (struct ast_sip_session_media *session_media, struct ast_sip_session *session, pjmedia_sdp_session *answer, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
int ast_sip_can_present_connected_id (const struct ast_sip_session *session, const struct ast_party_id *id)
 Determines if the Connected Line info can be presented for this session.
 
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 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 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 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 1238 of file res_pjsip_session.c.

◆ DEFAULT_NUM_SESSION_MEDIA

#define DEFAULT_NUM_SESSION_MEDIA   2

Definition at line 64 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 1751 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 1749 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 1750 of file res_pjsip_session.c.

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1239 of file res_pjsip_session.c.

◆ MOD_DATA_NAT_HOOK

#define MOD_DATA_NAT_HOOK   "nat_hook"

Definition at line 61 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 4390 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 1748 of file res_pjsip_session.c.

◆ STATE_REMOVED

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

Definition at line 1747 of file res_pjsip_session.c.

◆ STREAM_REMOVED

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

Definition at line 1746 of file res_pjsip_session.c.

Enumeration Type Documentation

◆ delayed_method

Enumerator
DELAYED_METHOD_INVITE 
DELAYED_METHOD_UPDATE 
DELAYED_METHOD_BYE 

Definition at line 1307 of file res_pjsip_session.c.

1307 {
1311};
@ 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 3600 of file res_pjsip_session.c.

3600 {
3601 /*! The extension was successfully found */
3603 /*! The extension specified in the RURI was not found */
3605 /*! The extension specified in the RURI was a partial match */
3607 /*! The RURI is of an unsupported scheme */
3609};
@ 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 4341 of file res_pjsip_session.c.

4342{
4343 int id = session_module.id;
4344 struct ast_sip_session *session = NULL;
4345
4346 if (!DEBUG_ATLEAST(5)) {
4347 /* Debug not spamy enough */
4348 return;
4349 }
4350
4351 ast_log(LOG_DEBUG, "Function %s called on event %s\n",
4352 function, pjsip_event_str(e->type));
4353 if (!inv) {
4354 ast_log(LOG_DEBUG, "Transaction %p does not belong to an inv_session?\n", tsx);
4355 ast_log(LOG_DEBUG, "The transaction state is %s\n",
4356 pjsip_tsx_state_str(tsx->state));
4357 return;
4358 }
4359 if (id > -1) {
4360 session = inv->mod_data[session_module.id];
4361 }
4362 if (!session) {
4363 ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv);
4364 } else {
4365 ast_log(LOG_DEBUG, "The state change pertains to the endpoint '%s(%s)'\n",
4367 session->channel ? ast_channel_name(session->channel) : "");
4368 }
4369 if (inv->invite_tsx) {
4370 ast_log(LOG_DEBUG, "The inv session still has an invite_tsx (%p)\n",
4371 inv->invite_tsx);
4372 } else {
4373 ast_log(LOG_DEBUG, "The inv session does NOT have an invite_tsx\n");
4374 }
4375 if (tsx) {
4376 ast_log(LOG_DEBUG, "The %s %.*s transaction involved in this state change is %p\n",
4377 pjsip_role_name(tsx->role),
4378 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4379 tsx);
4380 ast_log(LOG_DEBUG, "The current transaction state is %s\n",
4381 pjsip_tsx_state_str(tsx->state));
4382 ast_log(LOG_DEBUG, "The transaction state change event is %s\n",
4383 pjsip_event_str(e->body.tsx_state.type));
4384 } else {
4385 ast_log(LOG_DEBUG, "There is no transaction involved in this state change\n");
4386 }
4387 ast_log(LOG_DEBUG, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
4388}
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 6179 of file res_pjsip_session.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

5011{
5012 pj_str_t stmp;
5013 pjmedia_sdp_attr *attr;
5014 struct sip_session_media_bundle_group bundle_groups[PJMEDIA_MAX_SDP_MEDIA];
5015 int index, mid_id;
5016 struct sip_session_media_bundle_group *bundle_group;
5017
5018 if (session->endpoint->media.webrtc) {
5019 attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
5020 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5021 }
5022
5023 if (!session->endpoint->media.bundle) {
5024 return 0;
5025 }
5026
5027 memset(bundle_groups, 0, sizeof(bundle_groups));
5028
5029 /* Build the bundle group layout so we can then add it to the SDP */
5030 for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
5031 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
5032
5033 /* If this stream is not part of a bundle group we can't add it */
5034 if (session_media->bundle_group == -1) {
5035 continue;
5036 }
5037
5038 bundle_group = &bundle_groups[session_media->bundle_group];
5039
5040 /* If this is the first mid then we need to allocate the attribute string and place BUNDLE in front */
5041 if (!bundle_group->mids[0]) {
5042 bundle_group->mids[0] = session_media->mid;
5043 bundle_group->attr_string = ast_str_create(64);
5044 if (!bundle_group->attr_string) {
5045 continue;
5046 }
5047
5048 ast_str_set(&bundle_group->attr_string, 0, "BUNDLE %s", session_media->mid);
5049 continue;
5050 }
5051
5052 for (mid_id = 1; mid_id < PJMEDIA_MAX_SDP_MEDIA; ++mid_id) {
5053 if (!bundle_group->mids[mid_id]) {
5054 bundle_group->mids[mid_id] = session_media->mid;
5055 ast_str_append(&bundle_group->attr_string, 0, " %s", session_media->mid);
5056 break;
5057 } else if (!strcmp(bundle_group->mids[mid_id], session_media->mid)) {
5058 break;
5059 }
5060 }
5061 }
5062
5063 /* Add all bundle groups that have mids to the SDP */
5064 for (index = 0; index < PJMEDIA_MAX_SDP_MEDIA; ++index) {
5065 bundle_group = &bundle_groups[index];
5066
5067 if (!bundle_group->attr_string) {
5068 continue;
5069 }
5070
5071 attr = pjmedia_sdp_attr_create(pool, "group", pj_cstr(&stmp, ast_str_buffer(bundle_group->attr_string)));
5072 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5073
5074 ast_free(bundle_group->attr_string);
5075 }
5076
5077 return 0;
5078}
#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:620
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691

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

4960{
4961 struct ast_sip_session_sdp_handler *handler = session_media->handler;
4962 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
4963 int res = 0;
4964 SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
4965 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
4966
4967 if (handler) {
4968 /* if an already assigned handler reports a catastrophic error, fail */
4969 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
4970 if (res < 0) {
4971 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
4972 }
4973 SCOPE_EXIT_RTN_VALUE(0, "Had handler\n");
4974 }
4975
4976 handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY);
4977 if (!handler_list) {
4978 SCOPE_EXIT_RTN_VALUE(0, "No handlers\n");
4979 }
4980
4981 /* no handler for this stream type and we have a list to search */
4982 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
4983 if (handler == session_media->handler) {
4984 continue;
4985 }
4986 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
4987 if (res < 0) {
4988 /* catastrophic error */
4989 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
4990 }
4991 if (res > 0) {
4992 /* Handled by this handler. Move to the next stream */
4993 session_media_set_handler(session_media, handler);
4994 SCOPE_EXIT_RTN_VALUE(0, "Handled\n");
4995 }
4996 }
4997
4998 /* streams that weren't handled won't be included in generated outbound SDP */
4999 SCOPE_EXIT_RTN_VALUE(0, "Not handled\n");
5000}
#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 6179 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 132 of file res_pjsip_session.c.

133{
134 return id->number.valid
135 && (session->endpoint->id.trust_outbound
137}
#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:1807

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

2996{
2997 struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
2998
2999 if (!channel) {
3000 return NULL;
3001 }
3002
3003 ao2_ref(pvt, +1);
3004 channel->pvt = pvt;
3005 ao2_ref(session, +1);
3006 channel->session = session;
3007
3008 return channel;
3009}
#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 3548 of file res_pjsip_session.c.

3549{
3550 pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3551 struct ast_sip_session *session;
3552
3553 if (!inv_session ||
3554 !(session = inv_session->mod_data[session_module.id])) {
3555 return NULL;
3556 }
3557
3558 ao2_ref(session, +1);
3559
3560 return session;
3561}
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 1285 of file res_pjsip_session.c.

1286{
1287 ast_assert(datastore != NULL);
1288 ast_assert(datastore->info != NULL);
1289 ast_assert(ast_strlen_zero(datastore->uid) == 0);
1290
1291 if (!ao2_link(session->datastores, datastore)) {
1292 return -1;
1293 }
1294 return 0;
1295}
#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 3011 of file res_pjsip_session.c.

3013{
3015 struct ast_sip_session *ret_session;
3016 int dsp_features = 0;
3017
3019 if (!session) {
3020 return NULL;
3021 }
3022
3023 AST_LIST_HEAD_INIT(&session->supplements);
3024 AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
3026
3028 if (!session->direct_media_cap) {
3029 return NULL;
3030 }
3033 if (!session->datastores) {
3034 return NULL;
3035 }
3036 session->active_media_state = ast_sip_session_media_state_alloc();
3037 if (!session->active_media_state) {
3038 return NULL;
3039 }
3040 session->pending_media_state = ast_sip_session_media_state_alloc();
3041 if (!session->pending_media_state) {
3042 return NULL;
3043 }
3044 if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
3045 return NULL;
3046 }
3047
3049 dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3050 }
3051 if (endpoint->faxdetect) {
3052 dsp_features |= DSP_FEATURE_FAX_DETECT;
3053 }
3054 if (dsp_features) {
3055 session->dsp = ast_dsp_new();
3056 if (!session->dsp) {
3057 return NULL;
3058 }
3059
3060 ast_dsp_set_features(session->dsp, dsp_features);
3061 }
3062
3063 session->endpoint = ao2_bump(endpoint);
3064
3065 if (rdata) {
3066 /*
3067 * We must continue using the serializer that the original
3068 * INVITE came in on for the dialog. There may be
3069 * retransmissions already enqueued in the original
3070 * serializer that can result in reentrancy and message
3071 * sequencing problems.
3072 */
3073 session->serializer = ast_sip_get_distributor_serializer(rdata);
3074 } else {
3075 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
3076
3077 /* Create name with seq number appended. */
3078 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outsess/%s",
3080
3081 session->serializer = ast_sip_create_serializer(tps_name);
3082 }
3083 if (!session->serializer) {
3084 return NULL;
3085 }
3088
3089 /* When a PJSIP INVITE session is created it is created with a reference
3090 * count of 1, with that reference being managed by the underlying state
3091 * of the INVITE session itself. When the INVITE session transitions to
3092 * a DISCONNECTED state that reference is released. This means we can not
3093 * rely on that reference to ensure the INVITE session remains for the
3094 * lifetime of our session. To ensure it does we add our own reference
3095 * and release it when our own session goes away, ensuring that the INVITE
3096 * session remains for the lifetime of session.
3097 */
3098
3099#ifdef HAVE_PJSIP_INV_SESSION_REF
3100 if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
3101 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3102 return NULL;
3103 }
3104#endif
3105
3106 pjsip_dlg_inc_session(inv_session->dlg, &session_module);
3107 inv_session->mod_data[session_module.id] = ao2_bump(session);
3108 session->contact = ao2_bump(contact);
3109 session->inv_session = inv_session;
3110
3111 session->dtmf = endpoint->dtmf;
3112 session->moh_passthrough = endpoint->moh_passthrough;
3113
3115 /* Release the ref held by session->inv_session */
3116 ao2_ref(session, -1);
3117 return NULL;
3118 }
3119
3120 session->authentication_challenge_count = 0;
3121
3122 /* Fire session begin handlers */
3124
3125 /* Avoid unnecessary ref manipulation to return a session */
3126 ret_session = session;
3127 session = NULL;
3128 return ret_session;
3129}
@ 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:1743
#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:1772
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1762
@ 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:2088
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:556
@ AST_SIP_DTMF_INBAND
Definition res_pjsip.h:552
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:1134
enum ast_sip_dtmf_mode dtmf
Definition res_pjsip.h:1110
unsigned int faxdetect
Definition res_pjsip.h:1122
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 1255 of file res_pjsip_session.c.

1256{
1257 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
1258 char uuid_buf[AST_UUID_STR_LEN];
1259 const char *uid_ptr = uid;
1260
1261 if (!info) {
1262 return NULL;
1263 }
1264
1265 datastore = ao2_alloc(sizeof(*datastore), session_datastore_destroy);
1266 if (!datastore) {
1267 return NULL;
1268 }
1269
1270 datastore->info = info;
1271 if (ast_strlen_zero(uid)) {
1272 /* They didn't provide an ID so we'll provide one ourself */
1273 uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
1274 }
1275
1276 datastore->uid = ast_strdup(uid_ptr);
1277 if (!datastore->uid) {
1278 return NULL;
1279 }
1280
1281 ao2_ref(datastore, +1);
1282 return datastore;
1283}
#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 2868 of file res_pjsip_session.c.

2869{
2870 pjmedia_sdp_session *offer;
2872
2873 if (!(offer = create_local_sdp(session->inv_session, session, NULL, 0))) {
2874 pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
2875 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create offer\n");
2876 }
2877
2878 pjsip_inv_set_local_sdp(session->inv_session, offer);
2879 pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
2880#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
2881 if (!session->endpoint->preferred_codec_only) {
2882 pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
2883 }
2884#endif
2885
2886 /*
2887 * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the
2888 * From in the initial INVITE will be wrong but the rest of the messages will be OK.
2889 */
2891
2892 if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
2893 SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
2894 }
2895
2897}
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 3237 of file res_pjsip_session.c.

3240{
3241 const char *uri = NULL;
3242 RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup);
3243 RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
3244 pjsip_timer_setting timer;
3245 pjsip_dialog *dlg;
3246 struct pjsip_inv_session *inv_session;
3248 struct ast_sip_session *ret_session;
3249 SCOPE_ENTER(1, "%s %s Topology: %s\n", ast_sorcery_object_get_id(endpoint), request_user,
3250 ast_str_tmp(256, ast_stream_topology_to_str(req_topology, &STR_TMP)));
3251
3252 /* If no location has been provided use the AOR list from the endpoint itself */
3253 if (location || !contact) {
3254 location = S_OR(location, endpoint->aors);
3255
3257 &found_aor, &found_contact);
3258 if (!found_contact || ast_strlen_zero(found_contact->uri)) {
3259 uri = location;
3260 } else {
3261 uri = found_contact->uri;
3262 }
3263 } else {
3264 uri = contact->uri;
3265 }
3266
3267 /* If we still have no URI to dial fail to create the session */
3268 if (ast_strlen_zero(uri)) {
3269 ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
3271 SCOPE_EXIT_RTN_VALUE(NULL, "No URI\n");
3272 }
3273
3274 if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
3275 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create dialog\n");
3276 }
3277
3278 if (setup_outbound_invite_auth(dlg)) {
3279 pjsip_dlg_terminate(dlg);
3280 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't setup auth\n");
3281 }
3282
3283 if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
3284 pjsip_dlg_terminate(dlg);
3285 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create uac\n");
3286 }
3287#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3288 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3289#endif
3290
3291 pjsip_timer_setting_default(&timer);
3293 timer.sess_expires = endpoint->extensions.timer.sess_expires;
3294 pjsip_timer_init_session(inv_session, &timer);
3295
3296 session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact,
3297 inv_session, NULL);
3298 if (!session) {
3299 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3300 return NULL;
3301 }
3302 session->aor = ao2_bump(found_aor);
3303 session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;
3304
3306
3307 if (ast_stream_topology_get_count(req_topology) > 0) {
3308 /* get joint caps between req_topology and endpoint topology */
3309 int i;
3310
3311 for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {
3312 struct ast_stream *req_stream;
3313 struct ast_stream *clone_stream;
3314
3315 req_stream = ast_stream_topology_get_stream(req_topology, i);
3316
3318 continue;
3319 }
3320
3321 clone_stream = ast_sip_session_create_joint_call_stream(session, req_stream);
3322 if (!clone_stream || ast_stream_get_format_count(clone_stream) == 0) {
3323 ast_stream_free(clone_stream);
3324 continue;
3325 }
3326
3327 if (!session->pending_media_state->topology) {
3328 session->pending_media_state->topology = ast_stream_topology_alloc();
3329 if (!session->pending_media_state->topology) {
3330 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3331 ao2_ref(session, -1);
3332 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create topology\n");
3333 }
3334 }
3335
3336 if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) {
3337 ast_stream_free(clone_stream);
3338 continue;
3339 }
3340 }
3341 }
3342
3343 if (!session->pending_media_state->topology) {
3344 /* Use the configured topology on the endpoint as the pending one */
3345 session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology);
3346 if (!session->pending_media_state->topology) {
3347 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3348 ao2_ref(session, -1);
3349 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't clone topology\n");
3350 }
3351 }
3352
3353 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3354 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3355 /* Since we are not notifying ourselves that the INVITE session is being terminated
3356 * we need to manually drop its reference to session
3357 */
3358 ao2_ref(session, -1);
3359 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't add usage\n");
3360 }
3361
3362 /* Avoid unnecessary ref manipulation to return a session */
3363 ret_session = session;
3364 session = NULL;
3365 SCOPE_EXIT_RTN_VALUE(ret_session);
3366}
static struct ast_timer * timer
Definition chan_iax2.c:388
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:1751
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:958
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition res_pjsip.h:1437
void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags, struct ast_sip_aor **aor, struct ast_sip_contact **contact)
Retrieve the first bound contact AND the AOR chosen from a list of AORs and filter based on flags.
Definition location.c:272
struct ast_sip_session * ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata)
Allocate a new SIP session.
static int setup_outbound_invite_auth(pjsip_dialog *dlg)
@ AST_SIP_SESSION_OUTGOING_CALL
struct ast_stream * ast_sip_session_create_joint_call_stream(const struct ast_sip_session *session, struct ast_stream *remote)
Create a new stream of joint capabilities.
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition stream.c: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:478
Contact associated with an address of record.
Definition res_pjsip.h:390
const ast_string_field uri
Definition res_pjsip.h:412
struct ast_sip_timer_options timer
Definition res_pjsip.h:819
struct ast_stream_topology * topology
Definition res_pjsip.h:1021
struct ast_sip_endpoint_id_configuration id
Definition res_pjsip.h:1100
const ast_string_field aors
Definition res_pjsip.h:1090
struct ast_sip_endpoint_extensions extensions
Definition res_pjsip.h:1092
struct ast_sip_endpoint_media_configuration media
Definition res_pjsip.h:1094
unsigned int sess_expires
Definition res_pjsip.h:806
unsigned int min_se
Definition res_pjsip.h:804

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

Referenced by request().

◆ ast_sip_session_defer_termination()

int ast_sip_session_defer_termination ( struct ast_sip_session session)

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

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

Definition at line 3474 of file res_pjsip_session.c.

3475{
3476 pj_time_val delay = { .sec = 60, };
3477 int res;
3478
3479 /* The session should not have an active deferred termination request. */
3480 ast_assert(!session->defer_terminate);
3481
3482 session->defer_terminate = 1;
3483
3484 session->defer_end = 1;
3485 session->ended_while_deferred = 0;
3486
3487 ao2_ref(session, +1);
3488 pj_timer_entry_init(&session->scheduled_termination, 0, session, session_termination_cb);
3489
3490 res = (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
3491 &session->scheduled_termination, &delay) != PJ_SUCCESS) ? -1 : 0;
3492 if (res) {
3493 session->defer_terminate = 0;
3494 ao2_ref(session, -1);
3495 }
3496 return res;
3497}
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:514
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 3514 of file res_pjsip_session.c.

3515{
3516 if (!session->defer_terminate) {
3517 /* Already canceled or timer fired. */
3518 return;
3519 }
3520
3521 session->defer_terminate = 0;
3522
3523 if (session->terminate_while_deferred) {
3524 /* Complete the termination started by the upper layer. */
3526 }
3527
3528 /* Stop the termination timer if it is still running. */
3530}
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 3532 of file res_pjsip_session.c.

3533{
3534 if (!session->defer_end) {
3535 return;
3536 }
3537
3538 session->defer_end = 0;
3539
3540 if (session->ended_while_deferred) {
3541 /* Complete the session end started by the remote hangup. */
3542 ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3543 session->ended_while_deferred = 0;
3545 }
3546}
#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 1297 of file res_pjsip_session.c.

1298{
1299 return ao2_find(session->datastores, name, OBJ_KEY);
1300}
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 3563 of file res_pjsip_session.c.

3564{
3565 pjsip_inv_session *inv_session = session->inv_session;
3566
3567 if (!inv_session) {
3568 return NULL;
3569 }
3570
3571 return inv_session->dlg;
3572}

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

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

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

3575{
3576 pjsip_inv_session *inv_session = session->inv_session;
3577
3578 if (!inv_session) {
3579 return PJSIP_INV_STATE_NULL;
3580 }
3581
3582 return inv_session->state;
3583}

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

370{
371 int index;
372
373 if (!session->pending_media_state->topology) {
374 ast_log(LOG_WARNING, "Pending topology was NULL for channel '%s'\n",
375 session->channel ? ast_channel_name(session->channel) : "unknown");
376 return 0;
377 }
378
380 return 0;
381 }
382
383 for (index = 0; index < ast_stream_topology_get_count(session->pending_media_state->topology); ++index) {
384 if (ast_stream_get_type(ast_stream_topology_get_stream(session->pending_media_state->topology, index)) !=
385 ast_stream_get_type(stream)) {
386 continue;
387 }
388
389 return ast_stream_topology_get_stream(session->pending_media_state->topology, index) == stream ? 1 : 0;
390 }
391
392 return 0;
393}
#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 395 of file res_pjsip_session.c.

397{
398 struct ast_sip_session_media_read_callback_state callback_state = {
399 .fd = fd,
400 .read_callback = callback,
401 .session = session_media,
402 };
403
404 /* The contents of the vector are whole structs and not pointers */
405 return AST_VECTOR_APPEND(&session->pending_media_state->read_callbacks, callback_state);
406}
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 424 of file res_pjsip_session.c.

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

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

410{
411 if (session_media->write_callback) {
412 if (session_media->write_callback == callback) {
413 return 0;
414 }
415
416 return -1;
417 }
418
419 session_media->write_callback = callback;
420
421 return 0;
422}
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 500 of file res_pjsip_session.c.

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

249{
252}
#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 307 of file res_pjsip_session.c.

308{
309 struct ast_sip_session_media_state *cloned;
310 int index;
311
312 if (!media_state) {
313 return NULL;
314 }
315
317 AST_VECTOR_SIZE(&media_state->sessions),
318 AST_VECTOR_SIZE(&media_state->read_callbacks));
319 if (!cloned) {
320 return NULL;
321 }
322
323 if (media_state->topology) {
324 cloned->topology = ast_stream_topology_clone(media_state->topology);
325 if (!cloned->topology) {
327 return NULL;
328 }
329 }
330
331 for (index = 0; index < AST_VECTOR_SIZE(&media_state->sessions); ++index) {
332 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index);
334
335 ao2_bump(session_media);
336 if (AST_VECTOR_REPLACE(&cloned->sessions, index, session_media)) {
337 ao2_cleanup(session_media);
338 }
340 !cloned->default_session[type]) {
341 cloned->default_session[type] = session_media;
342 }
343 }
344
345 for (index = 0; index < AST_VECTOR_SIZE(&media_state->read_callbacks); ++index) {
347
349 }
350
351 return cloned;
352}
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::@283 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:679

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

355{
356 if (!media_state) {
357 return;
358 }
359
360 /* This will reset the internal state so we only have to free persistent things */
362
363 AST_VECTOR_FREE(&media_state->sessions);
364 AST_VECTOR_FREE(&media_state->read_callbacks);
365
366 ast_free(media_state);
367}
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 288 of file res_pjsip_session.c.

289{
290 int index;
291
292 if (!media_state) {
293 return;
294 }
295
296 AST_VECTOR_RESET(&media_state->sessions, ao2_cleanup);
298
299 for (index = 0; index < AST_MEDIA_TYPE_END; ++index) {
300 media_state->default_session[index] = NULL;
301 }
302
304 media_state->topology = NULL;
305}
@ 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:636
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition vector.h:582

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

255{
256 int i;
257 int ret;
258
259 if (!media_state || !sip_session) {
260 return;
261 }
262
263 for (i = 0; i < AST_VECTOR_SIZE(&media_state->sessions); i++) {
264 struct ast_rtp_instance_stats *stats_tmp = NULL;
265 struct ast_sip_session_media *media = AST_VECTOR_GET(&media_state->sessions, i);
266 if (!media || !media->rtp) {
267 continue;
268 }
269
270 stats_tmp = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
271 if (!stats_tmp) {
272 return;
273 }
274
276 if (ret) {
277 ast_free(stats_tmp);
278 continue;
279 }
280
281 /* remove all the duplicated stats if exist */
283
284 AST_VECTOR_APPEND(&sip_session->media_stats, stats_tmp);
285 }
286}
#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::@286 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:499

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

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

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

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

149{
150 RAII_VAR(struct sdp_handler_list *, handler_list,
151 ao2_find(sdp_handlers, stream_type, OBJ_KEY), ao2_cleanup);
153
154 if (handler_list) {
155 struct ast_sip_session_sdp_handler *iter;
156 /* Check if this handler is already registered for this stream type */
157 AST_LIST_TRAVERSE(&handler_list->list, iter, next) {
158 if (!strcmp(iter->id, handler->id)) {
159 ast_log(LOG_WARNING, "Handler '%s' already registered for stream type '%s'.\n", handler->id, stream_type);
160 return -1;
161 }
162 }
163 AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
164 ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
165
166 return 0;
167 }
168
169 /* No stream of this type has been registered yet, so we need to create a new list */
170 handler_list = ao2_alloc(sizeof(*handler_list) + strlen(stream_type), NULL);
171 if (!handler_list) {
172 return -1;
173 }
174 /* Safe use of strcpy */
175 strcpy(handler_list->stream_type, stream_type);
176 AST_LIST_HEAD_INIT_NOLOCK(&handler_list->list);
177 AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
178 if (!ao2_link(sdp_handlers, handler_list)) {
179 return -1;
180 }
181 ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
182
183 return 0;
184}
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 1302 of file res_pjsip_session.c.

1303{
1304 ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
1305}
#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 2819 of file res_pjsip_session.c.

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

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

2864{
2866}
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 2839 of file res_pjsip_session.c.

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

2590{
2591 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
2592 RAII_VAR(struct ast_sip_session *, dlg_session, dlg ? ast_sip_dialog_get_session(dlg) : NULL, ao2_cleanup);
2593 if (!dlg_session) {
2594 /* If the dialog has a session, handle_outgoing_response will be called
2595 from session_on_tx_response. If it does not, call it from here. */
2597 }
2598 pjsip_inv_send_msg(session->inv_session, tdata);
2599 return;
2600}
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 3131 of file res_pjsip_session.c.

3132{
3134}
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 3371 of file res_pjsip_session.c.

3372{
3373 pj_status_t status;
3374 pjsip_tx_data *packet = NULL;
3375 SCOPE_ENTER(1, "%s Response %d\n", ast_sip_session_get_name(session), response);
3376
3377 if (session->defer_terminate) {
3378 session->terminate_while_deferred = 1;
3379 SCOPE_EXIT_RTN("Deferred\n");
3380 }
3381
3382 if (!response) {
3383 response = 603;
3384 }
3385
3386 /* The media sessions need to exist for the lifetime of the underlying channel
3387 * to ensure that anything (such as bridge_native_rtp) has access to them as
3388 * appropriate. Since ast_sip_session_terminate is called by chan_pjsip and other
3389 * places when the session is to be terminated we terminate any existing
3390 * media sessions here.
3391 */
3392 ast_sip_session_media_stats_save(session, session->active_media_state);
3393 SWAP(session->active_media_state, session->pending_media_state);
3394 ast_sip_session_media_state_reset(session->pending_media_state);
3395
3396 switch (session->inv_session->state) {
3397 case PJSIP_INV_STATE_NULL:
3398 if (!session->inv_session->invite_tsx) {
3399 /*
3400 * Normally, it's pjproject's transaction cleanup that ultimately causes the
3401 * final session reference to be released but if both STATE and invite_tsx are NULL,
3402 * we never created a transaction in the first place. In this case, we need to
3403 * do the cleanup ourselves.
3404 */
3405 /* Transfer the inv_session session reference to the session_end_task */
3406 session->inv_session->mod_data[session_module.id] = NULL;
3407 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3409 /*
3410 * session_end_completion will cleanup the final session reference unless
3411 * ast_sip_session_terminate's caller is holding one.
3412 */
3414 } else {
3415 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3416 }
3417 break;
3418 case PJSIP_INV_STATE_CONFIRMED:
3419 if (session->inv_session->invite_tsx) {
3420 ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",
3422 /* If this is delayed the only thing that will happen is a BYE request so we don't
3423 * actually need to store the response code for when it happens.
3424 */
3426 break;
3427 }
3428 /* Fall through */
3429 default:
3430 status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet);
3431 if (status == PJ_SUCCESS && packet) {
3432 struct ast_sip_session_delayed_request *delay;
3433
3434 /* Flush any delayed requests so they cannot overlap this transaction. */
3435 while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
3436 delayed_request_free(delay);
3437 }
3438
3439 if (packet->msg->type == PJSIP_RESPONSE_MSG) {
3441 } else {
3443 }
3444 }
3445 break;
3446 }
3448}
jack_status_t status
Definition app_jack.c:149
#define SCOPE_EXIT_RTN(...)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static int session_end_completion(void *vsession)
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.
static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, enum delayed_method method, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queue_head)
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
void ast_sip_session_media_stats_save(struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
Save a media stats.
Structure used for sending delayed requests.
struct ast_sip_session_delayed_request * next
#define SWAP(a, b)
Definition utils.h:256

References ast_debug, AST_LIST_REMOVE_HEAD, ast_sip_session_get_name(), ast_sip_session_media_state_reset(), ast_sip_session_media_stats_save(), ast_sip_session_send_request(), ast_sip_session_send_response(), delay_request(), DELAYED_METHOD_BYE, delayed_request_free(), ast_sip_session_delayed_request::next, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end(), session_end_completion(), session_module, status, and SWAP.

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

◆ ast_sip_session_unregister_sdp_handler()

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

Unregister an SDP handler.

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

Definition at line 209 of file res_pjsip_session.c.

210{
212}
#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 3136 of file res_pjsip_session.c.

3137{
3139}
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 3869 of file res_pjsip_session.c.

3870{
3871 pjsip_msg_body *body = rdata->msg_info.msg->body;
3872 pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3873
3874 if (body && ctype_hdr &&
3877 pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3878 while (part != NULL) {
3880 return 1;
3881 }
3882 part = pjsip_multipart_get_next_part(body, part);
3883 }
3884 }
3885 return 0;
3886}
#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:2199
pjsip_media_type pjsip_media_type_multipart_mixed
Definition res_pjsip.c:3908
pjsip_media_type pjsip_media_type_multipart_alternative
Definition res_pjsip.c:3907
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 3845 of file res_pjsip_session.c.

3846{
3847 pjsip_hdr *hdr = part->hdr.next;
3848 static const pj_str_t str_handling_required = {"handling=required", 16};
3849
3850 while (hdr != &part->hdr) {
3851 if (hdr->type == PJSIP_H_OTHER) {
3852 pjsip_generic_string_hdr *generic_hdr = (pjsip_generic_string_hdr*)hdr;
3853
3854 if (!pj_stricmp2(&hdr->name, "Content-Disposition") &&
3855 pj_stristr(&generic_hdr->hvalue, &str_handling_required) &&
3856 !check_sdp_content_type_supported(&part->body->content_type)) {
3857 return 1;
3858 }
3859 }
3860 hdr = hdr->next;
3861 }
3862
3863 return 0;
3864}
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 1594 of file res_pjsip_session.c.

1596{
1597 ao2_ref(session, +1);
1598 if (ast_sip_push_task(session->serializer, cb, session)) {
1599 ao2_ref(session, -1);
1600 }
1601}
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2094

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

4555{
4556 struct ast_sip_session *session = inv->mod_data[session_module.id];
4557 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4558
4559 if (inv->state == PJSIP_INV_STATE_DISCONNECTED && inv->cancelling) {
4560 return 0;
4561 }
4562
4563 if (tsx->status_code != 503 && tsx->status_code != 408) {
4564 return 0;
4565 }
4566
4567 if (!ast_sip_failover_request(tsx->last_tx)) {
4568 return 0;
4569 }
4570
4571 pjsip_inv_uac_restart(inv, PJ_FALSE);
4572 /*
4573 * Bump the ref since it will be on a new transaction and
4574 * we don't want it to go away along with the old transaction.
4575 */
4576 pjsip_tx_data_add_ref(tsx->last_tx);
4578 return 1;
4579}
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:1810

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

3834{
3835 pjsip_media_type app_sdp;
3836 pjsip_media_type_init2(&app_sdp, "application", "sdp");
3837
3838 if (!pjsip_media_type_cmp(content_type, &app_sdp, 0)) {
3839 return 1;
3840 }
3841
3842 return 0;
3843}

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

5081{
5082 static const pj_str_t STR_IN = { "IN", 2 };
5083 static const pj_str_t STR_IP4 = { "IP4", 3 };
5084 static const pj_str_t STR_IP6 = { "IP6", 3 };
5085 pjmedia_sdp_session *local;
5086 int i;
5087 int stream;
5089
5090 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
5091 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Failed to create session SDP. Session has been already disconnected\n",
5093 }
5094
5095 if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
5096 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Pool allocation failure\n", ast_sip_session_get_name(session));
5097 }
5098
5099 if (!offer) {
5100 local->origin.version = local->origin.id = (pj_uint32_t)(ast_random());
5101 } else {
5102 local->origin.version = offer->origin.version + 1;
5103 local->origin.id = offer->origin.id;
5104 }
5105
5106 pj_strdup2(inv->pool_prov, &local->origin.user, session->endpoint->media.sdpowner);
5107 pj_strdup2(inv->pool_prov, &local->name, session->endpoint->media.sdpsession);
5108
5109 if (!session->pending_media_state->topology || !ast_stream_topology_get_count(session->pending_media_state->topology)) {
5110 /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication
5111 * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation
5112 * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the endpoint.
5113 * We will also do this if wanted by the ignore_active_stream_topology flag.
5114 */
5115 ast_trace(-1, "no information about stream topology received\n");
5116 ast_stream_topology_free(session->pending_media_state->topology);
5117 if (session->active_media_state->topology && !ignore_active_stream_topology) {
5118 ast_trace(-1, "using existing topology\n");
5119 session->pending_media_state->topology = ast_stream_topology_clone(session->active_media_state->topology);
5120 } else {
5121 if (ignore_active_stream_topology) {
5122 ast_trace(-1, "fall back to endpoint configuration - ignore active stream topolog\n");
5123 } else {
5124 ast_trace(-1, "fall back to endpoint configuration\n");
5125 }
5126 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
5127 }
5128 if (!session->pending_media_state->topology) {
5129 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: No pending media state topology\n", ast_sip_session_get_name(session));
5130 }
5131 }
5132
5133 ast_trace(-1, "%s: Processing streams\n", ast_sip_session_get_name(session));
5134
5135 for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) {
5136 struct ast_sip_session_media *session_media;
5137 struct ast_stream *stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
5138 unsigned int streams = local->media_count;
5139 SCOPE_ENTER(4, "%s: Processing stream %s\n", ast_sip_session_get_name(session),
5140 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5141
5142 /* This code does not enforce any maximum stream count limitations as that is done on either
5143 * the handling of an incoming SDP offer or on the handling of a session refresh.
5144 */
5145
5146 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i);
5147 if (!session_media) {
5148 local = NULL;
5149 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc/add session media for stream %s\n",
5151 }
5152
5153 if (add_sdp_streams(session_media, session, local, offer, stream)) {
5154 local = NULL;
5155 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't add sdp streams for stream %s\n",
5157 }
5158
5159 /* If a stream was actually added then add any additional details */
5160 if (streams != local->media_count) {
5161 pjmedia_sdp_media *media = local->media[streams];
5162 pj_str_t stmp;
5163 pjmedia_sdp_attr *attr;
5164
5165 /* Add the media identifier if present */
5166 if (!ast_strlen_zero(session_media->mid)) {
5167 attr = pjmedia_sdp_attr_create(inv->pool_prov, "mid", pj_cstr(&stmp, session_media->mid));
5168 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
5169 }
5170
5171 ast_trace(-1, "%s: Stream %s added%s%s\n", ast_sip_session_get_name(session),
5172 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5173 S_COR(!ast_strlen_zero(session_media->mid), " with mid ", ""), S_OR(session_media->mid, ""));
5174
5175 }
5176
5177 /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */
5178 if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) {
5179 SCOPE_EXIT_EXPR(break, "%s: Stream %s exceeded max pjmedia count of %d\n",
5181 PJMEDIA_MAX_SDP_MEDIA);
5182 }
5183
5184 SCOPE_EXIT("%s: Done with %s\n", ast_sip_session_get_name(session),
5185 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5186
5187 }
5188
5189 /* Add any bundle groups that are present on the media state */
5190 ast_trace(-1, "%s: Adding bundle groups (if available)\n", ast_sip_session_get_name(session));
5191 if (add_bundle_groups(session, inv->pool_prov, local)) {
5192 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't add bundle groups\n", ast_sip_session_get_name(session));
5193 }
5194
5195 /* Use the connection details of an available media if possible for SDP level */
5196 ast_trace(-1, "%s: Copying connection details\n", ast_sip_session_get_name(session));
5197
5198 for (stream = 0; stream < local->media_count; stream++) {
5199 SCOPE_ENTER(4, "%s: Processing media %d\n", ast_sip_session_get_name(session), stream);
5200 if (!local->media[stream]->conn) {
5201 SCOPE_EXIT_EXPR(continue, "%s: Media %d has no connection info\n", ast_sip_session_get_name(session), stream);
5202 }
5203
5204 if (local->conn) {
5205 if (!pj_strcmp(&local->conn->net_type, &local->media[stream]->conn->net_type) &&
5206 !pj_strcmp(&local->conn->addr_type, &local->media[stream]->conn->addr_type) &&
5207 !pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) {
5208 local->media[stream]->conn = NULL;
5209 }
5210 SCOPE_EXIT_EXPR(continue, "%s: Media %d has good existing connection info\n", ast_sip_session_get_name(session), stream);
5211 }
5212
5213 /* This stream's connection info will serve as the connection details for SDP level */
5214 local->conn = local->media[stream]->conn;
5215 local->media[stream]->conn = NULL;
5216
5217 SCOPE_EXIT_EXPR(continue, "%s: Media %d reset\n", ast_sip_session_get_name(session), stream);
5218 }
5219
5220 /* If no SDP level connection details are present then create some */
5221 if (!local->conn) {
5222 ast_trace(-1, "%s: Creating connection details\n", ast_sip_session_get_name(session));
5223
5224 local->conn = pj_pool_zalloc(inv->pool_prov, sizeof(struct pjmedia_sdp_conn));
5225 local->conn->net_type = STR_IN;
5226 local->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
5227
5228 if (!ast_strlen_zero(session->endpoint->media.address)) {
5229 pj_strdup2(inv->pool_prov, &local->conn->addr, session->endpoint->media.address);
5230 } else {
5231 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()));
5232 }
5233 }
5234
5235 pj_strassign(&local->origin.net_type, &local->conn->net_type);
5236 pj_strassign(&local->origin.addr_type, &local->conn->addr_type);
5237 pj_strassign(&local->origin.addr, &local->conn->addr);
5238
5239end:
5241}
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:2464
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:2348

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

2910{
2911 const struct ast_datastore *datastore1 = obj;
2912 const struct ast_datastore *datastore2 = arg;
2913 const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
2914
2915 ast_assert(datastore1->uid != NULL);
2916 ast_assert(uid2 != NULL);
2917
2918 return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
2919}
@ 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 2899 of file res_pjsip_session.c.

2900{
2901 const struct ast_datastore *datastore = obj;
2902 const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
2903
2904 ast_assert(uid != NULL);
2905
2906 return ast_str_hash(uid);
2907}
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 1603 of file res_pjsip_session.c.

1612{
1617
1618 if (!delay) {
1621 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1622 }
1623
1624 if (method == DELAYED_METHOD_BYE || queue_head) {
1625 /* Send BYE as early as possible */
1626 AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1627 } else {
1628 AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1629 }
1631}
#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)
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 1322 of file res_pjsip_session.c.

1323{
1324 const char *str = "<unknown>";
1325
1326 switch (method) {
1328 str = "INVITE";
1329 break;
1331 str = "UPDATE";
1332 break;
1333 case DELAYED_METHOD_BYE:
1334 str = "BYE";
1335 break;
1336 }
1337
1338 return str;
1339}
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 4111 of file res_pjsip_session.c.

4112{
4113 pj_str_t method;
4114
4115 if (ast_strlen_zero(supplement_method)) {
4116 return PJ_TRUE;
4117 }
4118
4119 pj_cstr(&method, supplement_method);
4120
4121 return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
4122}
static const pjsip_method message_method
Definition res_pjsip.c:1269

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

3587{
3588 int res = -1;
3589 struct ast_party_id id;
3590
3591 ast_party_id_init(&id);
3592 if (!ast_sip_set_id_from_invite(rdata, &id, &session->endpoint->id.self, session->endpoint->id.trust_inbound)) {
3593 ast_copy_string(buf, id.number.str, len);
3594 res = 0;
3595 }
3596 ast_party_id_free(&id);
3597 return res;
3598}
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:1797
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:2798
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().

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session * generate_session_refresh_sdp ( struct ast_sip_session session)
static

Definition at line 1633 of file res_pjsip_session.c.

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

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

3622{
3623 char cid_num[AST_CHANNEL_NAME];
3624 pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
3625 struct ast_features_pickup_config *pickup_cfg;
3626 const char *pickupexten;
3627
3628 if (!ast_sip_is_allowed_uri(ruri)) {
3630 }
3631
3632 ast_copy_pj_str(session->exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(session->exten));
3633 if (ast_strlen_zero(session->exten)) {
3634 /* Some SIP devices send an empty extension for PLAR: this should map to s */
3635 ast_debug(1, "RURI contains no user portion: defaulting to extension 's'\n");
3636 ast_copy_string(session->exten, "s", sizeof(session->exten));
3637 }
3638
3639 /*
3640 * We may want to match in the dialplan without any user
3641 * options getting in the way.
3642 */
3644
3645 pickup_cfg = ast_get_chan_features_pickup_config(NULL); /* session->channel doesn't exist yet, using NULL */
3646 if (!pickup_cfg) {
3647 ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",
3649 pickupexten = "";
3650 } else {
3651 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
3652 ao2_ref(pickup_cfg, -1);
3653 }
3654
3655 fetch_callerid_num(session, rdata, cid_num, sizeof(cid_num));
3656
3657 /* If there's an overlap_context override specified, use that; otherwise, just use the endpoint's context */
3658
3659 if (!strcmp(session->exten, pickupexten) ||
3660 ast_exists_extension(NULL, S_OR(session->endpoint->overlap_context, session->endpoint->context), session->exten, 1, S_OR(cid_num, NULL))) {
3661 /*
3662 * Save off the INVITE Request-URI in case it is
3663 * needed: CHANNEL(pjsip,request_uri)
3664 */
3665 session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri);
3666
3668 }
3669
3670 /*
3671 * Check for partial match via overlap dialling (if enabled)
3672 */
3673 if (session->endpoint->allow_overlap && (
3674 !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
3675 ast_canmatch_extension(NULL, S_OR(session->endpoint->overlap_context, session->endpoint->context), session->exten, 1, S_OR(cid_num, NULL)))) {
3676 /* Overlap partial match */
3678 }
3679
3681}
#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:4196
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:4211
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:3448
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition res_pjsip.c:3443
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3529
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:2172
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 622 of file res_pjsip_session.c.

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

4465{
4466 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
4468 } else {
4469 handle_incoming_response(session, rdata, response_priority);
4470 }
4471
4472 return 0;
4473}
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 4581 of file res_pjsip_session.c.

4583{
4584 pjsip_msg *msg;
4585 ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4586 "request" : "response");
4587
4588
4590 msg = rdata->msg_info.msg;
4591 if (msg->type == PJSIP_REQUEST_MSG
4592 && msg->line.req.method.id == PJSIP_ACK_METHOD
4593 && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
4594 pjsip_tx_data *tdata;
4595
4596 /*
4597 * SDP negotiation failed on an incoming call that delayed
4598 * negotiation and then gave us an invalid SDP answer. We
4599 * need to send a BYE to end the call because of the invalid
4600 * SDP answer.
4601 */
4602 ast_debug(1,
4603 "%s: Ending session due to incomplete SDP negotiation. %s\n",
4605 pjsip_rx_data_get_info(rdata));
4606 if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
4607 && tdata) {
4609 }
4610 }
4611}
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 4392 of file res_pjsip_session.c.

4393{
4394 struct ast_sip_session_supplement *supplement;
4395 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4396 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));
4397
4398 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4399 if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
4400 if (supplement->incoming_request(session, rdata)) {
4401 break;
4402 }
4403 }
4404 }
4405
4407}
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 4443 of file res_pjsip_session.c.

4445{
4446 struct ast_sip_session_supplement *supplement;
4447 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4448 SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4449 status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4450
4451 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4452 if (!(supplement->response_priority & response_priority)) {
4453 continue;
4454 }
4455 if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4456 supplement->incoming_response(session, rdata);
4457 }
4458 }
4459
4461}
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 774 of file res_pjsip_session.c.

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

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

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

4033{
4034 RAII_VAR(struct ast_sip_endpoint *, endpoint,
4036 pjsip_inv_session *inv_session = NULL;
4037 struct ast_sip_session *session;
4038 struct new_invite invite;
4039 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4040 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4041 SCOPE_ENTER(1, "Request: %s\n", res ? req_uri : "");
4042
4043 ast_assert(endpoint != NULL);
4044
4045 inv_session = pre_session_setup(rdata, endpoint);
4046 if (!inv_session) {
4047 /* pre_session_setup() returns a response on failure */
4048 SCOPE_EXIT_RTN("Failure in pre session setup\n");
4049 }
4050
4051 /*
4052 * Upon a successful pre_session_setup the associated dialog is returned locked
4053 * and with an added reference. Well actually two references. One added when the
4054 * dialog itself was created, and another added when the pjsip invite session was
4055 * created and the dialog was added to it.
4056 *
4057 * In order to ensure the dialog's, and any of its internal attributes, lifetimes
4058 * we'll hold the lock and maintain the reference throughout the entire new invite
4059 * handling process. See ast_sip_create_dialog_uas_locked for more details but,
4060 * basically we do this to make sure a transport failure does not destroy the dialog
4061 * and/or transaction out from underneath us between pjsip calls. Alternatively, we
4062 * could probably release the lock if we needed to, but then we'd have to re-lock and
4063 * check the dialog and transaction prior to every pjsip call.
4064 *
4065 * That means any off nominal/failure paths in this function must remove the associated
4066 * dialog reference added at dialog creation, and remove the lock. As well the
4067 * referenced pjsip invite session must be "cleaned up", which should also then
4068 * remove its reference to the dialog at that time.
4069 *
4070 * Nominally we'll unlock the dialog, and release the reference when all new invite
4071 * process handling has successfully completed.
4072 */
4073
4074 session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
4075 if (!session) {
4076 /* Dialog's lock and reference are removed in new_invite_initial_answer */
4077 if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4078 /* Terminate the session if it wasn't done in the answer */
4079 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
4080 }
4081 SCOPE_EXIT_RTN("Couldn't create session\n");
4082 }
4083 session->call_direction = AST_SIP_SESSION_INCOMING_CALL;
4084
4085 /*
4086 * The current thread is supposed be the session serializer to prevent
4087 * any initial INVITE retransmissions from trying to setup the same
4088 * call again.
4089 */
4091
4092 invite.session = session;
4093 invite.rdata = rdata;
4094 new_invite(&invite);
4095
4096 /*
4097 * The dialog lock and reference added at dialog creation time must be
4098 * maintained throughout the new invite process. Since we're pretty much
4099 * done at this point with things it's safe to go ahead and remove the lock
4100 * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
4101 *
4102 * Note, any future functionality added that does work using the dialog must
4103 * be done before this.
4104 */
4105 pjsip_dlg_dec_lock(inv_session->dlg);
4106
4107 SCOPE_EXIT("Request: %s Session: %s\n", req_uri, ast_sip_session_get_name(session));
4108 ao2_ref(session, -1);
4109}
#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:1061
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 4475 of file res_pjsip_session.c.

4476{
4477 struct ast_sip_session_supplement *supplement;
4478 struct pjsip_request_line req = tdata->msg->line.req;
4479 SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4480 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4481
4482 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4483
4484 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4485 if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
4486 supplement->outgoing_request(session, tdata);
4487 }
4488 }
4490}
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 4492 of file res_pjsip_session.c.

4493{
4494 struct ast_sip_session_supplement *supplement;
4495 struct pjsip_status_line status = tdata->msg->line.status;
4496 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
4497 SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4498 (int) pj_strlen(&cseq->method.name),
4499 pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
4500 pj_strbuf(&status.reason));
4501
4502
4503 if (!cseq) {
4504 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4506 }
4507
4508 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4509
4510 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4511 if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
4512 supplement->outgoing_response(session, tdata);
4513 }
4514 }
4515
4517}
#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 4409 of file res_pjsip_session.c.

4410{
4411 struct ast_sip_session_supplement *iter;
4412
4413 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4414 if (iter->session_begin) {
4415 iter->session_begin(session);
4416 }
4417 }
4418}
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 4420 of file res_pjsip_session.c.

4421{
4422 struct ast_sip_session_supplement *iter;
4423
4424 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4425 if (iter->session_destroy) {
4426 iter->session_destroy(session);
4427 }
4428 }
4429}
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 4431 of file res_pjsip_session.c.

4432{
4433 struct ast_sip_session_supplement *iter;
4434
4435 /* Session is dead. Notify the supplements. */
4436 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4437 if (iter->session_end) {
4438 iter->session_end(session);
4439 }
4440 }
4441}
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 4124 of file res_pjsip_session.c.

4125{
4126 struct ast_sip_session_supplement *supplement;
4127 struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
4128
4129 if (!session) {
4130 return PJ_FALSE;
4131 }
4132
4133 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4134 if (does_method_match(&method->name, supplement->method)) {
4135 return PJ_TRUE;
4136 }
4137 }
4138 return PJ_FALSE;
4139}

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

226{
227 struct ast_sip_session_media_state *media_state;
228
229 media_state = ast_calloc(1, sizeof(*media_state));
230 if (!media_state) {
231 return NULL;
232 }
233
234 if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) {
235 ast_free(media_state);
236 return NULL;
237 }
238
239 if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) {
240 AST_VECTOR_FREE(&media_state->sessions);
241 ast_free(media_state);
242 return NULL;
243 }
244
245 return media_state;
246}
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 1550 of file res_pjsip_session.c.

1551{
1552 struct ast_sip_session *session = vsession;
1553 int res;
1555
1556 if (session->inv_session->invite_tsx) {
1557 /*
1558 * INVITE transaction still active. Let it send
1559 * the collision re-INVITE when it terminates.
1560 */
1561 ao2_ref(session, -1);
1562 res = 0;
1563 } else {
1565 }
1566
1568}
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 1452 of file res_pjsip_session.c.

1453{
1454 struct ast_sip_session *session = vsession;
1455 struct ast_sip_session_delayed_request *delay;
1456 int found = 0;
1457 int res = 0;
1459
1460 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1461 switch (delay->method) {
1463 break;
1466 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1467 delayed_method2str(delay->method));
1468 res = send_delayed_request(session, delay);
1469 delayed_request_free(delay);
1470 if (!res) {
1471 found = 1;
1472 }
1473 break;
1474 case DELAYED_METHOD_BYE:
1475 /* A BYE is pending so don't bother anymore. */
1476 found = 1;
1477 break;
1478 }
1479 if (found) {
1480 break;
1481 }
1482 }
1484
1485 ao2_ref(session, -1);
1487}
#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 1499 of file res_pjsip_session.c.

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

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

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

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

Referenced by resolve_refresh_media_states().

◆ is_stream_limitation_reached()

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

Definition at line 602 of file res_pjsip_session.c.

603{
604 switch (type) {
606 return !(type_streams[type] < endpoint->media.max_audio_streams);
608 return !(type_streams[type] < endpoint->media.max_video_streams);
610 /* We don't have an option for image (T.38) streams so cap it to one. */
611 return (type_streams[type] > 0);
614 default:
615 /* We don't want any unknown or "other" streams on our endpoint,
616 * so always just say we've reached the limit
617 */
618 return 1;
619 }
620}
@ 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 6121 of file res_pjsip_session.c.

6122{
6123 pjsip_endpoint *endpt;
6124
6127 }
6128 if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
6130 }
6135 if (!sdp_handlers) {
6137 }
6139 pjsip_inv_usage_init(endpt, &inv_callback);
6140 pjsip_100rel_init_module(endpt);
6141 pjsip_timer_init_module(endpt);
6144 }
6147
6149
6151#ifdef TEST_FRAMEWORK
6152 AST_TEST_REGISTER(test_resolve_refresh_media_states);
6153#endif
6155}
#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:331
#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 214 of file res_pjsip_session.c.

216{
217 if (vec_elem->local_ssrc == srch->local_ssrc) {
218 return 1;
219 }
220
221 return 0;
222}
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 3888 of file res_pjsip_session.c.

3889{
3890 pjsip_tx_data *tdata = NULL;
3891 pjsip_timer_setting timer;
3892 pjsip_rdata_sdp_info *sdp_info;
3893 pjmedia_sdp_session *local = NULL;
3894 char buffer[AST_SOCKADDR_BUFLEN];
3895 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(invite->session));
3896
3897
3898 /* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
3899 * so that we will be notified so we can destroy the session properly
3900 */
3901
3902 if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
3903 ast_trace_log(-1, LOG_ERROR, "%s: Session already DISCONNECTED [reason=%d (%s)]\n",
3905 invite->session->inv_session->cause,
3906 pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
3908 }
3909
3910 switch (get_destination(invite->session, invite->rdata)) {
3912 /* Things worked. Keep going */
3913 break;
3915 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - unsupported uri\n",
3917 invite->rdata->tp_info.transport->type_name,
3918 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3919 invite->session->exten);
3920 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
3921 ast_sip_session_send_response(invite->session, tdata);
3922 } else {
3923 pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
3924 }
3925 goto end;
3927 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - partial match\n",
3929 invite->rdata->tp_info.transport->type_name,
3930 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3931 invite->session->exten);
3932
3933 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) {
3934 ast_sip_session_send_response(invite->session, tdata);
3935 } else {
3936 pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE);
3937 }
3938 goto end;
3940 default:
3941 ast_trace_log(-1, LOG_NOTICE, "%s: Call (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",
3943 invite->rdata->tp_info.transport->type_name,
3944 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3945 invite->session->exten,
3946 invite->session->endpoint->context);
3947
3948 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) {
3949 ast_sip_session_send_response(invite->session, tdata);
3950 } else {
3951 pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
3952 }
3953 goto end;
3954 };
3955
3956 if (check_content_disposition(invite->rdata)) {
3957 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 415, NULL, NULL, &tdata) == PJ_SUCCESS) {
3958 ast_sip_session_send_response(invite->session, tdata);
3959 } else {
3960 pjsip_inv_terminate(invite->session->inv_session, 415, PJ_TRUE);
3961 }
3962 goto end;
3963 }
3964
3965 pjsip_timer_setting_default(&timer);
3966 timer.min_se = invite->session->endpoint->extensions.timer.min_se;
3967 timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires;
3968 pjsip_timer_init_session(invite->session->inv_session, &timer);
3969
3970 /*
3971 * At this point, we've verified what we can that won't take awhile,
3972 * so let's go ahead and send a 100 Trying out to stop any
3973 * retransmissions.
3974 */
3975 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
3976 if (tdata) {
3977 pjsip_inv_send_msg(invite->session->inv_session, tdata);
3978 } else {
3979 pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
3980 }
3981 goto end;
3982 }
3983
3984 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' sending 100 Trying\n",
3986 invite->rdata->tp_info.transport->type_name,
3987 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3988 invite->session->exten);
3989 ast_sip_session_send_response(invite->session, tdata);
3990
3991 sdp_info = pjsip_rdata_get_sdp_info(invite->rdata);
3992 if (sdp_info && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
3993 if (handle_incoming_sdp(invite->session, sdp_info->sdp)) {
3994 tdata = NULL;
3995 if (pjsip_inv_end_session(invite->session->inv_session, 488, NULL, &tdata) == PJ_SUCCESS
3996 && tdata) {
3997 ast_sip_session_send_response(invite->session, tdata);
3998 }
3999 goto end;
4000 }
4001 /* We are creating a local SDP which is an answer to their offer */
4002 local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp, 0);
4003 } else {
4004 /* We are creating a local SDP which is an offer */
4005 local = create_local_sdp(invite->session->inv_session, invite->session, NULL, 0);
4006 }
4007
4008 /* If we were unable to create a local SDP terminate the session early, it won't go anywhere */
4009 if (!local) {
4010 tdata = NULL;
4011 if (pjsip_inv_end_session(invite->session->inv_session, 500, NULL, &tdata) == PJ_SUCCESS
4012 && tdata) {
4013 ast_sip_session_send_response(invite->session, tdata);
4014 }
4015 goto end;
4016 }
4017
4018 pjsip_inv_set_local_sdp(invite->session->inv_session, local);
4019 pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
4020#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
4021 if (!invite->session->endpoint->preferred_codec_only) {
4022 pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE);
4023 }
4024#endif
4025
4026 handle_incoming_request(invite->session, invite->rdata);
4027
4028end:
4030}
#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:1144
const ast_string_field context
Definition res_pjsip.h:1090
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 3705 of file res_pjsip_session.c.

3707{
3708 pjsip_tx_data *tdata = NULL;
3709 int res = 0;
3710
3711 if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3712 if (pjsip_inv_initial_answer(
3713 inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
3714
3715 pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
3716 res = -1;
3717 } else {
3718 pjsip_inv_send_msg(inv_session, tdata);
3719 }
3720 }
3721
3722 if (answer_code >= 300) {
3723 /*
3724 * A session is ending. The dialog has a reference that needs to be
3725 * removed and holds a lock that needs to be unlocked before returning.
3726 */
3727 pjsip_dlg_dec_lock(inv_session->dlg);
3728 }
3729
3730 return res;
3731}

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

3152{
3153 pjsip_transaction *tsx;
3154 pjsip_dialog *dlg;
3155 pjsip_inv_session *inv;
3156 pjsip_tx_data *tdata;
3157 struct ast_sip_session *session;
3158
3159 if (rdata->msg_info.msg->line.status.code != 401
3160 && rdata->msg_info.msg->line.status.code != 407) {
3161 /* Doesn't pertain to us. Move on */
3162 return PJ_FALSE;
3163 }
3164
3165 tsx = pjsip_rdata_get_tsx(rdata);
3166 dlg = pjsip_rdata_get_dlg(rdata);
3167 if (!dlg || !tsx) {
3168 return PJ_FALSE;
3169 }
3170
3171 if (tsx->method.id != PJSIP_INVITE_METHOD) {
3172 /* Not an INVITE that needs authentication */
3173 return PJ_FALSE;
3174 }
3175
3176 inv = pjsip_dlg_get_inv_session(dlg);
3177 session = inv->mod_data[session_module.id];
3178
3179 if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {
3180 /*
3181 * We cannot handle reINVITE authentication at this
3182 * time because the reINVITE transaction is still in
3183 * progress.
3184 */
3185 ast_debug(3, "%s: A reINVITE is being challenged\n", ast_sip_session_get_name(session));
3186 return PJ_FALSE;
3187 }
3188 ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));
3189
3190 if (++session->authentication_challenge_count > MAX_RX_CHALLENGES) {
3191 ast_debug(3, "%s: Initial INVITE reached maximum number of auth attempts.\n", ast_sip_session_get_name(session));
3192 return PJ_FALSE;
3193 }
3194
3195 if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata,
3196 tsx->last_tx, &tdata)) {
3197 return PJ_FALSE;
3198 }
3199
3200 /*
3201 * Restart the outgoing initial INVITE transaction to deal
3202 * with authentication.
3203 */
3204 pjsip_inv_uac_restart(inv, PJ_FALSE);
3205
3207 return PJ_TRUE;
3208}
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 3752 of file res_pjsip_session.c.

3753{
3754 pjsip_tx_data *tdata;
3755 pjsip_dialog *dlg;
3756 pjsip_inv_session *inv_session;
3757 unsigned int options = endpoint->extensions.flags;
3758 const pj_str_t STR_100REL = { "100rel", 6};
3759 unsigned int i;
3760 pj_status_t dlg_status = PJ_EUNKNOWN;
3761
3762 /*
3763 * If 100rel is set to "peer_supported" on the endpoint and the peer indicated support for 100rel
3764 * in the Supported header, send 1xx responses reliably by adding PJSIP_INV_REQUIRE_100REL to pjsip_inv_options flags.
3765 */
3766 if (endpoint->rel100 == AST_SIP_100REL_PEER_SUPPORTED && rdata->msg_info.supported != NULL) {
3767 for (i = 0; i < rdata->msg_info.supported->count; ++i) {
3768 if (pj_stricmp(&rdata->msg_info.supported->values[i], &STR_100REL) == 0) {
3769 options |= PJSIP_INV_REQUIRE_100REL;
3770 break;
3771 }
3772 }
3773 }
3774
3775 if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
3776 if (tdata) {
3777 if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
3778 pjsip_tx_data_dec_ref(tdata);
3779 }
3780 } else {
3781 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3782 }
3783 return NULL;
3784 }
3785
3786 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, &dlg_status);
3787 if (!dlg) {
3788 if (dlg_status != PJ_EEXISTS) {
3789 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3790 }
3791 return NULL;
3792 }
3793
3794 /*
3795 * The returned dialog holds a lock and has a reference added. Any paths where the
3796 * dialog invite session is not returned must unlock the dialog and remove its reference.
3797 */
3798
3799 if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
3800 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3801 /*
3802 * The acquired dialog holds a lock, and a reference. Since the dialog is not
3803 * going to be returned here it must first be unlocked and de-referenced. This
3804 * must be done prior to calling dialog termination.
3805 */
3806 pjsip_dlg_dec_lock(dlg);
3807 pjsip_dlg_terminate(dlg);
3808 return NULL;
3809 }
3810
3811#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3812 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3813#endif
3814 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3815 /* Dialog's lock and a reference are removed in new_invite_initial_answer */
3816 new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE);
3817 /* Remove 2nd reference added at inv_session creation */
3818 pjsip_dlg_dec_session(inv_session->dlg, &session_module);
3819 return NULL;
3820 }
3821
3822 return inv_session;
3823}
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:1186
@ AST_SIP_100REL_PEER_SUPPORTED
Definition res_pjsip.h:537
enum ast_sip_100rel_mode rel100
Definition res_pjsip.h:1172
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 186 of file res_pjsip_session.c.

187{
188 struct sdp_handler_list *handler_list = obj;
190 struct ast_sip_session_sdp_handler *iter;
191 const char *stream_type = arg;
192
193 AST_LIST_TRAVERSE_SAFE_BEGIN(&handler_list->list, iter, next) {
194 if (!strcmp(iter->id, handler->id)) {
196 ast_debug(1, "Unregistered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
197 }
198 }
200
201 if (AST_LIST_EMPTY(&handler_list->list)) {
202 ast_debug(3, "No more handlers exist for stream type '%s'\n", stream_type);
203 return CMP_MATCH;
204 } else {
205 return CMP_STOP;
206 }
207}
#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 764 of file res_pjsip_session.c.

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

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

4264{
4265 pjsip_inv_session *inv = session->inv_session;
4266 pj_time_val tv;
4267 struct ast_sip_session_media_state *pending_media_state = NULL;
4268 struct ast_sip_session_media_state *active_media_state = NULL;
4269 const char *session_name = ast_sip_session_get_name(session);
4270 int use_pending = 0;
4271 int use_active = 0;
4272
4273 SCOPE_ENTER(3, "%s\n", session_name);
4274
4275 /*
4276 * If the two media state topologies are the same this means that the session refresh request
4277 * did not specify a desired topology, so it does not care. If that is the case we don't even
4278 * pass one in here resulting in the current topology being used. It's possible though that
4279 * either one of the topologies could be NULL so we have to test for that before we check for
4280 * equality.
4281 */
4282
4283 /* We only want to clone a media state if its topology is not null */
4284 use_pending = session->pending_media_state->topology != NULL;
4285 use_active = session->active_media_state->topology != NULL;
4286
4287 /*
4288 * If both media states have topologies, we can test for equality. If they're equal we're not going to
4289 * clone either states.
4290 */
4291 if (use_pending && use_active && ast_stream_topology_equal(session->active_media_state->topology, session->pending_media_state->topology)) {
4292 use_pending = 0;
4293 use_active = 0;
4294 }
4295
4296 if (use_pending) {
4297 pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);
4298 if (!pending_media_state) {
4299 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
4300 }
4301 }
4302
4303 if (use_active) {
4304 active_media_state = ast_sip_session_media_state_clone(session->active_media_state);
4305 if (!active_media_state) {
4306 ast_sip_session_media_state_free(pending_media_state);
4307 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
4308 }
4309 }
4310
4311 if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,
4312 active_media_state, 1)) {
4313 ast_sip_session_media_state_free(pending_media_state);
4314 ast_sip_session_media_state_free(active_media_state);
4315 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
4316 }
4317
4318 if (pj_timer_entry_running(&session->rescheduled_reinvite)) {
4319 /* Timer already running. Something weird is going on. */
4320 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
4321 }
4322
4323 tv.sec = 0;
4324 if (inv->role == PJSIP_ROLE_UAC) {
4325 tv.msec = 2100 + ast_random() % 2000;
4326 } else {
4327 tv.msec = ast_random() % 2000;
4328 }
4329 pj_timer_entry_init(&session->rescheduled_reinvite, 0, session, resend_reinvite);
4330
4331 ao2_ref(session, +1);
4332 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
4333 &session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {
4334 ao2_ref(session, -1);
4335 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
4336 }
4337
4339}
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 4242 of file res_pjsip_session.c.

4243{
4244 struct ast_sip_session *session = entry->user_data;
4245
4246 ast_debug(3, "%s: re-INVITE collision timer expired.\n",
4248
4249 if (AST_LIST_EMPTY(&session->delayed_requests)) {
4250 /* No delayed request pending, so just return */
4251 ao2_ref(session, -1);
4252 return;
4253 }
4255 /*
4256 * Uh oh. We now have nothing in the foreseeable future
4257 * to trigger sending the delayed requests.
4258 */
4259 ao2_ref(session, -1);
4260 }
4261}
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 1848 of file res_pjsip_session.c.

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

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

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

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

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

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

1407{
1408 int res;
1409 SCOPE_ENTER(3, "%s: sending delayed %s request\n",
1411 delayed_method2str(delay->method));
1412
1413 switch (delay->method) {
1416 delay->on_sdp_creation, delay->on_response,
1418 delay->active_media_state, 1);
1419 /* Ownership of media state transitions to ast_sip_session_refresh */
1420 delay->pending_media_state = NULL;
1421 delay->active_media_state = NULL;
1425 delay->on_sdp_creation, delay->on_response,
1427 delay->active_media_state, 1);
1428 /* Ownership of media state transitions to ast_sip_session_refresh */
1429 delay->pending_media_state = NULL;
1430 delay->active_media_state = NULL;
1432 case DELAYED_METHOD_BYE:
1434 SCOPE_EXIT_RTN_VALUE(0, "%s: Terminating session on delayed BYE\n", ast_sip_session_get_name(session));
1435 }
1436
1437 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",
1439 delayed_method2str(delay->method), delay->method);
1440}
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition res_pjsip.h:717
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition res_pjsip.h:715

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

1242{
1243 struct ast_datastore *datastore = obj;
1244
1245 /* Using the destroy function (if present) destroy the data */
1246 if (datastore->info->destroy != NULL && datastore->data != NULL) {
1247 datastore->info->destroy(datastore->data);
1248 datastore->data = NULL;
1249 }
1250
1251 ast_free((void *) datastore->uid);
1252 datastore->uid = NULL;
1253}
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 2921 of file res_pjsip_session.c.

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

Referenced by ast_sip_session_alloc().

◆ session_end()

static int session_end ( void *  vsession)
static

Definition at line 4519 of file res_pjsip_session.c.

4520{
4521 struct ast_sip_session *session = vsession;
4522
4523 /* Stop the scheduled termination */
4525
4526 /* Session is dead. Notify the supplements. */
4528
4529 return 0;
4530}
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 4542 of file res_pjsip_session.c.

4543{
4544 struct ast_sip_session *session = vsession;
4545
4546 ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL);
4547 ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL);
4548
4549 /* Now we can release the ref that was held by session->inv_session */
4551 return 0;
4552}

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

4700{
4701 struct ast_sip_session *session;
4702
4703 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
4704 return 0;
4705 }
4706
4707 /*
4708 * We are locking because ast_sip_dialog_get_session() needs
4709 * the dialog locked to get the session by other threads.
4710 */
4711 pjsip_dlg_inc_lock(inv->dlg);
4712 session = inv->mod_data[id];
4713 inv->mod_data[id] = NULL;
4714 pjsip_dlg_dec_lock(inv->dlg);
4715
4716 /*
4717 * Pass the session ref held by session->inv_session to
4718 * session_end_completion().
4719 */
4720 if (session
4722 /* Do it anyway even though this is not the right thread. */
4724 }
4725
4726 return 1;
4727}

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

5267{
5268 struct ast_sip_session *session = inv->mod_data[session_module.id];
5269 const pjmedia_sdp_session *previous_sdp = NULL;
5270 pjmedia_sdp_session *offer;
5271 int i;
5272 unsigned int ignore_active_stream_topology = 0;
5273
5274 /* We allow PJSIP to produce an SDP if no channel is present. This may result
5275 * in an incorrect SDP occurring, but if no channel is present then we are in
5276 * the midst of a BYE and are hanging up. This ensures that all the code to
5277 * produce an SDP doesn't need to worry about a channel being present or not,
5278 * just in case.
5279 */
5281 if (!session->channel) {
5282 SCOPE_EXIT_RTN("%s: No channel\n", ast_sip_session_get_name(session));
5283 }
5284
5285 /* Some devices send a re-INVITE offer with empty SDP. Asterisk by default return
5286 * an answer with the current used codecs, which is not strictly compliant to RFC
5287 * 3261 (SHOULD requirement). So we detect this condition and include all
5288 * configured codecs in the answer if the workaround is activated. The actual
5289 * logic is in the create_local_sdp function. We can't detect here that we have
5290 * no SDP body in the INVITE, as we don't have access to the message.
5291 */
5292 if (inv->invite_tsx && inv->state == PJSIP_INV_STATE_CONFIRMED
5293 && inv->invite_tsx->method.id == PJSIP_INVITE_METHOD) {
5294 ast_trace(-1, "re-INVITE\n");
5295 if (inv->invite_tsx->role == PJSIP_ROLE_UAS
5297 ast_trace(-1, "UAS role, include all codecs in the answer on empty SDP\n");
5298 ignore_active_stream_topology = 1;
5299 }
5300 }
5301
5302 if (inv->neg) {
5303 if (pjmedia_sdp_neg_was_answer_remote(inv->neg)) {
5304 pjmedia_sdp_neg_get_active_remote(inv->neg, &previous_sdp);
5305 } else {
5306 pjmedia_sdp_neg_get_active_local(inv->neg, &previous_sdp);
5307 }
5308 }
5309
5310 if (ignore_active_stream_topology) {
5311 offer = create_local_sdp(inv, session, NULL, 1);
5312 } else {
5313 offer = create_local_sdp(inv, session, previous_sdp, 0);
5314 }
5315 if (!offer) {
5316 SCOPE_EXIT_RTN("%s: create offer failed\n", ast_sip_session_get_name(session));
5317 }
5318
5319 ast_queue_unhold(session->channel);
5320
5321 /*
5322 * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite).
5323 * When hold is initially indicated, we
5324 * - Receive an INVITE with no SDP
5325 * - Send a 200 OK with SDP, indicating sendrecv in the media streams
5326 * - Receive an ACK with SDP, indicating sendonly in the media streams
5327 *
5328 * At this point, the pjmedia negotiator saves the state of the media direction so that
5329 * if we are to send any offers, we'll offer recvonly in the media streams. This is
5330 * problematic if the device is attempting to unhold, though. If the device unholds
5331 * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly.
5332 * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond
5333 * with sendonly or inactive. The result of this is that the stream is not off hold.
5334 *
5335 * Therefore, in this case, when we receive a reinvite while the stream is on hold, we
5336 * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv
5337 * in order to get the stream off hold. If this is actually a different purpose reinvite
5338 * (like a session timer refresh), then the answerer can respond to our sendrecv with
5339 * sendonly, keeping the stream on hold.
5340 */
5341 for (i = 0; i < offer->media_count; ++i) {
5342 pjmedia_sdp_media *m = offer->media[i];
5343 pjmedia_sdp_attr *recvonly;
5344 pjmedia_sdp_attr *inactive;
5345 pjmedia_sdp_attr *sendonly;
5346
5347 recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL);
5348 inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL);
5349 sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL);
5350 if (recvonly || inactive || sendonly) {
5351 pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly;
5352 pjmedia_sdp_attr *sendrecv;
5353
5354 pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove);
5355
5356 sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL);
5357 pjmedia_sdp_media_add_attr(m, sendrecv);
5358 }
5359 }
5360
5361 *p_offer = offer;
5362 SCOPE_EXIT_RTN("%s: offer created\n", ast_sip_session_get_name(session));
5363}
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition channel.c:1273
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 5365 of file res_pjsip_session.c.

5366{
5367 struct ast_sip_session *session = inv->mod_data[session_module.id];
5368 const pjmedia_sdp_session *local, *remote;
5370
5371 if (ast_shutdown_final()) {
5372 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5373 }
5374
5375 session = inv->mod_data[session_module.id];
5376 if (!session || !session->channel) {
5377 /*
5378 * If we don't have a session or channel then we really
5379 * don't care about media updates.
5380 * Just ignore
5381 */
5382 SCOPE_EXIT_RTN("%s: No channel or session\n", ast_sip_session_get_name(session));
5383 }
5384
5385 if (session->endpoint) {
5386 int bail = 0;
5387
5388 /*
5389 * If following_fork is set, then this is probably the result of a
5390 * forked INVITE and SDP asnwers coming from the different fork UAS
5391 * destinations. In this case updated_sdp_answer will also be set.
5392 *
5393 * If only updated_sdp_answer is set, then this is the non-forking
5394 * scenario where the same UAS just needs to change something like
5395 * the media port.
5396 */
5397
5398 if (inv->following_fork) {
5399 if (session->endpoint->media.rtp.follow_early_media_fork) {
5400 ast_trace(-1, "%s: Following early media fork with different To tags\n", ast_sip_session_get_name(session));
5401 } else {
5402 ast_trace(-1, "%s: Not following early media fork with different To tags\n", ast_sip_session_get_name(session));
5403 bail = 1;
5404 }
5405 }
5406#ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS
5407 else if (inv->updated_sdp_answer) {
5408 if (session->endpoint->media.rtp.accept_multiple_sdp_answers) {
5409 ast_trace(-1, "%s: Accepting updated SDP with same To tag\n", ast_sip_session_get_name(session));
5410 } else {
5411 ast_trace(-1, "%s: Ignoring updated SDP answer with same To tag\n", ast_sip_session_get_name(session));
5412 bail = 1;
5413 }
5414 }
5415#endif
5416 if (bail) {
5418 }
5419 }
5420
5421 if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||
5422 (pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {
5424 ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
5425 ast_queue_hangup(session->channel);
5426 SCOPE_EXIT_RTN("%s: Couldn't get active or local or remote negotiator. Hanging up\n", ast_sip_session_get_name(session));
5427 }
5428
5429 if (handle_negotiated_sdp(session, local, remote)) {
5430 ast_sip_session_media_state_reset(session->pending_media_state);
5431 SCOPE_EXIT_RTN("%s: handle_negotiated_sdp failed. Resetting pending media state\n", ast_sip_session_get_name(session));
5432 }
5434}
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:1181
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:2496
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 4694 of file res_pjsip_session.c.

4695{
4696 /* XXX STUB */
4697}

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

5437{
5438 struct ast_sip_session *session;
5439 const pjsip_sip_uri *uri;
5440
5441 if (ast_shutdown_final()) {
5442 return PJSIP_REDIRECT_STOP;
5443 }
5444
5445 session = inv->mod_data[session_module.id];
5446 if (!session || !session->channel) {
5447 return PJSIP_REDIRECT_STOP;
5448 }
5449
5450 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_PJSIP) {
5451 return PJSIP_REDIRECT_ACCEPT;
5452 }
5453
5454 if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
5455 return PJSIP_REDIRECT_STOP;
5456 }
5457
5459
5460 uri = pjsip_uri_get_uri(target);
5461
5462 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
5464
5465 ast_copy_pj_str(exten, &uri->user, sizeof(exten));
5466
5467 /*
5468 * We may want to match in the dialplan without any user
5469 * options getting in the way.
5470 */
5472
5473 ast_channel_call_forward_set(session->channel, exten);
5474 } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
5475 char target_uri[PJSIP_MAX_URL_SIZE];
5476 /* PJSIP/ + endpoint length + / + max URL size */
5477 char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
5478
5479 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
5480 sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
5481 ast_channel_call_forward_set(session->channel, forward);
5482 }
5483
5484 return PJSIP_REDIRECT_STOP;
5485}
#define AST_MAX_EXTENSION
Definition channel.h:134
@ AST_SIP_REDIRECT_URI_CORE
Definition res_pjsip.h:748
@ AST_SIP_REDIRECT_URI_PJSIP
Definition res_pjsip.h:750
@ AST_SIP_REDIRECT_USER
Definition res_pjsip.h:746
@ 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 5243 of file res_pjsip_session.c.

5244{
5245 struct ast_sip_session *session = inv->mod_data[session_module.id];
5246 pjmedia_sdp_session *answer;
5248
5249 if (ast_shutdown_final()) {
5250 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5251 }
5252
5253 session = inv->mod_data[session_module.id];
5254 if (handle_incoming_sdp(session, offer)) {
5255 ast_sip_session_media_state_reset(session->pending_media_state);
5256 SCOPE_EXIT_RTN("%s: handle_incoming_sdp failed\n", ast_sip_session_get_name(session));
5257 }
5258
5259 if ((answer = create_local_sdp(inv, session, offer, 0))) {
5260 pjsip_inv_set_sdp_answer(inv, answer);
5261 SCOPE_EXIT_RTN("%s: Set SDP answer\n", ast_sip_session_get_name(session));
5262 }
5263 SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));
5264}

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

4614{
4615 pjsip_event_id_e type;
4616 struct ast_sip_session *session = inv->mod_data[session_module.id];
4617 SCOPE_ENTER(1, "%s Event: %s Inv State: %s\n", ast_sip_session_get_name(session),
4618 pjsip_event_str(e->type), pjsip_inv_state_name(inv->state));
4619
4620 if (ast_shutdown_final()) {
4621 SCOPE_EXIT_RTN("Shutting down\n");
4622 }
4623
4624 if (e) {
4625 print_debug_details(inv, NULL, e);
4626 type = e->type;
4627 } else {
4628 type = PJSIP_EVENT_UNKNOWN;
4629 }
4630
4631 session = inv->mod_data[session_module.id];
4632 if (!session) {
4633 SCOPE_EXIT_RTN("No session\n");
4634 }
4635
4636 switch(type) {
4637 case PJSIP_EVENT_TX_MSG:
4638 break;
4639 case PJSIP_EVENT_RX_MSG:
4640 handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);
4641 break;
4642 case PJSIP_EVENT_TSX_STATE:
4643 ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),
4644 pjsip_event_str(e->body.tsx_state.type));
4645 /* Transaction state changes are prompted by some other underlying event. */
4646 switch(e->body.tsx_state.type) {
4647 case PJSIP_EVENT_TX_MSG:
4648 break;
4649 case PJSIP_EVENT_RX_MSG:
4650 if (!check_request_status(inv, e)) {
4651 handle_incoming_before_media(inv, session, e->body.tsx_state.src.rdata);
4652 }
4653 break;
4654 case PJSIP_EVENT_TRANSPORT_ERROR:
4655 case PJSIP_EVENT_TIMER:
4656 /*
4657 * Check the request status on transport error or timeout. A transport
4658 * error can occur when a TCP socket closes and that can be the result
4659 * of a 503. Also we may need to failover on a timeout (408).
4660 */
4661 check_request_status(inv, e);
4662 break;
4663 case PJSIP_EVENT_USER:
4664 case PJSIP_EVENT_UNKNOWN:
4665 case PJSIP_EVENT_TSX_STATE:
4666 /* Inception? */
4667 break;
4668 }
4669 break;
4670 case PJSIP_EVENT_TRANSPORT_ERROR:
4671 case PJSIP_EVENT_TIMER:
4672 case PJSIP_EVENT_UNKNOWN:
4673 case PJSIP_EVENT_USER:
4674 default:
4675 break;
4676 }
4677
4678 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
4679 if (session->defer_end) {
4680 ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));
4681 session->ended_while_deferred = 1;
4682 SCOPE_EXIT_RTN("Deferring\n");
4683 }
4684
4685 if (ast_sip_push_task(session->serializer, session_end, session)) {
4686 /* Do it anyway even though this is not the right thread. */
4688 }
4689 }
4690
4692}
#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 4729 of file res_pjsip_session.c.

4730{
4732 int id = session_module.id;
4733 pjsip_tx_data *tdata;
4734 struct ast_sip_session *session = inv->mod_data[session_module.id];
4735 SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4736 pjsip_tsx_state_str(tsx->state), pjsip_inv_state_name(inv->state));
4737
4738 if (ast_shutdown_final()) {
4739 SCOPE_EXIT_RTN("Shutting down\n");
4740 }
4741
4742 session = inv->mod_data[id];
4743
4744 print_debug_details(inv, tsx, e);
4745 if (!session) {
4746 /* The session has ended. Ignore the transaction change. */
4747 SCOPE_EXIT_RTN("Session ended\n");
4748 }
4749
4750 /*
4751 * If the session is disconnected really nothing else to do unless currently transacting
4752 * a BYE. If a BYE then hold off destruction until the transaction timeout occurs. This
4753 * has to be done for BYEs because sometimes the dialog can be in a disconnected
4754 * state but the BYE request transaction has not yet completed.
4755 */
4756 if (tsx->method.id != PJSIP_BYE_METHOD && session_end_if_disconnected(id, inv)) {
4757 SCOPE_EXIT_RTN("Disconnected\n");
4758 }
4759
4760 switch (e->body.tsx_state.type) {
4761 case PJSIP_EVENT_TX_MSG:
4762 /* When we create an outgoing request, we do not have access to the transaction that
4763 * is created. Instead, We have to place transaction-specific data in the tdata. Here,
4764 * we transfer the data into the transaction. This way, when we receive a response, we
4765 * can dig this data out again
4766 */
4767 tsx->mod_data[id] = e->body.tsx_state.src.tdata->mod_data[id];
4768 break;
4769 case PJSIP_EVENT_RX_MSG:
4770 cb = ast_sip_mod_data_get(tsx->mod_data, id, MOD_DATA_ON_RESPONSE);
4771 /* As the PJSIP invite session implementation responds with a 200 OK before we have a
4772 * chance to be invoked session supplements for BYE requests actually end up executing
4773 * in the invite session state callback as well. To prevent session supplements from
4774 * running on the BYE request again we explicitly squash invocation of them here.
4775 */
4776 if ((e->body.tsx_state.src.rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) ||
4777 (tsx->method.id != PJSIP_BYE_METHOD)) {
4778 handle_incoming(session, e->body.tsx_state.src.rdata,
4780 }
4781 if (tsx->method.id == PJSIP_INVITE_METHOD) {
4782 if (tsx->role == PJSIP_ROLE_UAC) {
4783 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
4784 /* This means we got a non 2XX final response to our outgoing INVITE */
4785 if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
4787 SCOPE_EXIT_RTN("Non 2XX final response\n");
4788 }
4789 if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
4790 ast_debug(1, "%s: reINVITE received final response code %d\n",
4792 tsx->status_code);
4793 if ((tsx->status_code == 401 || tsx->status_code == 407
4794 || (session->endpoint->security_negotiation && tsx->status_code == 494))
4795 && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
4797 &session->endpoint->outbound_auths,
4798 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
4799 /* Send authed reINVITE */
4801 SCOPE_EXIT_RTN("Sending authed reinvite\n");
4802 }
4803 /* Per RFC3261 14.1 a response to a re-INVITE should only terminate
4804 * the dialog if a 481 or 408 occurs. All other responses should leave
4805 * the dialog untouched.
4806 */
4807 if (tsx->status_code == 481 || tsx->status_code == 408) {
4808 if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
4809 && tdata) {
4811 }
4812 }
4813 }
4814 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
4815 if (!inv->cancelling
4816 && inv->role == PJSIP_ROLE_UAC
4817 && inv->state == PJSIP_INV_STATE_CONFIRMED
4818 && pjmedia_sdp_neg_was_answer_remote(inv->neg)
4819 && pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE
4821 ) {
4822 /*
4823 * We didn't send a CANCEL but the UAS sent us the 200 OK with an invalid or unacceptable codec SDP.
4824 * In this case the SDP negotiation is incomplete and PJPROJECT has already sent the ACK.
4825 * So, we send the BYE with 503 status code here. And the actual hangup cause code is already set
4826 * to AST_CAUSE_BEARERCAPABILITY_NOTAVAIL by the session_inv_on_media_update(), setting the 503
4827 * status code doesn't affect to hangup cause code.
4828 */
4829 ast_debug(1, "Endpoint '%s(%s)': Ending session due to 200 OK with incomplete SDP negotiation. %s\n",
4831 session->channel ? ast_channel_name(session->channel) : "",
4832 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4833 pjsip_inv_end_session(session->inv_session, 503, NULL, &tdata);
4834 SCOPE_EXIT_RTN("Incomplete SDP negotiation\n");
4835 }
4836
4837 if (inv->cancelling && tsx->status_code == PJSIP_SC_OK) {
4838 int sdp_negotiation_done =
4839 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE;
4840
4841 /*
4842 * We can get here for the following reasons.
4843 *
4844 * 1) The race condition detailed in RFC5407 section 3.1.2.
4845 * We sent a CANCEL at the same time that the UAS sent us a
4846 * 200 OK with a valid SDP for the original INVITE. As a
4847 * result, we have now received a 200 OK for a cancelled
4848 * call and the SDP negotiation is complete. We need to
4849 * immediately send a BYE to end the dialog.
4850 *
4851 * 2) We sent a CANCEL and hit the race condition but the
4852 * UAS sent us an invalid SDP with the 200 OK. In this case
4853 * the SDP negotiation is incomplete and PJPROJECT has
4854 * already sent the BYE for us because of the invalid SDP.
4855 */
4856 ast_test_suite_event_notify("PJSIP_SESSION_CANCELED",
4857 "Endpoint: %s\r\n"
4858 "Channel: %s\r\n"
4859 "Message: %s\r\n"
4860 "SDP: %s",
4862 session->channel ? ast_channel_name(session->channel) : "",
4863 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata),
4864 sdp_negotiation_done ? "complete" : "incomplete");
4865 if (!sdp_negotiation_done) {
4866 ast_debug(1, "%s: Incomplete SDP negotiation cancelled session. %s\n",
4868 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4869 } else if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
4870 && tdata) {
4871 ast_debug(1, "%s: Ending session due to RFC5407 race condition. %s\n",
4873 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
4875 }
4876 }
4877 }
4878 }
4879 } else {
4880 /* All other methods */
4881 if (tsx->role == PJSIP_ROLE_UAC) {
4882 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
4883 /* This means we got a final response to our outgoing method */
4884 ast_debug(1, "%s: %.*s received final response code %d\n",
4886 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4887 tsx->status_code);
4888 if ((tsx->status_code == 401 || tsx->status_code == 407 || tsx->status_code == 494)
4889 && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
4891 &session->endpoint->outbound_auths,
4892 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
4893 /* Send authed version of the method */
4895 SCOPE_EXIT_RTN("Sending authed %.*s\n",
4896 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name));
4897 }
4898 }
4899 }
4900 }
4901 if (cb) {
4902 cb(session, e->body.tsx_state.src.rdata);
4903 }
4904 break;
4905 case PJSIP_EVENT_TRANSPORT_ERROR:
4906 case PJSIP_EVENT_TIMER:
4907 /*
4908 * The timer event is run by the pjsip monitor thread and not
4909 * by the session serializer.
4910 */
4911 if (session_end_if_disconnected(id, inv)) {
4912 SCOPE_EXIT_RTN("Disconnected\n");
4913 }
4914 break;
4915 case PJSIP_EVENT_USER:
4916 case PJSIP_EVENT_UNKNOWN:
4917 case PJSIP_EVENT_TSX_STATE:
4918 /* Inception? */
4919 break;
4920 }
4921
4922 if (AST_LIST_EMPTY(&session->delayed_requests)) {
4923 /* No delayed request pending, so just return */
4924 SCOPE_EXIT_RTN("Nothing delayed\n");
4925 }
4926
4927 if (tsx->method.id == PJSIP_INVITE_METHOD) {
4928 if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
4929 ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
4931 pjsip_tsx_state_str(tsx->state));
4933 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
4934 /*
4935 * Terminated INVITE transactions always should result in
4936 * queuing delayed requests, no matter what event caused
4937 * the transaction to terminate.
4938 */
4939 ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
4941 pjsip_tsx_state_str(tsx->state));
4943 }
4944 } else if (tsx->role == PJSIP_ROLE_UAC
4945 && tsx->state == PJSIP_TSX_STATE_COMPLETED
4946 && !pj_strcmp2(&tsx->method.name, "UPDATE")) {
4947 ast_debug(3, "%s: UPDATE delay check. tsx-state:%s\n",
4949 pjsip_tsx_state_str(tsx->state));
4951 }
4952
4954}
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:3092
static int invite_proceeding(void *vsession)
static int update_completed(void *vsession)
static void check_delayed_requests(struct ast_sip_session *session, int(*cb)(void *vsession))
static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session_response_cb on_response)
static int session_end_if_disconnected(int id, pjsip_inv_session *inv)
@ AST_SIP_SESSION_AFTER_MEDIA
int(* ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata)

References AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, ast_channel_hangupcause(), ast_channel_name(), ast_debug, AST_LIST_EMPTY, ast_shutdown_final(), ast_sip_create_request_with_auth(), ast_sip_mod_data_get, AST_SIP_SESSION_AFTER_MEDIA, ast_sip_session_get_name(), ast_sip_session_send_request(), ast_sip_session_send_request_with_cb(), ast_sorcery_object_get_id(), ast_test_suite_event_notify, check_delayed_requests(), handle_incoming(), id, invite_proceeding(), invite_terminated(), MAX_RX_CHALLENGES, MOD_DATA_ON_RESPONSE, NULL, print_debug_details, reschedule_reinvite(), SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end_if_disconnected(), session_module, and update_completed().

◆ session_media_dtor()

static void session_media_dtor ( void *  obj)
static

Definition at line 479 of file res_pjsip_session.c.

480{
481 struct ast_sip_session_media *session_media = obj;
482
483 /* It is possible for multiple handlers to have allocated memory on the
484 * session media (usually through a stream changing types). Therefore, we
485 * traverse all the SDP handlers and let them all call stream_destroy on
486 * the session_media
487 */
488 ao2_callback(sdp_handlers, 0, stream_destroy, session_media);
489
490 if (session_media->srtp) {
491 ast_sdp_srtp_destroy(session_media->srtp);
492 }
493
494 ast_free(session_media->mid);
495 ast_free(session_media->remote_mslabel);
496 ast_free(session_media->remote_label);
497 ast_free(session_media->stream_name);
498}
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 455 of file res_pjsip_session.c.

457{
458 ast_assert(session_media->handler != handler);
459
460 if (session_media->handler) {
461 session_media->handler->stream_destroy(session_media);
462 }
463 session_media->handler = handler;
464}
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 4197 of file res_pjsip_session.c.

4198{
4199 pj_status_t handled = PJ_FALSE;
4200 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4201 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4202 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4203 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4204 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4205 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4206 SCOPE_ENTER(1, "%s Request: %.*s %s\n", ast_sip_session_get_name(session),
4207 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), res ? req_uri : "");
4208
4209 switch (req.method.id) {
4210 case PJSIP_INVITE_METHOD:
4211 if (dlg) {
4212 ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
4213 break;
4214 }
4215 handled = PJ_TRUE;
4217 break;
4218 default:
4219 /* Handle other in-dialog methods if their supplements have been registered */
4220 handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
4221 has_supplement(inv_session->mod_data[session_module.id], rdata);
4222 break;
4223 }
4224
4225 SCOPE_EXIT_RTN_VALUE(handled, "%s Handled request %.*s %s ? %s\n", ast_sip_session_get_name(session),
4226 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), req_uri,
4227 handled == PJ_TRUE ? "yes" : "no");
4228}
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 4167 of file res_pjsip_session.c.

4168{
4169
4170 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4171 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4172 pjsip_inv_session *inv_session = dlg ? pjsip_dlg_get_inv_session(dlg) : NULL;
4173 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4174 SCOPE_ENTER(1, "%s Method: %.*s Status: %d\n", ast_sip_session_get_name(session),
4175 (int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
4176
4177 SCOPE_EXIT_RTN_VALUE(PJ_FALSE);
4178}

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

4146{
4147
4148 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
4149 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4150 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4151 SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4152 pjsip_tsx_state_str(tsx->state), inv_session ? pjsip_inv_state_name(inv_session->state) : "unknown");
4153
4154 if (session) {
4155 ast_trace(2, "Topology: Pending: %s Active: %s\n",
4156 ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)),
4157 ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
4158 }
4159
4161}

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

4232{
4233 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
4235 if (session) {
4237 }
4238
4239 return PJ_SUCCESS;
4240}

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

5499{
5502 tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK);
5503 pjsip_sdp_info *sdp_info;
5504 pjmedia_sdp_session *sdp;
5505 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
5507 int stream;
5508
5509 /*
5510 * If there's no transport_state or body, or the hook
5511 * has already been run, just return.
5512 */
5513 if (ast_strlen_zero(transport->external_media_address) || !transport_state || hook || !tdata->msg->body) {
5514 return;
5515 }
5516
5517 sdp_info = pjsip_get_sdp_info(tdata->pool, tdata->msg->body, NULL, &pjsip_media_type_application_sdp);
5518 if (sdp_info->sdp_err != PJ_SUCCESS || !sdp_info->sdp) {
5519 return;
5520 }
5521 sdp = sdp_info->sdp;
5522
5523 if (sdp->conn) {
5524 char host[NI_MAXHOST];
5525 struct ast_sockaddr our_sdp_addr = { { 0, } };
5526
5527 ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
5528 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
5529
5530 /* Reversed check here. We don't check the remote
5531 * endpoint being in our local net, but whether our
5532 * outgoing session IP is local. If it is, we'll do
5533 * rewriting. No localnet configured? Always rewrite. */
5534 if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {
5535 ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),
5536 ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5537 pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5538 pj_strassign(&sdp->origin.addr, &sdp->conn->addr);
5539 }
5540 }
5541
5542 for (stream = 0; stream < sdp->media_count; ++stream) {
5543 /* See if there are registered handlers for this media stream type */
5544 char media[20];
5546 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5547
5548 /* We need a null-terminated version of the media string */
5549 ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
5550
5551 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
5552 if (!handler_list) {
5553 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session),
5554 media);
5555 continue;
5556 }
5557 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5558 if (handler->change_outgoing_sdp_stream_media_address) {
5559 handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
5560 }
5561 }
5562 }
5563
5564 /* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
5565 ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK, nat_hook);
5566}
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:3906
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
#define MOD_DATA_NAT_HOOK
Structure for SIP nat hook information.
Definition res_pjsip.h:327
Structure for SIP transport information.
Definition res_pjsip.h:117
const ast_string_field external_media_address
Definition res_pjsip.h:239
Socket address structure.
Definition netsock2.h:97

References ao2_cleanup, ao2_find, ast_copy_pj_str(), ast_debug, AST_LIST_TRAVERSE, ast_sip_dialog_get_session(), ast_sip_get_transport_state(), ast_sip_mod_data_get, ast_sip_mod_data_set, ast_sip_session_get_name(), ast_sip_transport_is_local, ast_sockaddr_parse(), ast_sockaddr_stringify_addr_remote(), ast_sorcery_object_get_id(), ast_strlen_zero(), ast_sip_transport::external_media_address, handler(), MOD_DATA_NAT_HOOK, nat_hook, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, PARSE_PORT_FORBID, pjsip_media_type_application_sdp, RAII_VAR, sdp_handlers, session, and session_module.

Referenced by load_module().

◆ session_reinvite_on_rx_request()

static pj_bool_t session_reinvite_on_rx_request ( pjsip_rx_data *  rdata)
static

Definition at line 2754 of file res_pjsip_session.c.

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

3466{
3467 struct ast_sip_session *session = entry->user_data;
3468
3471 }
3472}
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 3450 of file res_pjsip_session.c.

3451{
3452 struct ast_sip_session *session = data;
3453
3454 if (session->defer_terminate) {
3455 session->defer_terminate = 0;
3456 if (session->inv_session) {
3458 }
3459 }
3460
3461 ao2_ref(session, -1);
3462 return 0;
3463}

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

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

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

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

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

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

◆ set_remote_mslabel_and_stream_group()

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

Definition at line 694 of file res_pjsip_session.c.

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

3227{
3228 pj_status_t status;
3229
3230 ++dlg->sess_count;
3231 status = pjsip_dlg_add_usage(dlg, &outbound_invite_auth_module, NULL);
3232 --dlg->sess_count;
3233
3234 return status != PJ_SUCCESS ? -1 : 0;
3235}

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

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

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

3507{
3508 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
3509 &session->scheduled_termination, session->scheduled_termination.id)) {
3510 ao2_ref(session, -1);
3511 }
3512}

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

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

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

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

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

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6157 of file res_pjsip_session.c.

6158{
6160
6161#ifdef TEST_FRAMEWORK
6162 AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6163#endif
6170 return 0;
6171}
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 1580 of file res_pjsip_session.c.

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

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6179 of file res_pjsip_session.c.

◆ inv_callback

pjsip_inv_callback inv_callback
static

Definition at line 5487 of file res_pjsip_session.c.

5487 {
5488 .on_state_changed = session_inv_on_state_changed,
5489 .on_new_session = session_inv_on_new_session,
5490 .on_tsx_state_changed = session_inv_on_tsx_state_changed,
5491 .on_rx_offer = session_inv_on_rx_offer,
5492 .on_create_offer = session_inv_on_create_offer,
5493 .on_media_update = session_inv_on_media_update,
5494 .on_redirected = session_inv_on_redirected,
5495};
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 87 of file res_pjsip_session.c.

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

◆ outbound_invite_auth_module

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

Definition at line 3210 of file res_pjsip_session.c.

3210 {
3211 .name = {"Outbound INVITE Auth", 20},
3212 .priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
3213 .on_rx_response = outbound_invite_auth,
3214};

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

2607 {
2608 .name = {"Session Module", 14},
2609 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
2610 .on_rx_request = session_on_rx_request,
2611 .on_rx_response = session_on_rx_response,
2612 .on_tsx_state = session_on_tsx_state,
2613 .on_tx_response = session_on_tx_response,
2614};
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(), session_outgoing_nat_hook(), 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 2833 of file res_pjsip_session.c.

2833 {
2834 .name = { "Session Re-Invite Module", 24 },
2835 .priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
2836 .on_rx_request = session_reinvite_on_rx_request,
2837};

Referenced by load_module(), and unload_module().