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

Go to the source code of this file.

Data Structures

struct  ast_sip_session_delayed_request
 Structure used for sending delayed requests. More...
 
struct  new_invite
 
struct  sdp_handler_list
 
struct  sip_session_media_bundle_group
 Bundle group building structure. More...
 

Macros

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

Enumerations

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

Functions

static void __print_debug_details (const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_bundle_groups (struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer)
 
static int add_sdp_streams (struct ast_sip_session_media *session_media, struct ast_sip_session *session, pjmedia_sdp_session *answer, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
 
struct ast_module * AST_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_pvt * ast_sip_channel_pvt_alloc (void *pvt, struct ast_sip_session *session)
 Allocate a new SIP channel pvt structure.
 
struct ast_sip_session * ast_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_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.
 
struct ast_datastore * ast_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_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.
 
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_datastore * ast_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_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.
 
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_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.
 
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc (void)
 Allocate a session media state structure.
 
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.
 
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_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 void delayed_request_free (struct ast_sip_session_delayed_request *delay)
 
static pj_bool_t does_method_match (const pj_str_t *message_method, const char *supplement_method)
 
static int fetch_callerid_num (struct ast_sip_session *session, pjsip_rx_data *rdata, char *buf, size_t len)
 Fetch just the Caller ID number in order of PAI, RPID, From.
 
static void flush_delayed_requests (struct ast_sip_session *session)
 
static pjmedia_sdp_session * generate_session_refresh_sdp (struct ast_sip_session *session)
 
static enum sip_get_destination_result get_destination (struct ast_sip_session *session, pjsip_rx_data *rdata)
 Determine where in the dialplan a call should go.
 
static int get_mid_bundle_group (const pjmedia_sdp_session *sdp, const char *mid)
 
static int handle_incoming (struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
 
static void handle_incoming_before_media (pjsip_inv_session *inv, struct ast_sip_session *session, pjsip_rx_data *rdata)
 
static void handle_incoming_request (struct ast_sip_session *session, pjsip_rx_data *rdata)
 
static void handle_incoming_response (struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority)
 
static int handle_incoming_sdp (struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
 
static int handle_negotiated_sdp (struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
 
static int handle_negotiated_sdp_session_media (struct ast_sip_session_media *session_media, struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
 
static void handle_new_invite_request (pjsip_rx_data *rdata)
 
static void handle_outgoing_request (struct ast_sip_session *session, pjsip_tx_data *tdata)
 
static void handle_outgoing_response (struct ast_sip_session *session, pjsip_tx_data *tdata)
 
static void handle_session_begin (struct ast_sip_session *session)
 
static void handle_session_destroy (struct ast_sip_session *session)
 
static void handle_session_end (struct ast_sip_session *session)
 
static pj_bool_t has_supplement (const struct ast_sip_session *session, const pjsip_rx_data *rdata)
 
static struct ast_sip_session_media_state * internal_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_bundle_only_stream (const struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream)
 Determine whether a zero-port stream is offered for BUNDLE-only use.
 
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_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 int sdp_handler_list_cmp (void *obj, void *arg, int flags)
 
static int sdp_handler_list_hash (const void *obj, int flags)
 
static int sdp_requires_deferral (struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
 Determine whether the SDP provided requires deferral of negotiating or not.
 
static int send_delayed_request (struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
 
static void session_datastore_destroy (void *obj)
 
static void session_destructor (void *obj)
 
static int session_end (void *vsession)
 
static int session_end_completion (void *vsession)
 
static int session_end_if_disconnected (int id, pjsip_inv_session *inv)
 
static void session_inv_on_create_offer (pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
 
static void session_inv_on_media_update (pjsip_inv_session *inv, pj_status_t status)
 
static void session_inv_on_new_session (pjsip_inv_session *inv, pjsip_event *e)
 
static pjsip_redirect_op session_inv_on_redirected (pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
 
static void session_inv_on_rx_offer (pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
 
static void session_inv_on_state_changed (pjsip_inv_session *inv, pjsip_event *e)
 
static void session_inv_on_tsx_state_changed (pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
 
static void session_media_dtor (void *obj)
 
static void session_media_set_handler (struct ast_sip_session_media *session_media, struct ast_sip_session_sdp_handler *handler)
 Set an SDP stream handler for a corresponding session media.
 
static pj_bool_t session_on_rx_request (pjsip_rx_data *rdata)
 Called when a new SIP request comes into PJSIP.
 
static pj_bool_t session_on_rx_response (pjsip_rx_data *rdata)
 
static void session_on_tsx_state (pjsip_transaction *tsx, pjsip_event *e)
 
static pj_status_t session_on_tx_response (pjsip_tx_data *tdata)
 
static void session_outgoing_nat_hook (pjsip_tx_data *tdata, struct ast_sip_transport *transport)
 Hook for modifying outgoing messages with SDP to contain the proper address information.
 
static pj_bool_t session_reinvite_on_rx_request (pjsip_rx_data *rdata)
 
static void session_termination_cb (pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
 
static int session_termination_task (void *data)
 
static void set_from_header (struct ast_sip_session *session)
 
static int set_mid_and_bundle_group (struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
 
static int set_outstanding_invite_timeout (struct ast_sip_session *session)
 
static void set_remote_mslabel_and_stream_group (struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream, struct ast_stream *asterisk_stream)
 
static int setup_outbound_invite_auth (pjsip_dialog *dlg)
 
static void sip_channel_destroy (void *obj)
 Destructor for SIP channel.
 
static void sip_session_defer_termination_stop_timer (struct ast_sip_session *session)
 
static int sip_session_refresh (struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queued)
 
static int stream_destroy (void *obj, void *arg, int flags)
 
static int uac_invite_tsx_terminates_dialog (pjsip_transaction *tsx)
 
static int unload_module (void)
 
static int update_completed (void *vsession)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Session resource" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
 
static const struct ast_module_info * ast_module_info = &__mod_info
 
static pjsip_inv_callback inv_callback
 
static struct ast_sip_nat_hook * nat_hook
 NAT hook for modifying outgoing messages with SDP.
 
static pjsip_module outbound_invite_auth_module
 
static struct ao2_container * sdp_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 1272 of file res_pjsip_session.c.

◆ DEFAULT_NUM_SESSION_MEDIA

#define DEFAULT_NUM_SESSION_MEDIA   2

Definition at line 63 of file res_pjsip_session.c.

◆ GET_STREAM_NAME_SAFE

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

Definition at line 1851 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 1849 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 1850 of file res_pjsip_session.c.

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1273 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,
  e 
)    __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e))

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

◆ STATE_REMOVED

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

Definition at line 1847 of file res_pjsip_session.c.

◆ STREAM_REMOVED

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

Definition at line 1846 of file res_pjsip_session.c.

Enumeration Type Documentation

◆ delayed_method

Enumerator
DELAYED_METHOD_INVITE 
DELAYED_METHOD_UPDATE 
DELAYED_METHOD_BYE 

Definition at line 1341 of file res_pjsip_session.c.

1341 {
1345};
@ 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 3715 of file res_pjsip_session.c.

3715 {
3716 /*! The extension was successfully found */
3718 /*! The extension specified in the RURI was not found */
3720 /*! The extension specified in the RURI was a partial match */
3722 /*! The RURI is of an unsupported scheme */
3724};
@ 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 4456 of file res_pjsip_session.c.

4457{
4458 int id = session_module.id;
4459 struct ast_sip_session *session = NULL;
4460
4461 if (!DEBUG_ATLEAST(5)) {
4462 /* Debug not spamy enough */
4463 return;
4464 }
4465
4466 ast_log(LOG_DEBUG, "Function %s called on event %s\n",
4467 function, pjsip_event_str(e->type));
4468 if (!inv) {
4469 ast_log(LOG_DEBUG, "Transaction %p does not belong to an inv_session?\n", tsx);
4470 ast_log(LOG_DEBUG, "The transaction state is %s\n",
4471 pjsip_tsx_state_str(tsx->state));
4472 return;
4473 }
4474 if (id > -1) {
4475 session = inv->mod_data[session_module.id];
4476 }
4477 if (!session) {
4478 ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv);
4479 } else {
4480 ast_log(LOG_DEBUG, "The state change pertains to the endpoint '%s(%s)'\n",
4482 session->channel ? ast_channel_name(session->channel) : "");
4483 }
4484 if (inv->invite_tsx) {
4485 ast_log(LOG_DEBUG, "The inv session still has an invite_tsx (%p)\n",
4486 inv->invite_tsx);
4487 } else {
4488 ast_log(LOG_DEBUG, "The inv session does NOT have an invite_tsx\n");
4489 }
4490 if (tsx) {
4491 ast_log(LOG_DEBUG, "The %s %.*s transaction involved in this state change is %p\n",
4492 pjsip_role_name(tsx->role),
4493 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4494 tsx);
4495 ast_log(LOG_DEBUG, "The current transaction state is %s\n",
4496 pjsip_tsx_state_str(tsx->state));
4497 ast_log(LOG_DEBUG, "The transaction state change event is %s\n",
4498 pjsip_event_str(e->body.tsx_state.type));
4499 } else {
4500 ast_log(LOG_DEBUG, "There is no transaction involved in this state change\n");
4501 }
4502 ast_log(LOG_DEBUG, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
4503}
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 6300 of file res_pjsip_session.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

5137{
5138 pj_str_t stmp;
5139 pjmedia_sdp_attr *attr;
5140 struct sip_session_media_bundle_group bundle_groups[PJMEDIA_MAX_SDP_MEDIA];
5141 int index, mid_id;
5142 struct sip_session_media_bundle_group *bundle_group;
5143
5144 if (session->endpoint->media.webrtc) {
5145 attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *"));
5146 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5147 }
5148
5149 if (!session->endpoint->media.bundle) {
5150 return 0;
5151 }
5152
5153 memset(bundle_groups, 0, sizeof(bundle_groups));
5154
5155 /* Build the bundle group layout so we can then add it to the SDP */
5156 for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
5157 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
5158
5159 /* If this stream is not part of a bundle group we can't add it */
5160 if (session_media->bundle_group == -1) {
5161 continue;
5162 }
5163
5164 bundle_group = &bundle_groups[session_media->bundle_group];
5165
5166 /* If this is the first mid then we need to allocate the attribute string and place BUNDLE in front */
5167 if (!bundle_group->mids[0]) {
5168 bundle_group->mids[0] = session_media->mid;
5169 bundle_group->attr_string = ast_str_create(64);
5170 if (!bundle_group->attr_string) {
5171 continue;
5172 }
5173
5174 ast_str_set(&bundle_group->attr_string, 0, "BUNDLE %s", session_media->mid);
5175 continue;
5176 }
5177
5178 for (mid_id = 1; mid_id < PJMEDIA_MAX_SDP_MEDIA; ++mid_id) {
5179 if (!bundle_group->mids[mid_id]) {
5180 bundle_group->mids[mid_id] = session_media->mid;
5181 ast_str_append(&bundle_group->attr_string, 0, " %s", session_media->mid);
5182 break;
5183 } else if (!strcmp(bundle_group->mids[mid_id], session_media->mid)) {
5184 break;
5185 }
5186 }
5187 }
5188
5189 /* Add all bundle groups that have mids to the SDP */
5190 for (index = 0; index < PJMEDIA_MAX_SDP_MEDIA; ++index) {
5191 bundle_group = &bundle_groups[index];
5192
5193 if (!bundle_group->attr_string) {
5194 continue;
5195 }
5196
5197 attr = pjmedia_sdp_attr_create(pool, "group", pj_cstr(&stmp, ast_str_buffer(bundle_group->attr_string)));
5198 pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr);
5199
5200 ast_free(bundle_group->attr_string);
5201 }
5202
5203 return 0;
5204}
#define ast_free(a)
Definition astmm.h:180
static int answer(void *data)
Definition chan_pjsip.c:793
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
A structure containing SIP session media information.
int bundle_group
The bundle group the stream belongs to.
char * mid
Media identifier for this stream (may be shared across multiple streams)
Bundle group building structure.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708

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

Referenced by create_local_sdp().

◆ add_sdp_streams()

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

Definition at line 5082 of file res_pjsip_session.c.

5086{
5087 struct ast_sip_session_sdp_handler *handler = session_media->handler;
5088 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5089 int res = 0;
5090 SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
5091 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5092
5093 if (handler) {
5094 /* if an already assigned handler reports a catastrophic error, fail */
5095 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
5096 if (res < 0) {
5097 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5098 }
5099 SCOPE_EXIT_RTN_VALUE(0, "Had handler\n");
5100 }
5101
5102 handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY);
5103 if (!handler_list) {
5104 SCOPE_EXIT_RTN_VALUE(0, "No handlers\n");
5105 }
5106
5107 /* no handler for this stream type and we have a list to search */
5108 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5109 if (handler == session_media->handler) {
5110 continue;
5111 }
5112 res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
5113 if (res < 0) {
5114 /* catastrophic error */
5115 SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5116 }
5117 if (res > 0) {
5118 /* Handled by this handler. Move to the next stream */
5119 session_media_set_handler(session_media, handler);
5120 SCOPE_EXIT_RTN_VALUE(0, "Handled\n");
5121 }
5122 }
5123
5124 /* streams that weren't handled won't be included in generated outbound SDP */
5125 SCOPE_EXIT_RTN_VALUE(0, "Not handled\n");
5126}
#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 6300 of file res_pjsip_session.c.

◆ ast_sip_can_present_connected_id()

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

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

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

Definition at line 131 of file res_pjsip_session.c.

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

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

Referenced by add_id_headers(), and stir_shaken_outgoing_request().

◆ ast_sip_channel_pvt_alloc()

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

Allocate a new SIP channel pvt structure.

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

Definition at line 3092 of file res_pjsip_session.c.

3093{
3094 struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
3095
3096 if (!channel) {
3097 return NULL;
3098 }
3099
3100 ao2_ref(pvt, +1);
3101 channel->pvt = pvt;
3102 ao2_ref(session, +1);
3103 channel->session = session;
3104
3105 return channel;
3106}
#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 3663 of file res_pjsip_session.c.

3664{
3665 pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3666 struct ast_sip_session *session;
3667
3668 if (!inv_session ||
3669 !(session = inv_session->mod_data[session_module.id])) {
3670 return NULL;
3671 }
3672
3673 ao2_ref(session, +1);
3674
3675 return session;
3676}
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(), session_reinvite_on_rx_request(), and transport_info_on_tx_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 1319 of file res_pjsip_session.c.

1320{
1321 ast_assert(datastore != NULL);
1322 ast_assert(datastore->info != NULL);
1323 ast_assert(ast_strlen_zero(datastore->uid) == 0);
1324
1325 if (!ao2_link(session->datastores, datastore)) {
1326 return -1;
1327 }
1328 return 0;
1329}
#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(), t38_state_get_or_alloc(), and transport_info_on_tx_request().

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

3110{
3112 struct ast_sip_session *ret_session;
3113 int dsp_features = 0;
3114
3116 if (!session) {
3117 return NULL;
3118 }
3119
3120 AST_LIST_HEAD_INIT(&session->supplements);
3121 AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
3123
3125 if (!session->direct_media_cap) {
3126 return NULL;
3127 }
3130 if (!session->datastores) {
3131 return NULL;
3132 }
3133 session->active_media_state = ast_sip_session_media_state_alloc();
3134 if (!session->active_media_state) {
3135 return NULL;
3136 }
3137 session->pending_media_state = ast_sip_session_media_state_alloc();
3138 if (!session->pending_media_state) {
3139 return NULL;
3140 }
3141 if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
3142 return NULL;
3143 }
3144
3146 dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3147 }
3148 if (endpoint->faxdetect) {
3149 dsp_features |= DSP_FEATURE_FAX_DETECT;
3150 }
3151 if (dsp_features) {
3152 session->dsp = ast_dsp_new();
3153 if (!session->dsp) {
3154 return NULL;
3155 }
3156
3157 ast_dsp_set_features(session->dsp, dsp_features);
3158 }
3159
3160 session->endpoint = ao2_bump(endpoint);
3161
3162 if (rdata) {
3163 /*
3164 * We must continue using the serializer that the original
3165 * INVITE came in on for the dialog. There may be
3166 * retransmissions already enqueued in the original
3167 * serializer that can result in reentrancy and message
3168 * sequencing problems.
3169 */
3170 session->serializer = ast_sip_get_distributor_serializer(rdata);
3171 } else {
3172 /*
3173 * This is an outgoing session, so we can just choose a serializer
3174 * from the distributor pool based on the dialog.
3175 */
3177 }
3178 if (!session->serializer) {
3179 return NULL;
3180 }
3183
3184 /* When a PJSIP INVITE session is created it is created with a reference
3185 * count of 1, with that reference being managed by the underlying state
3186 * of the INVITE session itself. When the INVITE session transitions to
3187 * a DISCONNECTED state that reference is released. This means we can not
3188 * rely on that reference to ensure the INVITE session remains for the
3189 * lifetime of our session. To ensure it does we add our own reference
3190 * and release it when our own session goes away, ensuring that the INVITE
3191 * session remains for the lifetime of session.
3192 */
3193
3194#ifdef HAVE_PJSIP_INV_SESSION_REF
3195 if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
3196 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3197 return NULL;
3198 }
3199#endif
3200
3201 pjsip_dlg_inc_session(inv_session->dlg, &session_module);
3202 inv_session->mod_data[session_module.id] = ao2_bump(session);
3203 session->contact = ao2_bump(contact);
3204 session->inv_session = inv_session;
3205
3206 session->dtmf = endpoint->dtmf;
3207 session->moh_passthrough = endpoint->moh_passthrough;
3208
3210 /* Release the ref held by session->inv_session */
3211 ao2_ref(session, -1);
3212 return NULL;
3213 }
3214
3215 session->authentication_challenge_count = 0;
3216
3217 /* Fire session begin handlers */
3219
3220 /* Avoid unnecessary ref manipulation to return a session */
3221 ret_session = session;
3222 session = NULL;
3223 return ret_session;
3224}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
Definition channel.c:1744
#define DSP_FEATURE_DIGIT_DETECT
Definition dsp.h:28
#define DSP_FEATURE_FAX_DETECT
Definition dsp.h:29
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition dsp.c:1953
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1943
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
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.
struct ast_taskprocessor * ast_sip_get_distributor_serializer_dialog(pjsip_dialog *dlg)
Determine the distributor serializer for the SIP dialog.
#define LOG_ERROR
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
@ AST_SIP_DTMF_AUTO
Definition res_pjsip.h:558
@ AST_SIP_DTMF_INBAND
Definition res_pjsip.h:554
static void handle_session_begin(struct ast_sip_session *session)
#define DATASTORE_BUCKETS
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
static void session_destructor(void *obj)
static int datastore_cmp(void *obj, void *arg, int flags)
static int datastore_hash(const void *obj, int flags)
int ast_sip_session_add_supplements(struct ast_sip_session *session)
Add supplements to a SIP session.
unsigned int moh_passthrough
Definition res_pjsip.h:1140
enum ast_sip_dtmf_mode dtmf
Definition res_pjsip.h:1116
unsigned int faxdetect
Definition res_pjsip.h:1128
struct ast_sip_contact * contact
struct ast_sip_endpoint * endpoint
#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_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), AST_SIP_DTMF_AUTO, AST_SIP_DTMF_INBAND, ast_sip_get_distributor_serializer(), ast_sip_get_distributor_serializer_dialog(), ast_sip_session_add_supplements(), ast_sip_session_media_state_alloc(), 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 1289 of file res_pjsip_session.c.

1290{
1291 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
1292 char uuid_buf[AST_UUID_STR_LEN];
1293 const char *uid_ptr = uid;
1294
1295 if (!info) {
1296 return NULL;
1297 }
1298
1299 datastore = ao2_alloc(sizeof(*datastore), session_datastore_destroy);
1300 if (!datastore) {
1301 return NULL;
1302 }
1303
1304 datastore->info = info;
1305 if (ast_strlen_zero(uid)) {
1306 /* They didn't provide an ID so we'll provide one ourself */
1307 uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf));
1308 }
1309
1310 datastore->uid = ast_strdup(uid_ptr);
1311 if (!datastore->uid) {
1312 return NULL;
1313 }
1314
1315 ao2_ref(datastore, +1);
1316 return datastore;
1317}
#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(), t38_state_get_or_alloc(), and transport_info_on_tx_request().

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

2969{
2970 pjmedia_sdp_session *offer;
2972
2973 if (!(offer = create_local_sdp(session->inv_session, session, NULL, 0))) {
2974 pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
2975 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create offer\n");
2976 }
2977
2978 pjsip_inv_set_local_sdp(session->inv_session, offer);
2979 pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
2980#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
2981 if (!session->endpoint->preferred_codec_only) {
2982 pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
2983 }
2984#endif
2985
2986 /*
2987 * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the
2988 * From in the initial INVITE will be wrong but the rest of the messages will be OK.
2989 */
2991
2992 if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
2993 SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
2994 }
2995
2997}
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 3332 of file res_pjsip_session.c.

3335{
3336 const char *uri = NULL;
3337 RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup);
3338 RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
3339 pjsip_timer_setting timer;
3340 pjsip_dialog *dlg;
3341 struct pjsip_inv_session *inv_session;
3343 struct ast_sip_session *ret_session;
3344 SCOPE_ENTER(1, "%s %s Topology: %s\n", ast_sorcery_object_get_id(endpoint), request_user,
3345 ast_str_tmp(256, ast_stream_topology_to_str(req_topology, &STR_TMP)));
3346
3348 request_user, req_topology)) {
3349 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Session creation blocked by supplement\n",
3351 }
3352
3353 /* If no location has been provided use the AOR list from the endpoint itself */
3354 if (location || !contact) {
3355 location = S_OR(location, endpoint->aors);
3356
3358 &found_aor, &found_contact);
3359 if (!found_contact || ast_strlen_zero(found_contact->uri)) {
3360 uri = location;
3361 } else {
3362 uri = found_contact->uri;
3363 }
3364 } else {
3365 uri = contact->uri;
3366 }
3367
3368 /* If we still have no URI to dial fail to create the session */
3369 if (ast_strlen_zero(uri)) {
3370 ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
3372 SCOPE_EXIT_RTN_VALUE(NULL, "No URI\n");
3373 }
3374
3375 if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
3376 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create dialog\n");
3377 }
3378
3379 if (setup_outbound_invite_auth(dlg)) {
3380 pjsip_dlg_terminate(dlg);
3381 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't setup auth\n");
3382 }
3383
3384 if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
3385 pjsip_dlg_terminate(dlg);
3386 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create uac\n");
3387 }
3388#if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3389 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3390#endif
3391
3392 pjsip_timer_setting_default(&timer);
3394 timer.sess_expires = endpoint->extensions.timer.sess_expires;
3395 pjsip_timer_init_session(inv_session, &timer);
3396
3397 session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact,
3398 inv_session, NULL);
3399 if (!session) {
3400 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3401 return NULL;
3402 }
3403 session->aor = ao2_bump(found_aor);
3404 session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;
3405
3407
3408 if (ast_stream_topology_get_count(req_topology) > 0) {
3409 /* get joint caps between req_topology and endpoint topology */
3410 int i;
3411
3412 for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {
3413 struct ast_stream *req_stream;
3414 struct ast_stream *clone_stream;
3415
3416 req_stream = ast_stream_topology_get_stream(req_topology, i);
3417
3419 continue;
3420 }
3421
3422 clone_stream = ast_sip_session_create_joint_call_stream(session, req_stream);
3423 if (!clone_stream || ast_stream_get_format_count(clone_stream) == 0) {
3424 ast_stream_free(clone_stream);
3425 continue;
3426 }
3427
3428 if (!session->pending_media_state->topology) {
3429 session->pending_media_state->topology = ast_stream_topology_alloc();
3430 if (!session->pending_media_state->topology) {
3431 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3432 ao2_ref(session, -1);
3433 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create topology\n");
3434 }
3435 }
3436
3437 if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) {
3438 ast_stream_free(clone_stream);
3439 continue;
3440 }
3441 }
3442 }
3443
3444 if (!session->pending_media_state->topology) {
3445 /* Use the configured topology on the endpoint as the pending one */
3446 session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology);
3447 if (!session->pending_media_state->topology) {
3448 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3449 ao2_ref(session, -1);
3450 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't clone topology\n");
3451 }
3452 }
3453
3454 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3455 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3456 /* Since we are not notifying ourselves that the INVITE session is being terminated
3457 * we need to manually drop its reference to session
3458 */
3459 ao2_ref(session, -1);
3460 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't add usage\n");
3461 }
3462
3463 /* Avoid unnecessary ref manipulation to return a session */
3464 ret_session = session;
3465 session = NULL;
3466 SCOPE_EXIT_RTN_VALUE(ret_session);
3467}
static struct ast_timer * timer
Definition chan_iax2.c:401
void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
Copy the source party id information to the destination party id.
Definition channel.c:1752
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
Definition res_pjsip.c:962
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition res_pjsip.h:1443
void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags, struct ast_sip_aor **aor, struct ast_sip_contact **contact)
Retrieve the first bound contact AND the AOR chosen from a list of AORs and filter based on flags.
Definition location.c:272
struct ast_sip_session * ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata)
Allocate a new SIP session.
static int setup_outbound_invite_auth(pjsip_dialog *dlg)
@ AST_SIP_SESSION_OUTGOING_CALL
int ast_sip_session_check_supplement_create(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, struct ast_stream_topology *req_topology)
Check registered supplements for permission to create an outgoing session.
struct ast_stream * ast_sip_session_create_joint_call_stream(const struct ast_sip_session *session, struct ast_stream *remote)
Create a new stream of joint capabilities.
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition stream.c:652
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition stream.h:78
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition stream.c:751
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition stream.c:939
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition stream.c:791
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition stream.c:768
int ast_stream_get_format_count(const struct ast_stream *stream)
Get the count of the current negotiated formats of a stream.
Definition stream.c:358
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition stream.c:373
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition stream.c:292
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition stream.c:670
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
A SIP address of record.
Definition res_pjsip.h:480
Contact associated with an address of record.
Definition res_pjsip.h:392
const ast_string_field uri
Definition res_pjsip.h:414
struct ast_sip_timer_options timer
Definition res_pjsip.h:821
struct ast_stream_topology * topology
Definition res_pjsip.h:1027
struct ast_sip_endpoint_id_configuration id
Definition res_pjsip.h:1106
const ast_string_field aors
Definition res_pjsip.h:1096
struct ast_sip_endpoint_extensions extensions
Definition res_pjsip.h:1098
struct ast_sip_endpoint_media_configuration media
Definition res_pjsip.h:1100
unsigned int sess_expires
Definition res_pjsip.h:808
unsigned int min_se
Definition res_pjsip.h:806

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

Referenced by request().

◆ ast_sip_session_defer_termination()

int ast_sip_session_defer_termination ( struct ast_sip_session *  session)

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

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

Definition at line 3589 of file res_pjsip_session.c.

3590{
3591 pj_time_val delay = { .sec = 60, };
3592 int res;
3593
3594 /* The session should not have an active deferred termination request. */
3595 ast_assert(!session->defer_terminate);
3596
3597 session->defer_terminate = 1;
3598
3599 session->defer_end = 1;
3600 session->ended_while_deferred = 0;
3601
3602 ao2_ref(session, +1);
3603 pj_timer_entry_init(&session->scheduled_termination, 0, session, session_termination_cb);
3604
3605 res = (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
3606 &session->scheduled_termination, &delay) != PJ_SUCCESS) ? -1 : 0;
3607 if (res) {
3608 session->defer_terminate = 0;
3609 ao2_ref(session, -1);
3610 }
3611 return res;
3612}
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
static void session_termination_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)

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

Referenced by refer_incoming_attended_request(), and refer_incoming_blind_request().

◆ ast_sip_session_defer_termination_cancel()

void ast_sip_session_defer_termination_cancel ( struct ast_sip_session *  session)

Cancel a pending deferred termination.

Parameters
sessionThe session to cancel a deferred termination on.

Definition at line 3629 of file res_pjsip_session.c.

3630{
3631 if (!session->defer_terminate) {
3632 /* Already canceled or timer fired. */
3633 return;
3634 }
3635
3636 session->defer_terminate = 0;
3637
3638 if (session->terminate_while_deferred) {
3639 /* Complete the termination started by the upper layer. */
3641 }
3642
3643 /* Stop the termination timer if it is still running. */
3645}
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 3647 of file res_pjsip_session.c.

3648{
3649 if (!session->defer_end) {
3650 return;
3651 }
3652
3653 session->defer_end = 0;
3654
3655 if (session->ended_while_deferred) {
3656 /* Complete the session end started by the remote hangup. */
3657 ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3658 session->ended_while_deferred = 0;
3660 }
3661}
#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 1331 of file res_pjsip_session.c.

1332{
1333 return ao2_find(session->datastores, name, OBJ_KEY);
1334}
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(), transport_info_on_tx_request(), 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 3678 of file res_pjsip_session.c.

3679{
3680 pjsip_inv_session *inv_session = session->inv_session;
3681
3682 if (!inv_session) {
3683 return NULL;
3684 }
3685
3686 return inv_session->dlg;
3687}

References ast_sip_session::inv_session, NULL, and session.

◆ ast_sip_session_get_name()

const char * ast_sip_session_get_name ( const struct ast_sip_session *  session)

Get the channel or endpoint name associated with the session.

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

Definition at line 117 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_get_pjsip_inv_state()

pjsip_inv_state ast_sip_session_get_pjsip_inv_state ( const struct ast_sip_session *  session)

Retrieves the pjsip_inv_state from a session.

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

Definition at line 3689 of file res_pjsip_session.c.

3690{
3691 pjsip_inv_session *inv_session = session->inv_session;
3692
3693 if (!inv_session) {
3694 return PJSIP_INV_STATE_NULL;
3695 }
3696
3697 return inv_session->state;
3698}

References ast_sip_session::inv_session, and session.

◆ ast_sip_session_is_pending_stream_default()

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

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

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

Definition at line 368 of file res_pjsip_session.c.

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

References ast_channel_name(), ast_log, ast_stream_get_state(), ast_stream_get_type(), AST_STREAM_STATE_REMOVED, ast_stream_topology_get_count(), ast_stream_topology_get_stream(), LOG_WARNING, and session.

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

◆ ast_sip_session_media_add_read_callback()

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

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

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

Definition at line 394 of file res_pjsip_session.c.

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

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

Referenced by apply_negotiated_sdp_stream(), and apply_negotiated_sdp_stream().

◆ ast_sip_session_media_get_transport()

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

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

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

Definition at line 423 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_media_set_write_callback()

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

Set a write callback for a media session.

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

Definition at line 407 of file res_pjsip_session.c.

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

References callback(), and ast_sip_session_media::write_callback.

Referenced by apply_negotiated_sdp_stream(), and apply_negotiated_sdp_stream().

◆ ast_sip_session_media_state_add()

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

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

Since
15.0.0

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

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

Definition at line 499 of file res_pjsip_session.c.

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

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_cleanup, ao2_ref, ast_asprintf, ast_codec_media_type2str(), ast_free, ast_sip_session_get_name(), ast_strdup, ast_stream_get_name(), ast_stream_get_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_get_stream(), ast_trace, AST_VECTOR_GET, AST_VECTOR_REPLACE, AST_VECTOR_SIZE, ast_sip_session_media::bundle_group, ast_sip_session_media::bundled, ast_sip_session_media_state::default_session, ast_sip_session_media::encryption, ast_sip_session_media::keepalive_sched_id, ast_sip_session_media::mid, NULL, ast_sip_session_media::remote_ice, ast_sip_session_media::remote_rtcp_mux, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_media_dtor(), ast_sip_session_media_state::sessions, ast_sip_session_media::stream_name, ast_sip_session_media::stream_num, ast_sip_session_media::timeout_sched_id, ast_sip_session_media_state::topology, type, and ast_sip_session_media::type.

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

◆ ast_sip_session_media_state_alloc()

struct ast_sip_session_media_state * ast_sip_session_media_state_alloc ( void  )

Allocate a session media state structure.

Since
15.0.0
Return values
non-NULLsuccess
NULLfailure

Definition at line 247 of file res_pjsip_session.c.

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

References DEFAULT_NUM_SESSION_MEDIA, and internal_sip_session_media_state_alloc().

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

◆ ast_sip_session_media_state_clone()

struct ast_sip_session_media_state * ast_sip_session_media_state_clone ( const struct ast_sip_session_media_state *  media_state)

Clone a media state.

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

Definition at line 306 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_media_state_free()

void ast_sip_session_media_state_free ( struct ast_sip_session_media_state *  media_state)

Free a session media state structure.

Since
15.0.0

Definition at line 353 of file res_pjsip_session.c.

354{
355 if (!media_state) {
356 return;
357 }
358
359 /* This will reset the internal state so we only have to free persistent things */
361
362 AST_VECTOR_FREE(&media_state->sessions);
363 AST_VECTOR_FREE(&media_state->read_callbacks);
364
365 ast_free(media_state);
366}
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185

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

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

◆ ast_sip_session_media_state_reset()

void ast_sip_session_media_state_reset ( struct ast_sip_session_media_state *  media_state)

Reset a media state to a clean state.

Since
15.0.0
Parameters
media_stateThe media state to reset

Definition at line 287 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_media_stats_save()

void ast_sip_session_media_stats_save ( struct ast_sip_session *  sip_session,
struct ast_sip_session_media_state *  media_state 
)

Save a media stats.

Parameters
sip_sessionSession on which to save active media state for
media_stateThe media state to save

Definition at line 253 of file res_pjsip_session.c.

254{
255 int i;
256 int ret;
257
258 if (!media_state || !sip_session) {
259 return;
260 }
261
262 for (i = 0; i < AST_VECTOR_SIZE(&media_state->sessions); i++) {
263 struct ast_rtp_instance_stats *stats_tmp = NULL;
264 struct ast_sip_session_media *media = AST_VECTOR_GET(&media_state->sessions, i);
265 if (!media || !media->rtp) {
266 continue;
267 }
268
269 stats_tmp = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
270 if (!stats_tmp) {
271 return;
272 }
273
275 if (ret) {
276 ast_free(stats_tmp);
277 continue;
278 }
279
280 /* remove all the duplicated stats if exist */
282
283 AST_VECTOR_APPEND(&sip_session->media_stats, stats_tmp);
284 }
285}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
static int media_stats_local_ssrc_cmp(const struct ast_rtp_instance_stats *vec_elem, const struct ast_rtp_instance_stats *srch)
@ AST_RTP_INSTANCE_STAT_ALL
Definition rtp_engine.h:187
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
Retrieve statistics about an RTP instance.
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sip_session::@284 media_stats
#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition vector.h:516

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

Referenced by ast_sip_session_terminate(), and handle_negotiated_sdp().

◆ ast_sip_session_refresh()

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

Send a reinvite or UPDATE on a session.

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

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

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

Definition at line 2637 of file res_pjsip_session.c.

2643{
2644 return sip_session_refresh(session, on_request_creation, on_sdp_creation,
2645 on_response, method, generate_new_sdp, media_state, NULL, 0);
2646}
const char * method
Definition res_pjsip.c:1277
static int sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queued)

References method, NULL, session, and sip_session_refresh().

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

◆ ast_sip_session_regenerate_answer()

int ast_sip_session_regenerate_answer ( struct ast_sip_session *  session,
ast_sip_session_sdp_creation_cb  on_sdp_creation 
)

Regenerate SDP Answer.

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

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

Definition at line 2648 of file res_pjsip_session.c.

2650{
2651 pjsip_inv_session *inv_session = session->inv_session;
2652 pjmedia_sdp_session *new_answer = NULL;
2653 const pjmedia_sdp_session *previous_offer = NULL;
2655
2656 /* The SDP answer can only be regenerated if it is still pending to be sent */
2657 if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER &&
2658 pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) {
2659 ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n",
2660 ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg)));
2661 SCOPE_EXIT_RTN_VALUE(-1, "Bad negotiation state\n");
2662 }
2663
2664 pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer);
2665 if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2666 /* Transition the SDP negotiator back to when it received the remote offer */
2667 pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0);
2668 pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer);
2669 }
2670
2671 new_answer = create_local_sdp(inv_session, session, previous_offer, 0);
2672 if (!new_answer) {
2673 ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n",
2674 ast_channel_name(session->channel));
2675 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create new SDP\n");
2676 }
2677
2678 if (on_sdp_creation) {
2679 if (on_sdp_creation(session, new_answer)) {
2680 SCOPE_EXIT_RTN_VALUE(-1, "Callback failed\n");
2681 }
2682 }
2683
2684 pjsip_inv_set_sdp_answer(inv_session, new_answer);
2685
2687}

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

Referenced by dtmf_mode_refresh_cb().

◆ ast_sip_session_register_sdp_handler()

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

Register an SDP handler.

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

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

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

Definition at line 147 of file res_pjsip_session.c.

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

References ao2_alloc, ao2_cleanup, ao2_find, ao2_link, ast_debug, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log, handler(), ast_sip_session_sdp_handler::id, lock, LOG_WARNING, ast_sip_session_sdp_handler::next, NULL, OBJ_KEY, RAII_VAR, SCOPED_AO2LOCK, sdp_handlers, and sdp_handler_list::stream_type.

Referenced by load_module(), and load_module().

◆ ast_sip_session_remove_datastore()

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

Remove a session datastore from the session.

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

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

Definition at line 1336 of file res_pjsip_session.c.

1337{
1338 ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
1339}
#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 2919 of file res_pjsip_session.c.

2920{
2921 if (!session->deferred_reinvite) {
2922 return;
2923 }
2924
2925 if (session->channel) {
2926 pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(),
2927 session->deferred_reinvite, NULL, NULL);
2928 }
2929 pjsip_rx_data_free_cloned(session->deferred_reinvite);
2930 session->deferred_reinvite = NULL;
2931}

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

2964{
2966}
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 2939 of file res_pjsip_session.c.

2941{
2942 pjsip_inv_session *inv_session = session->inv_session;
2943
2944 /* For every request except BYE we disallow sending of the message when
2945 * the session has been disconnected. A BYE request is special though
2946 * because it can be sent again after the session is disconnected except
2947 * with credentials.
2948 */
2949 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED &&
2950 tdata->msg->line.req.method.id != PJSIP_BYE_METHOD) {
2951 return;
2952 }
2953
2954 ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id,
2955 MOD_DATA_ON_RESPONSE, on_response);
2956
2958 pjsip_inv_send_msg(session->inv_session, tdata);
2959
2960 return;
2961}
#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:3173
#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 2689 of file res_pjsip_session.c.

2690{
2691 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
2692 RAII_VAR(struct ast_sip_session *, dlg_session, dlg ? ast_sip_dialog_get_session(dlg) : NULL, ao2_cleanup);
2693 if (!dlg_session) {
2694 /* If the dialog has a session, handle_outgoing_response will be called
2695 from session_on_tx_response. If it does not, call it from here. */
2697 }
2698 pjsip_inv_send_msg(session->inv_session, tdata);
2699 return;
2700}
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 3226 of file res_pjsip_session.c.

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

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

3473{
3474 pj_status_t status;
3475 pjsip_tx_data *packet = NULL;
3476 SCOPE_ENTER(1, "%s Response %d\n", ast_sip_session_get_name(session), response);
3477
3478 if (session->defer_terminate) {
3479 session->terminate_while_deferred = 1;
3480 SCOPE_EXIT_RTN("Deferred\n");
3481 }
3482
3483 if (!response) {
3484 response = 603;
3485 }
3486
3487 /* The media sessions need to exist for the lifetime of the underlying channel
3488 * to ensure that anything (such as bridge_native_rtp) has access to them as
3489 * appropriate. Since ast_sip_session_terminate is called by chan_pjsip and other
3490 * places when the session is to be terminated we terminate any existing
3491 * media sessions here.
3492 */
3493 ast_sip_session_media_stats_save(session, session->active_media_state);
3494 /* Publish the replacement under the channel lock used by media readers.
3495 * Reset the detached state after unlocking: stream teardown may wait for
3496 * scheduler callbacks that need the channel lock.
3497 */
3498 if (session->channel) {
3499 ast_channel_lock(session->channel);
3500 }
3501 SWAP(session->active_media_state, session->pending_media_state);
3502 if (session->channel) {
3503 ast_channel_unlock(session->channel);
3504 }
3505 ast_sip_session_media_state_reset(session->pending_media_state);
3506
3507 switch (session->inv_session->state) {
3508 case PJSIP_INV_STATE_NULL:
3509 if (!session->inv_session->invite_tsx) {
3510 /*
3511 * Normally, it's pjproject's transaction cleanup that ultimately causes the
3512 * final session reference to be released but if both STATE and invite_tsx are NULL,
3513 * we never created a transaction in the first place. In this case, we need to
3514 * do the cleanup ourselves.
3515 */
3516 /* Transfer the inv_session session reference to the session_end_task */
3517 session->inv_session->mod_data[session_module.id] = NULL;
3518 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3520 /*
3521 * session_end_completion will cleanup the final session reference unless
3522 * ast_sip_session_terminate's caller is holding one.
3523 */
3525 } else {
3526 pjsip_inv_terminate(session->inv_session, response, PJ_TRUE);
3527 }
3528 break;
3529 case PJSIP_INV_STATE_CONFIRMED:
3530 if (session->inv_session->invite_tsx) {
3531 ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",
3533 /*
3534 * If this is delayed the only thing that will happen is a BYE request, so
3535 * no response code needs to be stored. Queue the BYE as before, then arm
3536 * a transaction timeout so a malformed/lost final re-INVITE response
3537 * cannot leave the session and RTP state referenced forever.
3538 */
3540 ast_log(LOG_ERROR, "%s: Unable to delay BYE request\n",
3543 session->terminate_on_invite_timeout = 1;
3544 }
3545 break;
3546 }
3547 /* Fall through */
3548 default:
3549 status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet);
3550 if (status == PJ_SUCCESS && packet) {
3551 /* Flush any delayed requests so they cannot overlap this transaction. */
3553
3554 if (packet->msg->type == PJSIP_RESPONSE_MSG) {
3556 } else {
3558 }
3559 }
3560 break;
3561 }
3563}
jack_status_t status
Definition app_jack.c:149
#define ast_channel_lock(chan)
Definition channel.h:2983
#define ast_channel_unlock(chan)
Definition channel.h:2984
#define SCOPE_EXIT_RTN(...)
static void flush_delayed_requests(struct ast_sip_session *session)
static int session_end_completion(void *vsession)
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.
static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, enum delayed_method method, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queue_head)
static int set_outstanding_invite_timeout(struct ast_sip_session *session)
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
void ast_sip_session_media_stats_save(struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
Save a media stats.
#define SWAP(a, b)
Definition utils.h:256

References ast_channel_lock, ast_channel_unlock, ast_debug, ast_log, ast_sip_session_get_name(), ast_sip_session_media_state_reset(), ast_sip_session_media_stats_save(), ast_sip_session_send_request(), ast_sip_session_send_response(), delay_request(), DELAYED_METHOD_BYE, flush_delayed_requests(), LOG_ERROR, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_end(), session_end_completion(), session_module, set_outstanding_invite_timeout(), status, and SWAP.

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

◆ ast_sip_session_unregister_sdp_handler()

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

Unregister an SDP handler.

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

Definition at line 208 of file res_pjsip_session.c.

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

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

Referenced by unload_module(), and unload_module().

◆ ast_sip_session_unsuspend()

void ast_sip_session_unsuspend ( struct ast_sip_session *  session)

Request the session serializer be unsuspended.

Since
12.7.0
Parameters
sessionWhich session to unsuspend the serializer.

Definition at line 3231 of file res_pjsip_session.c.

3232{
3234}
int ast_taskpool_serializer_unsuspend(struct ast_taskprocessor *serializer)
Unsuspend a serializer, causing tasks to be executed.
Definition taskpool.c:1067

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

3985{
3986 pjsip_msg_body *body = rdata->msg_info.msg->body;
3987 pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3988
3989 if (body && ctype_hdr &&
3992 pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3993 while (part != NULL) {
3995 return 1;
3996 }
3997 part = pjsip_multipart_get_next_part(body, part);
3998 }
3999 }
4000 return 0;
4001}
#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:2248
pjsip_media_type pjsip_media_type_multipart_mixed
Definition res_pjsip.c:3958
pjsip_media_type pjsip_media_type_multipart_alternative
Definition res_pjsip.c:3957
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 3960 of file res_pjsip_session.c.

3961{
3962 pjsip_hdr *hdr = part->hdr.next;
3963 static const pj_str_t str_handling_required = {"handling=required", 16};
3964
3965 while (hdr != &part->hdr) {
3966 if (hdr->type == PJSIP_H_OTHER) {
3967 pjsip_generic_string_hdr *generic_hdr = (pjsip_generic_string_hdr*)hdr;
3968
3969 if (!pj_stricmp2(&hdr->name, "Content-Disposition") &&
3970 pj_stristr(&generic_hdr->hvalue, &str_handling_required) &&
3971 !check_sdp_content_type_supported(&part->body->content_type)) {
3972 return 1;
3973 }
3974 }
3975 hdr = hdr->next;
3976 }
3977
3978 return 0;
3979}
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 1643 of file res_pjsip_session.c.

1645{
1646 ao2_ref(session, +1);
1647 if (ast_sip_push_task(session->serializer, cb, session)) {
1648 ao2_ref(session, -1);
1649 }
1650}
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126

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

4670{
4671 struct ast_sip_session *session = inv->mod_data[session_module.id];
4672 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4673
4674 if (inv->state == PJSIP_INV_STATE_DISCONNECTED && inv->cancelling) {
4675 return 0;
4676 }
4677
4678 if (tsx->status_code != 503 && tsx->status_code != 408) {
4679 return 0;
4680 }
4681
4682 if (!ast_sip_failover_request(tsx->last_tx)) {
4683 return 0;
4684 }
4685
4686 pjsip_inv_uac_restart(inv, PJ_FALSE);
4687 /*
4688 * Bump the ref since it will be on a new transaction and
4689 * we don't want it to go away along with the old transaction.
4690 */
4691 pjsip_tx_data_add_ref(tsx->last_tx);
4693 return 1;
4694}
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:1838

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

3949{
3950 pjsip_media_type app_sdp;
3951 pjsip_media_type_init2(&app_sdp, "application", "sdp");
3952
3953 if (!pjsip_media_type_cmp(content_type, &app_sdp, 0)) {
3954 return 1;
3955 }
3956
3957 return 0;
3958}

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

5207{
5208 static const pj_str_t STR_IN = { "IN", 2 };
5209 static const pj_str_t STR_IP4 = { "IP4", 3 };
5210 static const pj_str_t STR_IP6 = { "IP6", 3 };
5211 pjmedia_sdp_session *local;
5212 int i;
5213 int stream;
5215
5216 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
5217 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Failed to create session SDP. Session has been already disconnected\n",
5219 }
5220
5221 if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
5222 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Pool allocation failure\n", ast_sip_session_get_name(session));
5223 }
5224
5225 if (!offer) {
5226 local->origin.version = local->origin.id = (pj_uint32_t)(ast_random());
5227 } else {
5228 local->origin.version = offer->origin.version + 1;
5229 local->origin.id = offer->origin.id;
5230 }
5231
5232 pj_strdup2(inv->pool_prov, &local->origin.user, session->endpoint->media.sdpowner);
5233 pj_strdup2(inv->pool_prov, &local->name, session->endpoint->media.sdpsession);
5234
5235 if (!session->pending_media_state->topology || !ast_stream_topology_get_count(session->pending_media_state->topology)) {
5236 /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication
5237 * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation
5238 * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the endpoint.
5239 * We will also do this if wanted by the ignore_active_stream_topology flag.
5240 */
5241 ast_trace(-1, "no information about stream topology received\n");
5242 ast_stream_topology_free(session->pending_media_state->topology);
5243 if (session->active_media_state->topology && !ignore_active_stream_topology) {
5244 ast_trace(-1, "using existing topology\n");
5245 session->pending_media_state->topology = ast_stream_topology_clone(session->active_media_state->topology);
5246 } else {
5247 if (ignore_active_stream_topology) {
5248 ast_trace(-1, "fall back to endpoint configuration - ignore active stream topolog\n");
5249 } else {
5250 ast_trace(-1, "fall back to endpoint configuration\n");
5251 }
5252 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
5253 }
5254 if (!session->pending_media_state->topology) {
5255 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: No pending media state topology\n", ast_sip_session_get_name(session));
5256 }
5257 }
5258
5259 ast_trace(-1, "%s: Processing streams\n", ast_sip_session_get_name(session));
5260
5261 for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) {
5262 struct ast_sip_session_media *session_media;
5263 struct ast_stream *stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
5264 unsigned int streams = local->media_count;
5265 SCOPE_ENTER(4, "%s: Processing stream %s\n", ast_sip_session_get_name(session),
5266 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5267
5268 /* This code does not enforce any maximum stream count limitations as that is done on either
5269 * the handling of an incoming SDP offer or on the handling of a session refresh.
5270 */
5271
5272 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i);
5273 if (!session_media) {
5274 local = NULL;
5275 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc/add session media for stream %s\n",
5277 }
5278
5279 if (add_sdp_streams(session_media, session, local, offer, stream)) {
5280 local = NULL;
5281 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't add sdp streams for stream %s\n",
5283 }
5284
5285 /* If a stream was actually added then add any additional details */
5286 if (streams != local->media_count) {
5287 pjmedia_sdp_media *media = local->media[streams];
5288 pj_str_t stmp;
5289 pjmedia_sdp_attr *attr;
5290
5291 /* Add the media identifier if present */
5292 if (!ast_strlen_zero(session_media->mid)) {
5293 attr = pjmedia_sdp_attr_create(inv->pool_prov, "mid", pj_cstr(&stmp, session_media->mid));
5294 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
5295 }
5296
5297 ast_trace(-1, "%s: Stream %s added%s%s\n", ast_sip_session_get_name(session),
5298 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5299 S_COR(!ast_strlen_zero(session_media->mid), " with mid ", ""), S_OR(session_media->mid, ""));
5300
5301 }
5302
5303 /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */
5304 if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) {
5305 SCOPE_EXIT_EXPR(break, "%s: Stream %s exceeded max pjmedia count of %d\n",
5307 PJMEDIA_MAX_SDP_MEDIA);
5308 }
5309
5310 SCOPE_EXIT("%s: Done with %s\n", ast_sip_session_get_name(session),
5311 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5312
5313 }
5314
5315 /* Add any bundle groups that are present on the media state */
5316 ast_trace(-1, "%s: Adding bundle groups (if available)\n", ast_sip_session_get_name(session));
5317 if (add_bundle_groups(session, inv->pool_prov, local)) {
5318 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't add bundle groups\n", ast_sip_session_get_name(session));
5319 }
5320
5321 /* Use the connection details of an available media if possible for SDP level */
5322 ast_trace(-1, "%s: Copying connection details\n", ast_sip_session_get_name(session));
5323
5324 for (stream = 0; stream < local->media_count; stream++) {
5325 SCOPE_ENTER(4, "%s: Processing media %d\n", ast_sip_session_get_name(session), stream);
5326 if (!local->media[stream]->conn) {
5327 SCOPE_EXIT_EXPR(continue, "%s: Media %d has no connection info\n", ast_sip_session_get_name(session), stream);
5328 }
5329
5330 if (local->conn) {
5331 if (!pj_strcmp(&local->conn->net_type, &local->media[stream]->conn->net_type) &&
5332 !pj_strcmp(&local->conn->addr_type, &local->media[stream]->conn->addr_type) &&
5333 !pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) {
5334 local->media[stream]->conn = NULL;
5335 }
5336 SCOPE_EXIT_EXPR(continue, "%s: Media %d has good existing connection info\n", ast_sip_session_get_name(session), stream);
5337 }
5338
5339 /* This stream's connection info will serve as the connection details for SDP level */
5340 local->conn = local->media[stream]->conn;
5341 local->media[stream]->conn = NULL;
5342
5343 SCOPE_EXIT_EXPR(continue, "%s: Media %d reset\n", ast_sip_session_get_name(session), stream);
5344 }
5345
5346 /* If no SDP level connection details are present then create some */
5347 if (!local->conn) {
5348 ast_trace(-1, "%s: Creating connection details\n", ast_sip_session_get_name(session));
5349
5350 local->conn = pj_pool_zalloc(inv->pool_prov, sizeof(struct pjmedia_sdp_conn));
5351 local->conn->net_type = STR_IN;
5352 local->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
5353
5354 if (!ast_strlen_zero(session->endpoint->media.address)) {
5355 pj_strdup2(inv->pool_prov, &local->conn->addr, session->endpoint->media.address);
5356 } else {
5357 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()));
5358 }
5359 }
5360
5361 pj_strassign(&local->origin.net_type, &local->conn->net_type);
5362 pj_strassign(&local->origin.addr_type, &local->conn->addr_type);
5363 pj_strassign(&local->origin.addr, &local->conn->addr);
5364
5365end:
5367}
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:2513
static int add_sdp_streams(struct ast_sip_session_media *session_media, struct ast_sip_session *session, pjmedia_sdp_session *answer, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
static int add_bundle_groups(struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer)
struct ast_sip_session_media * ast_sip_session_media_state_add(struct ast_sip_session *session, struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
Allocate an ast_session_media and add it to the media state's vector.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
long int ast_random(void)
Definition utils.c:2346

References add_bundle_groups(), add_sdp_streams(), ast_random(), ast_sip_get_host_ip_string(), ast_sip_session_get_name(), ast_sip_session_media_state_add(), ast_str_tmp, ast_stream_get_type(), ast_stream_to_str(), ast_stream_topology_clone(), ast_stream_topology_free(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_strlen_zero(), ast_trace, end, LOG_ERROR, ast_sip_session_media::mid, NULL, S_COR, S_OR, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG_EXPR, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, and session.

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

◆ datastore_cmp()

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

Definition at line 3009 of file res_pjsip_session.c.

3010{
3011 const struct ast_datastore *datastore1 = obj;
3012 const struct ast_datastore *datastore2 = arg;
3013 const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
3014
3015 ast_assert(datastore1->uid != NULL);
3016 ast_assert(uid2 != NULL);
3017
3018 return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
3019}
@ 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 2999 of file res_pjsip_session.c.

3000{
3001 const struct ast_datastore *datastore = obj;
3002 const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
3003
3004 ast_assert(uid != NULL);
3005
3006 return ast_str_hash(uid);
3007}
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 1652 of file res_pjsip_session.c.

1661{
1666
1667 if (!delay) {
1670 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1671 }
1672
1673 if (method == DELAYED_METHOD_BYE || queue_head) {
1674 /* Send BYE as early as possible */
1675 AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1676 } else {
1677 AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1678 }
1680}
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static struct ast_sip_session_delayed_request * delayed_request_alloc(enum delayed_method method, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state)
Structure used for sending delayed requests.
struct ast_sip_session_delayed_request * next
ast_sip_session_sdp_creation_cb on_sdp_creation
struct ast_sip_session_media_state * active_media_state
struct ast_sip_session_media_state * pending_media_state
ast_sip_session_response_cb on_response

References ast_sip_session_delayed_request::active_media_state, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, ast_sip_session_get_name(), ast_sip_session_media_state_free(), DELAYED_METHOD_BYE, delayed_request_alloc(), ast_sip_session_delayed_request::generate_new_sdp, LOG_ERROR, method, ast_sip_session_delayed_request::next, ast_sip_session_delayed_request::on_response, ast_sip_session_delayed_request::on_sdp_creation, ast_sip_session_delayed_request::pending_media_state, SCOPE_ENTER, SCOPE_EXIT_LOG_RTN_VALUE, SCOPE_EXIT_RTN_VALUE, and session.

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

◆ delayed_method2str()

static const char * delayed_method2str ( enum delayed_method  method)
static

Definition at line 1356 of file res_pjsip_session.c.

1357{
1358 const char *str = "<unknown>";
1359
1360 switch (method) {
1362 str = "INVITE";
1363 break;
1365 str = "UPDATE";
1366 break;
1367 case DELAYED_METHOD_BYE:
1368 str = "BYE";
1369 break;
1370 }
1371
1372 return str;
1373}
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 4226 of file res_pjsip_session.c.

4227{
4228 pj_str_t method;
4229
4230 if (ast_strlen_zero(supplement_method)) {
4231 return PJ_TRUE;
4232 }
4233
4234 pj_cstr(&method, supplement_method);
4235
4236 return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
4237}
static const pjsip_method message_method
Definition res_pjsip.c:1273

References ast_strlen_zero(), message_method, and method.

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

◆ fetch_callerid_num()

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

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

Definition at line 3701 of file res_pjsip_session.c.

3702{
3703 int res = -1;
3704 struct ast_party_id id;
3705
3706 ast_party_id_init(&id);
3707 if (!ast_sip_set_id_from_invite(rdata, &id, &session->endpoint->id.self, session->endpoint->id.trust_inbound)) {
3708 ast_copy_string(buf, id.number.str, len);
3709 res = 0;
3710 }
3711 ast_party_id_free(&id);
3712 return res;
3713}
enum queue_result id
Definition app_queue.c:1790
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition channel.c:1798
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_sip_set_id_from_invite(struct pjsip_rx_data *rdata, struct ast_party_id *id, struct ast_party_id *default_id, int trust_inbound)
Set the ID from an INVITE.
Definition res_pjsip.c:2847
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
Information needed to identify an endpoint in a call.
Definition channel.h:340
Number structure.

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

Referenced by get_destination().

◆ flush_delayed_requests()

static void flush_delayed_requests ( struct ast_sip_session *  session)
static

Definition at line 1436 of file res_pjsip_session.c.

1437{
1438 struct ast_sip_session_delayed_request *delay;
1439
1440 while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
1441 delayed_request_free(delay);
1442 }
1443}
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static void delayed_request_free(struct ast_sip_session_delayed_request *delay)

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

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

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session * generate_session_refresh_sdp ( struct ast_sip_session *  session)
static

Definition at line 1733 of file res_pjsip_session.c.

1734{
1735 pjsip_inv_session *inv_session = session->inv_session;
1736 const pjmedia_sdp_session *previous_sdp = NULL;
1738
1739 if (inv_session->neg) {
1740 if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
1741 pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
1742 } else {
1743 pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
1744 }
1745 }
1746 SCOPE_EXIT_RTN_VALUE(create_local_sdp(inv_session, session, previous_sdp, 0));
1747}

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

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

References ao2_ref, ast_canmatch_extension(), AST_CHANNEL_NAME, ast_copy_pj_str(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_get_chan_features_pickup_config(), ast_log, ast_sip_is_allowed_uri(), ast_sip_pjsip_uri_get_username(), ast_sip_session_get_name(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_strdupa, ast_strlen_zero(), fetch_callerid_num(), LOG_ERROR, NULL, ast_features_pickup_config::pickupexten, S_OR, session, SIP_GET_DEST_EXTEN_FOUND, SIP_GET_DEST_EXTEN_NOT_FOUND, SIP_GET_DEST_EXTEN_PARTIAL, and SIP_GET_DEST_UNSUPPORTED_URI.

Referenced by new_invite().

◆ get_mid_bundle_group()

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

Definition at line 621 of file res_pjsip_session.c.

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

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

Referenced by set_mid_and_bundle_group().

◆ handle_incoming()

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

Definition at line 4578 of file res_pjsip_session.c.

4580{
4581 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
4583 } else {
4584 handle_incoming_response(session, rdata, response_priority);
4585 }
4586
4587 return 0;
4588}
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 4696 of file res_pjsip_session.c.

4698{
4699 pjsip_msg *msg;
4700 ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4701 "request" : "response");
4702
4703
4705 msg = rdata->msg_info.msg;
4706 if (msg->type == PJSIP_REQUEST_MSG
4707 && msg->line.req.method.id == PJSIP_ACK_METHOD
4708 && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
4709 pjsip_tx_data *tdata;
4710
4711 /*
4712 * SDP negotiation failed on an incoming call that delayed
4713 * negotiation and then gave us an invalid SDP answer. We
4714 * need to send a BYE to end the call because of the invalid
4715 * SDP answer.
4716 */
4717 ast_debug(1,
4718 "%s: Ending session due to incomplete SDP negotiation. %s\n",
4720 pjsip_rx_data_get_info(rdata));
4721 if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
4722 && tdata) {
4724 }
4725 }
4726}
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 4507 of file res_pjsip_session.c.

4508{
4509 struct ast_sip_session_supplement *supplement;
4510 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4511 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));
4512
4513 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4514 if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
4515 if (supplement->incoming_request(session, rdata)) {
4516 break;
4517 }
4518 }
4519 }
4520
4522}
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 4558 of file res_pjsip_session.c.

4560{
4561 struct ast_sip_session_supplement *supplement;
4562 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4563 SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4564 status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4565
4566 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4567 if (!(supplement->response_priority & response_priority)) {
4568 continue;
4569 }
4570 if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4571 supplement->incoming_response(session, rdata);
4572 }
4573 }
4574
4576}
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 788 of file res_pjsip_session.c.

789{
790 int i;
791 int handled = 0;
792 int type_streams[AST_MEDIA_TYPE_END] = {0};
793 SCOPE_ENTER(3, "%s: Media count: %d\n", ast_sip_session_get_name(session), sdp->media_count);
794
795 if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
796 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to handle incoming SDP. Session has been already disconnected\n",
798 }
799
800 /* It is possible for SDP deferral to have already created a pending topology */
801 if (!session->pending_media_state->topology) {
802 session->pending_media_state->topology = ast_stream_topology_alloc();
803 if (!session->pending_media_state->topology) {
804 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc pending topology\n",
806 }
807 }
808
809 for (i = 0; i < sdp->media_count; ++i) {
810 /* See if there are registered handlers for this media stream type */
811 char media[20];
813 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
814 struct ast_sip_session_media *session_media = NULL;
815 int res;
816 int bundle_only;
817 enum ast_media_type type;
818 struct ast_stream *stream = NULL;
819 pjmedia_sdp_media *remote_stream = sdp->media[i];
820 SCOPE_ENTER(4, "%s: Processing stream %d\n", ast_sip_session_get_name(session), i);
821
822 /* We need a null-terminated version of the media string */
823 ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
825
826 /* See if we have an already existing stream, which can occur from SDP deferral checking */
827 if (i < ast_stream_topology_get_count(session->pending_media_state->topology)) {
828 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
829 ast_trace(-1, "%s: Using existing pending stream %s\n", ast_sip_session_get_name(session),
830 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
831 }
832 if (!stream) {
833 struct ast_stream *existing_stream = NULL;
834 char *stream_name = NULL, *stream_name_allocated = NULL;
835 const char *stream_label = NULL;
836
837 if (session->active_media_state->topology &&
838 (i < ast_stream_topology_get_count(session->active_media_state->topology))) {
839 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
840 ast_trace(-1, "%s: Found existing active stream %s\n", ast_sip_session_get_name(session),
841 ast_str_tmp(128, ast_stream_to_str(existing_stream, &STR_TMP)));
842
843 if (ast_stream_get_state(existing_stream) != AST_STREAM_STATE_REMOVED) {
844 stream_name = (char *)ast_stream_get_name(existing_stream);
845 stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
846 }
847 }
848
849 if (ast_strlen_zero(stream_name)) {
850 if (ast_asprintf(&stream_name_allocated, "%s-%d", ast_codec_media_type2str(type), i) < 0) {
851 handled = 0;
852 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream name\n",
854
855 }
856 stream_name = stream_name_allocated;
857 ast_trace(-1, "%s: Using %s for new stream name\n", ast_sip_session_get_name(session),
858 stream_name);
859 }
860
861 stream = ast_stream_alloc(stream_name, type);
862 ast_free(stream_name_allocated);
863 if (!stream) {
864 handled = 0;
865 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream\n",
867 }
868
869 if (!ast_strlen_zero(stream_label)) {
870 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
871 ast_trace(-1, "%s: Using %s for new stream label\n", ast_sip_session_get_name(session),
872 stream_label);
873
874 }
875
876 if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
877 ast_stream_free(stream);
878 handled = 0;
879 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't set stream in topology\n",
881 }
882
883 /* For backwards compatibility with the core the default audio stream is always sendrecv */
884 if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
885 if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
886 /* Stream state reflects our state of a stream, so in the case of
887 * sendonly and recvonly we store the opposite since that is what ours
888 * is.
889 */
891 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
893 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
895 } else {
897 }
898 } else {
900 }
901 ast_trace(-1, "%s: Using new stream %s\n", ast_sip_session_get_name(session),
902 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
903 }
904
905 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
906 if (!session_media) {
907 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc session media\n",
909 }
910
911 /* MID and BUNDLE membership must be known before interpreting a zero port. */
912 set_mid_and_bundle_group(session, session_media, sdp, remote_stream);
913 bundle_only = is_bundle_only_stream(session_media, remote_stream);
914
915 /* A zero port normally declines a stream. RFC 9143 defines an exception
916 * for a bundled stream carrying the bundle-only attribute.
917 */
918 if ((!remote_stream->desc.port && !bundle_only)
919 || is_stream_limitation_reached(type, session->endpoint, type_streams)) {
920 remove_stream_from_bundle(session_media, stream);
921 SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s'\n",
923 }
924
925 if (bundle_only) {
926 ast_trace(-1, "%s: Accepting zero-port bundle-only SDP media stream %s\n",
928 }
929
930 set_remote_mslabel_and_stream_group(session, session_media, sdp, remote_stream, stream);
931
932 if (session_media->handler) {
933 handler = session_media->handler;
934 ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
936 session_media->handler->id);
937 res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
938 if (res < 0) {
939 /* Catastrophic failure. Abort! */
940 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
942 } else if (res == 0) {
943 remove_stream_from_bundle(session_media, stream);
944 SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s\n",
946 } else if (res > 0) {
947 handled = 1;
948 ++type_streams[type];
949 /* Handled by this handler. Move to the next stream */
950 SCOPE_EXIT_EXPR(continue, "%s: Media stream %s handled by %s\n",
952 session_media->handler->id);
953 }
954 }
955
956 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
957 if (!handler_list) {
958 SCOPE_EXIT_EXPR(continue, "%s: Media stream %s has no registered handlers\n",
960 }
961 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
962 if (handler == session_media->handler) {
963 continue;
964 }
965 ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
967 handler->id);
968
969 res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
970 if (res < 0) {
971 /* Catastrophic failure. Abort! */
972 handled = 0;
973 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
975 } else if (res == 0) {
976 remove_stream_from_bundle(session_media, stream);
977 ast_trace(-1, "%s: Declining incoming SDP media stream %s\n",
979 continue;
980 } else if (res > 0) {
981 session_media_set_handler(session_media, handler);
982 handled = 1;
983 ++type_streams[type];
984 ast_trace(-1, "%s: Media stream %s handled by %s\n",
986 session_media->handler->id);
987 break;
988 }
989 }
990
991 SCOPE_EXIT("%s: Done with stream %s\n", ast_sip_session_get_name(session),
992 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
993 }
994
995end:
996 SCOPE_EXIT_RTN_VALUE(handled ? 0 : -1, "%s: Handled? %s\n", ast_sip_session_get_name(session),
997 handled ? "yes" : "no");
998}
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 int is_bundle_only_stream(const struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream)
Determine whether a zero-port stream is offered for BUNDLE-only use.
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_bundle_only_stream(), 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 1099 of file res_pjsip_session.c.

1100{
1101 int i;
1102 struct ast_stream_topology *topology;
1103 unsigned int changed = 0; /* 0 = unchanged, 1 = new source, 2 = new topology */
1105
1106 if (!session->pending_media_state->topology) {
1107 if (session->active_media_state->topology) {
1108 /*
1109 * This happens when we have negotiated media after receiving a 183,
1110 * and we're now receiving a 200 with a new SDP. In this case, there
1111 * is active_media_state, but the pending_media_state has been reset.
1112 */
1113 struct ast_sip_session_media_state *active_media_state_clone;
1114
1115 active_media_state_clone =
1116 ast_sip_session_media_state_clone(session->active_media_state);
1117 if (!active_media_state_clone) {
1118 ast_log(LOG_WARNING, "%s: Unable to clone active media state\n",
1120 return -1;
1121 }
1122
1123 ast_sip_session_media_state_free(session->pending_media_state);
1124 session->pending_media_state = active_media_state_clone;
1125 } else {
1126 ast_log(LOG_WARNING, "%s: No pending or active media state\n",
1128 return -1;
1129 }
1130 }
1131
1132 /* If we're handling negotiated streams, then we should already have set
1133 * up session media instances (and Asterisk streams) that correspond to
1134 * the local SDP, and there should be the same number of session medias
1135 * and streams as there are local SDP streams
1136 */
1137 if (ast_stream_topology_get_count(session->pending_media_state->topology) != local->media_count
1138 || AST_VECTOR_SIZE(&session->pending_media_state->sessions) != local->media_count) {
1139 ast_log(LOG_WARNING, "%s: Local SDP contains %d media streams while we expected it to contain %u\n",
1141 ast_stream_topology_get_count(session->pending_media_state->topology), local->media_count);
1142 SCOPE_EXIT_RTN_VALUE(-1, "Media stream count mismatch\n");
1143 }
1144
1145 AST_VECTOR_RESET(&session->pending_media_state->read_callbacks, AST_VECTOR_ELEM_CLEANUP_NOOP);
1146
1147 for (i = 0; i < local->media_count; ++i) {
1148 struct ast_sip_session_media *session_media;
1149 struct ast_stream *stream;
1150
1151 if (!remote->media[i]) {
1152 continue;
1153 }
1154
1155 session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i);
1156 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
1157
1158 /* Make sure that this stream is in the correct state. If we need to change
1159 * the state to REMOVED, then our work here is done, so go ahead and move on
1160 * to the next stream.
1161 */
1162 /*
1163 * A zero port in a remote answer declines the stream. In an offer,
1164 * however, RFC 9143 permits a bundled stream to use port zero together
1165 * with a=bundle-only. In that case, keep the stream if our local answer
1166 * accepted it with a non-zero port.
1167 */
1168 if (!local->media[i]->desc.port
1169 || (!remote->media[i]->desc.port
1170 && !is_bundle_only_stream(session_media, remote->media[i]))) {
1172 continue;
1173 }
1174
1175 /* If the stream state is REMOVED, nothing needs to be done, so move on to the
1176 * next stream. This can occur if an internal thing has requested it to be
1177 * removed, or if we remove it as a result of the stream limit being reached.
1178 */
1180 /*
1181 * Defer removing the handler until we are ready to activate
1182 * the new topology. The channel's thread may still be using
1183 * the stream and we could crash before we are ready.
1184 */
1185 continue;
1186 }
1187
1188 if (handle_negotiated_sdp_session_media(session_media, session, local, remote, i, stream)) {
1189 SCOPE_EXIT_RTN_VALUE(-1, "Unable to handle negotiated session media\n");
1190 }
1191
1192 changed |= session_media->changed;
1193 session_media->changed = 0;
1194 }
1195
1196 /* Apply the pending media state to the channel and make it active */
1197 ast_channel_lock(session->channel);
1198
1199 /* Now update the stream handler for any declined/removed streams */
1200 for (i = 0; i < local->media_count; ++i) {
1201 struct ast_sip_session_media *session_media;
1202 struct ast_stream *stream;
1203
1204 if (!remote->media[i]) {
1205 continue;
1206 }
1207
1208 session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i);
1209 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
1210
1212 && session_media->handler) {
1213 /*
1214 * This stream is no longer being used and the channel's thread
1215 * is held off because we have the channel lock so release any
1216 * resources the handler may have on it.
1217 */
1218 session_media_set_handler(session_media, NULL);
1219 }
1220 }
1221
1222 /* Update the topology on the channel to match the accepted one */
1223 topology = ast_stream_topology_clone(session->pending_media_state->topology);
1224 if (topology) {
1225 ast_channel_set_stream_topology(session->channel, topology);
1226 /* If this is a remotely done renegotiation that has changed the stream topology notify what is
1227 * currently handling this channel. Note that fax uses its own process, so if we are transitioning
1228 * between audio and fax or vice versa we don't notify.
1229 */
1230 if (pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_FALSE &&
1231 session->active_media_state && session->active_media_state->topology &&
1232 !ast_stream_topology_equal(session->active_media_state->topology, topology) &&
1233 !session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] &&
1234 !session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]) {
1235 changed = 2;
1236 }
1237 }
1238
1239 /* Remove all current file descriptors from the channel */
1240 for (i = 0; i < AST_VECTOR_SIZE(&session->active_media_state->read_callbacks); ++i) {
1242 }
1243
1244 /* Add all the file descriptors from the pending media state */
1245 for (i = 0; i < AST_VECTOR_SIZE(&session->pending_media_state->read_callbacks); ++i) {
1246 struct ast_sip_session_media_read_callback_state *callback_state;
1247
1248 callback_state = AST_VECTOR_GET_ADDR(&session->pending_media_state->read_callbacks, i);
1249 ast_channel_internal_fd_set(session->channel, i + AST_EXTENDED_FDS, callback_state->fd);
1250 }
1251
1252 /* Active and pending flip flop as needed */
1253 ast_sip_session_media_stats_save(session, session->active_media_state);
1254 SWAP(session->active_media_state, session->pending_media_state);
1255 ast_sip_session_media_state_reset(session->pending_media_state);
1256
1257 ast_channel_unlock(session->channel);
1258
1259 if (changed == 1) {
1261
1262 ast_queue_frame(session->channel, &f);
1263 } else if (changed == 2) {
1265 } else {
1267 }
1268
1270}
#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.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition channel.c:1171
void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value)
int ast_channel_stream_topology_changed_externally(struct ast_channel *chan)
Provide notice from a channel that the topology has changed on it as a result of the remote party ren...
Definition channel.c:11188
void ast_channel_internal_fd_clear(struct ast_channel *chan, int which)
@ 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, is_bundle_only_stream(), 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 1000 of file res_pjsip_session.c.

1003{
1004 /* See if there are registered handlers for this media stream type */
1005 struct pjmedia_sdp_media *local_stream = local->media[index];
1006 char media[20];
1008 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
1009 int res;
1010 SCOPE_ENTER(1, "%s\n", session ? ast_sip_session_get_name(session) : "unknown");
1011
1012 /* We need a null-terminated version of the media string */
1013 ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media));
1014
1015 /* For backwards compatibility we only reflect the stream state correctly on
1016 * the non-default streams and any non-audio streams. This is because the stream
1017 * state of the default audio stream is also used for signaling that someone has
1018 * placed us on hold. This situation is not handled currently and can result in
1019 * the remote side being sorted of placed on hold too.
1020 */
1021 if (!ast_sip_session_is_pending_stream_default(session, asterisk_stream) || strcmp(media, "audio")) {
1022 /* Determine the state of the stream based on our local SDP */
1023 if (pjmedia_sdp_media_find_attr2(local_stream, "sendonly", NULL)) {
1025 } else if (pjmedia_sdp_media_find_attr2(local_stream, "recvonly", NULL)) {
1027 } else if (pjmedia_sdp_media_find_attr2(local_stream, "inactive", NULL)) {
1029 } else {
1031 }
1032 } else {
1034 }
1035
1036 set_mid_and_bundle_group(session, session_media, remote, remote->media[index]);
1037 set_remote_mslabel_and_stream_group(session, session_media, remote, remote->media[index], asterisk_stream);
1038
1039 handler = session_media->handler;
1040 if (handler) {
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 ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1048 handler->id);
1049 SCOPE_EXIT_RTN_VALUE(0, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1051 handler->id);
1052 }
1053 SCOPE_EXIT_RTN_VALUE(-1, "%s: Failed to apply negotiated SDP media stream '%s' using %s SDP handler\n",
1055 handler->id);
1056 }
1057
1058 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
1059 if (!handler_list) {
1060 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
1061 return -1;
1062 }
1063 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
1064 if (handler == session_media->handler) {
1065 continue;
1066 }
1067 ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1069 handler->id);
1070 res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
1071 if (res < 0) {
1072 /* Catastrophic failure. Abort! */
1073 SCOPE_EXIT_RTN_VALUE(-1, "%s: Handler '%s' returned %d\n",
1075 }
1076 if (res > 0) {
1077 ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1079 handler->id);
1080 /* Handled by this handler. Move to the next stream */
1081 session_media_set_handler(session_media, handler);
1082 SCOPE_EXIT_RTN_VALUE(0, "%s: Handler '%s' handled this sdp stream\n",
1084 }
1085 }
1086
1087 res = 0;
1088 if (session_media->handler && session_media->handler->stream_stop) {
1089 ast_debug(4, "%s: Stopping SDP media stream '%s' as it is not currently negotiated\n",
1091 session_media->handler->stream_stop(session_media);
1092 }
1093
1094 SCOPE_EXIT_RTN_VALUE(0, "%s: Media type '%s' %s\n",
1096 res ? "not negotiated. Stopped" : "handled");
1097}
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 4147 of file res_pjsip_session.c.

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

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

Referenced by session_on_rx_request().

◆ handle_outgoing_request()

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

Definition at line 4590 of file res_pjsip_session.c.

4591{
4592 struct ast_sip_session_supplement *supplement;
4593 struct pjsip_request_line req = tdata->msg->line.req;
4594 SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4595 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4596
4597 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4598
4599 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4600 if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
4601 supplement->outgoing_request(session, tdata);
4602 }
4603 }
4605}
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 4607 of file res_pjsip_session.c.

4608{
4609 struct ast_sip_session_supplement *supplement;
4610 struct pjsip_status_line status = tdata->msg->line.status;
4611 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
4612 SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4613 (int) pj_strlen(&cseq->method.name),
4614 pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
4615 pj_strbuf(&status.reason));
4616
4617
4618 if (!cseq) {
4619 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4621 }
4622
4623 ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4624
4625 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4626 if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
4627 supplement->outgoing_response(session, tdata);
4628 }
4629 }
4630
4632}
#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 4524 of file res_pjsip_session.c.

4525{
4526 struct ast_sip_session_supplement *iter;
4527
4528 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4529 if (iter->session_begin) {
4530 iter->session_begin(session);
4531 }
4532 }
4533}
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 4535 of file res_pjsip_session.c.

4536{
4537 struct ast_sip_session_supplement *iter;
4538
4539 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4540 if (iter->session_destroy) {
4541 iter->session_destroy(session);
4542 }
4543 }
4544}
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 4546 of file res_pjsip_session.c.

4547{
4548 struct ast_sip_session_supplement *iter;
4549
4550 /* Session is dead. Notify the supplements. */
4551 AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4552 if (iter->session_end) {
4553 iter->session_end(session);
4554 }
4555 }
4556}
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 4239 of file res_pjsip_session.c.

4240{
4241 struct ast_sip_session_supplement *supplement;
4242 struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
4243
4244 if (!session) {
4245 return PJ_FALSE;
4246 }
4247
4248 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4249 if (does_method_match(&method->name, supplement->method)) {
4250 return PJ_TRUE;
4251 }
4252 }
4253 return PJ_FALSE;
4254}

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

Referenced by session_on_rx_request().

◆ internal_sip_session_media_state_alloc()

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

Definition at line 223 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_media_state_alloc(), and ast_sip_session_media_state_clone().

◆ invite_collision_timeout()

static int invite_collision_timeout ( void *  vsession)
static

Definition at line 1599 of file res_pjsip_session.c.

1600{
1601 struct ast_sip_session *session = vsession;
1602 int res;
1604
1605 if (session->inv_session->invite_tsx) {
1606 /*
1607 * INVITE transaction still active. Let it send
1608 * the collision re-INVITE when it terminates.
1609 */
1610 ao2_ref(session, -1);
1611 res = 0;
1612 } else {
1614 }
1615
1617}
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 1501 of file res_pjsip_session.c.

1502{
1503 struct ast_sip_session *session = vsession;
1504 struct ast_sip_session_delayed_request *delay;
1505 int found = 0;
1506 int res = 0;
1508
1509 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1510 switch (delay->method) {
1512 break;
1515 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1516 delayed_method2str(delay->method));
1517 res = send_delayed_request(session, delay);
1518 delayed_request_free(delay);
1519 if (!res) {
1520 found = 1;
1521 }
1522 break;
1523 case DELAYED_METHOD_BYE:
1524 /* A BYE is pending so don't bother anymore. */
1525 found = 1;
1526 break;
1527 }
1528 if (found) {
1529 break;
1530 }
1531 }
1533
1534 ao2_ref(session, -1);
1536}
#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 1548 of file res_pjsip_session.c.

1549{
1550 struct ast_sip_session *session = vsession;
1551 struct ast_sip_session_delayed_request *delay;
1552 int found = 0;
1553 int res = 0;
1554 int timer_running;
1556
1557 /* re-INVITE collision timer running? */
1558 timer_running = pj_timer_entry_running(&session->rescheduled_reinvite);
1559
1560 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1561 switch (delay->method) {
1563 if (!timer_running) {
1564 found = 1;
1565 }
1566 break;
1568 case DELAYED_METHOD_BYE:
1569 found = 1;
1570 break;
1571 }
1572 if (found) {
1574 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1575 delayed_method2str(delay->method));
1576 res = send_delayed_request(session, delay);
1577 delayed_request_free(delay);
1578 if (!res) {
1579 break;
1580 }
1581 }
1582 }
1584
1585 ao2_ref(session, -1);
1587}

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

static int is_bundle_only_stream ( const struct ast_sip_session_media *  session_media,
const struct pjmedia_sdp_media *  stream 
)
static

Determine whether a zero-port stream is offered for BUNDLE-only use.

RFC 9143 permits an offerer to use a zero port together with the bundle-only attribute when the stream is to be accepted only as part of the associated BUNDLE group. A zero port without these conditions still means that the stream is disabled.

Definition at line 781 of file res_pjsip_session.c.

783{
784 return !stream->desc.port && session_media->bundled
785 && pjmedia_sdp_media_find_attr2(stream, "bundle-only", NULL);
786}

References ast_sip_session_media::bundled, and NULL.

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp().

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

1865{
1866 int stream_count = ast_stream_topology_get_count(state->topology);
1867 int session_count = AST_VECTOR_SIZE(&state->sessions);
1868 int i;
1869 int res = 0;
1870 SCOPE_ENTER(3, "%s: Topology: %s\n", session_name,
1871 ast_str_tmp(256, ast_stream_topology_to_str(state->topology, &STR_TMP)));
1872
1873 if (session_count != stream_count) {
1874 SCOPE_EXIT_RTN_VALUE(0, "%s: %d media sessions but %d streams\n", session_name,
1875 session_count, stream_count);
1876 }
1877
1878 for (i = 0; i < stream_count; i++) {
1879 struct ast_sip_session_media *media = NULL;
1880 struct ast_stream *stream = ast_stream_topology_get_stream(state->topology, i);
1881 const char *stream_name = NULL;
1882 int j;
1883 SCOPE_ENTER(4, "%s: Checking stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1884
1885 if (!stream) {
1886 SCOPE_EXIT_EXPR(goto end, "%s: stream %d is null\n", session_name, i);
1887 }
1888 stream_name = ast_stream_get_name(stream);
1889
1890 for (j = 0; j < stream_count; j++) {
1891 struct ast_stream *possible_dup = ast_stream_topology_get_stream(state->topology, j);
1892 if (j == i || !possible_dup) {
1893 continue;
1894 }
1895 if (!STREAM_REMOVED(stream) && ast_strings_equal(stream_name, GET_STREAM_NAME_SAFE(possible_dup))) {
1896 SCOPE_EXIT_EXPR(goto end, "%s: stream %i %s is duplicated to %d\n", session_name,
1897 i, stream_name, j);
1898 }
1899 }
1900
1901 media = AST_VECTOR_GET(&state->sessions, i);
1902 if (!media) {
1903 SCOPE_EXIT_EXPR(continue, "%s: media %d is null\n", session_name, i);
1904 }
1905
1906 for (j = 0; j < session_count; j++) {
1907 struct ast_sip_session_media *possible_dup = AST_VECTOR_GET(&state->sessions, j);
1908 if (j == i || !possible_dup) {
1909 continue;
1910 }
1911 if (!ast_strlen_zero(media->label) && !ast_strlen_zero(possible_dup->label)
1912 && ast_strings_equal(media->label, possible_dup->label)) {
1913 SCOPE_EXIT_EXPR(goto end, "%s: media %d %s is duplicated to %d\n", session_name,
1914 i, media->label, j);
1915 }
1916 }
1917
1918 if (media->stream_num != i) {
1919 SCOPE_EXIT_EXPR(goto end, "%s: media %d has stream_num %d\n", session_name,
1920 i, media->stream_num);
1921 }
1922
1923 if (media->type != ast_stream_get_type(stream)) {
1924 SCOPE_EXIT_EXPR(goto end, "%s: media %d has type %s but stream has type %s\n", stream_name,
1926 }
1927 SCOPE_EXIT("%s: Done with stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1928 }
1929
1930 res = 1;
1931end:
1932 SCOPE_EXIT_RTN_VALUE(res, "%s: %s\n", session_name, res ? "Valid" : "NOT Valid");
1933}
static int session_count
Definition http.c:110
#define GET_STREAM_NAME_SAFE(_stream)
#define STREAM_REMOVED(_stream)
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition strings.c:238
char label[AST_UUID_STR_LEN]
Track label.

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

Referenced by resolve_refresh_media_states().

◆ is_stream_limitation_reached()

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

Definition at line 601 of file res_pjsip_session.c.

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

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

Referenced by handle_incoming_sdp(), and sip_session_refresh().

◆ load_module()

static int load_module ( void  )
static

Definition at line 6242 of file res_pjsip_session.c.

6243{
6244 pjsip_endpoint *endpt;
6245
6248 }
6249 if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
6251 }
6256 if (!sdp_handlers) {
6258 }
6260 pjsip_inv_usage_init(endpt, &inv_callback);
6261 pjsip_100rel_init_module(endpt);
6262 pjsip_timer_init_module(endpt);
6265 }
6268
6270
6272#ifdef TEST_FRAMEWORK
6273 AST_TEST_REGISTER(test_resolve_refresh_media_states);
6274#endif
6276}
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition module.h:478
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
void pjsip_reason_header_load(void)
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:111
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int sdp_handler_list_cmp(void *obj, void *arg, int flags)
static pjsip_module session_reinvite_module
#define SDP_HANDLER_BUCKETS
static pjsip_module outbound_invite_auth_module
static pjsip_inv_callback inv_callback
static struct ast_sip_nat_hook * nat_hook
NAT hook for modifying outgoing messages with SDP.
static int sdp_handler_list_hash(const void *obj, int flags)
static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Hook for modifying outgoing messages with SDP to contain the proper address information.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition sorcery.c:2126
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition sorcery.c:1808
struct ast_module * self
Definition module.h:356
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition res_pjsip.h:333
#define AST_TEST_REGISTER(cb)
Definition test.h:127

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_module_shutdown_ref, ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_register_service(), ast_sorcery_alloc(), ast_sorcery_create(), AST_TEST_REGISTER, inv_callback, nat_hook, NULL, outbound_invite_auth_module, ast_sip_nat_hook::outgoing_external_message, pjsip_reason_header_load(), SDP_HANDLER_BUCKETS, sdp_handler_list_cmp(), sdp_handler_list_hash(), sdp_handlers, ast_module_info::self, session_module, session_outgoing_nat_hook(), and session_reinvite_module.

◆ media_stats_local_ssrc_cmp()

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

Definition at line 213 of file res_pjsip_session.c.

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

References ast_rtp_instance_stats::local_ssrc.

Referenced by ast_sip_session_media_stats_save().

◆ new_invite()

static int new_invite ( struct new_invite *  invite)
static

Definition at line 4003 of file res_pjsip_session.c.

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

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

◆ new_invite_initial_answer()

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

Definition at line 3820 of file res_pjsip_session.c.

3822{
3823 pjsip_tx_data *tdata = NULL;
3824 int res = 0;
3825
3826 if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3827 if (pjsip_inv_initial_answer(
3828 inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
3829
3830 pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
3831 res = -1;
3832 } else {
3833 pjsip_inv_send_msg(inv_session, tdata);
3834 }
3835 }
3836
3837 if (answer_code >= 300) {
3838 /*
3839 * A session is ending. The dialog has a reference that needs to be
3840 * removed and holds a lock that needs to be unlocked before returning.
3841 */
3842 pjsip_dlg_dec_lock(inv_session->dlg);
3843 }
3844
3845 return res;
3846}

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

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

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

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

Referenced by handle_new_invite_request().

◆ remove_handler()

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

Definition at line 185 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_unregister_sdp_handler().

◆ remove_stream_from_bundle()

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

Definition at line 763 of file res_pjsip_session.c.

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

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

Referenced by handle_incoming_sdp().

◆ reschedule_reinvite()

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

Definition at line 4378 of file res_pjsip_session.c.

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

4358{
4359 struct ast_sip_session *session = entry->user_data;
4360
4361 ast_debug(3, "%s: re-INVITE collision timer expired.\n",
4363
4364 if (AST_LIST_EMPTY(&session->delayed_requests)) {
4365 /* No delayed request pending, so just return */
4366 ao2_ref(session, -1);
4367 return;
4368 }
4370 /*
4371 * Uh oh. We now have nothing in the foreseeable future
4372 * to trigger sending the delayed requests.
4373 */
4374 ao2_ref(session, -1);
4375 }
4376}
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 1948 of file res_pjsip_session.c.

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

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

Referenced by sip_session_refresh().

◆ sdp_handler_list_cmp()

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

Definition at line 138 of file res_pjsip_session.c.

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

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

Referenced by load_module().

◆ sdp_handler_list_hash()

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

Definition at line 109 of file res_pjsip_session.c.

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

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

Referenced by load_module().

◆ sdp_requires_deferral()

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

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

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

Definition at line 2721 of file res_pjsip_session.c.

2722{
2723 int i;
2724
2725 if (!session->pending_media_state->topology) {
2726 session->pending_media_state->topology = ast_stream_topology_alloc();
2727 if (!session->pending_media_state->topology) {
2728 return -1;
2729 }
2730 }
2731
2732 for (i = 0; i < sdp->media_count; ++i) {
2733 /* See if there are registered handlers for this media stream type */
2734 char media[20];
2736 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
2737 struct ast_stream *existing_stream = NULL;
2738 struct ast_stream *stream;
2739 enum ast_media_type type;
2740 struct ast_sip_session_media *session_media = NULL;
2742 pjmedia_sdp_media *remote_stream = sdp->media[i];
2743
2744 /* We need a null-terminated version of the media string */
2745 ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
2746
2747 if (session->active_media_state->topology &&
2748 (i < ast_stream_topology_get_count(session->active_media_state->topology))) {
2749 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
2750 }
2751
2753 stream = ast_stream_alloc(existing_stream ? ast_stream_get_name(existing_stream) : ast_codec_media_type2str(type), type);
2754 if (!stream) {
2755 return -1;
2756 }
2757
2758 /* As this is only called on an incoming SDP offer before processing it is not possible
2759 * for streams and their media sessions to exist.
2760 */
2761 if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
2762 ast_stream_free(stream);
2763 return -1;
2764 }
2765
2766 if (existing_stream) {
2767 const char *stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
2768
2769 if (!ast_strlen_zero(stream_label)) {
2770 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
2771 }
2772 }
2773
2774 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
2775 if (!session_media) {
2776 return -1;
2777 }
2778
2779 /* For backwards compatibility with the core the default audio stream is always sendrecv */
2780 if (!ast_sip_session_is_pending_stream_default(session, stream) || strcmp(media, "audio")) {
2781 if (pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
2782 /* Stream state reflects our state of a stream, so in the case of
2783 * sendonly and recvonly we store the opposite since that is what ours
2784 * is.
2785 */
2787 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "recvonly", NULL)) {
2789 } else if (pjmedia_sdp_media_find_attr2(remote_stream, "inactive", NULL)) {
2791 } else {
2793 }
2794 } else {
2796 }
2797
2798 if (session_media->handler) {
2799 handler = session_media->handler;
2800 if (handler->defer_incoming_sdp_stream) {
2801 res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2802 sdp->media[i]);
2803 switch (res) {
2805 break;
2807 return 0;
2809 break;
2811 return 1;
2812 }
2813 }
2814 /* Handled by this handler. Move to the next stream */
2815 continue;
2816 }
2817
2818 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
2819 if (!handler_list) {
2820 ast_debug(3, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
2821 continue;
2822 }
2823 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
2824 if (handler == session_media->handler) {
2825 continue;
2826 }
2827 if (!handler->defer_incoming_sdp_stream) {
2828 continue;
2829 }
2830 res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
2831 sdp->media[i]);
2832 switch (res) {
2834 continue;
2836 session_media_set_handler(session_media, handler);
2837 return 0;
2839 /* Handled by this handler. */
2840 session_media_set_handler(session_media, handler);
2841 break;
2843 /* Handled by this handler. */
2844 session_media_set_handler(session_media, handler);
2845 return 1;
2846 }
2847 /* Move to the next stream */
2848 break;
2849 }
2850 }
2851 return 0;
2852}
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 1453 of file res_pjsip_session.c.

1454{
1455 int res;
1456 SCOPE_ENTER(3, "%s: sending delayed %s request\n",
1458 delayed_method2str(delay->method));
1459
1460 switch (delay->method) {
1463 delay->on_sdp_creation, delay->on_response,
1465 delay->active_media_state, 1);
1466 /* Ownership of media state transitions to ast_sip_session_refresh */
1467 delay->pending_media_state = NULL;
1468 delay->active_media_state = NULL;
1472 delay->on_sdp_creation, delay->on_response,
1474 delay->active_media_state, 1);
1475 /* Ownership of media state transitions to ast_sip_session_refresh */
1476 delay->pending_media_state = NULL;
1477 delay->active_media_state = NULL;
1479 case DELAYED_METHOD_BYE:
1480 /* The delayed BYE is being sent now; timeout cleanup is no longer needed. */
1481 session->terminate_on_invite_timeout = 0;
1483 SCOPE_EXIT_RTN_VALUE(0, "%s: Terminating session on delayed BYE\n", ast_sip_session_get_name(session));
1484 }
1485
1486 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",
1488 delayed_method2str(delay->method), delay->method);
1489}
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition res_pjsip.h:719
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition res_pjsip.h:717

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

Referenced by invite_proceeding(), and invite_terminated().

◆ session_datastore_destroy()

static void session_datastore_destroy ( void *  obj)
static

Definition at line 1275 of file res_pjsip_session.c.

1276{
1277 struct ast_datastore *datastore = obj;
1278
1279 /* Using the destroy function (if present) destroy the data */
1280 if (datastore->info->destroy != NULL && datastore->data != NULL) {
1281 datastore->info->destroy(datastore->data);
1282 datastore->data = NULL;
1283 }
1284
1285 ast_free((void *) datastore->uid);
1286 datastore->uid = NULL;
1287}
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 3021 of file res_pjsip_session.c.

3022{
3023 struct ast_sip_session *session = obj;
3024
3025#ifdef TEST_FRAMEWORK
3026 /* We dup the endpoint ID in case the endpoint gets freed out from under us */
3027 const char *endpoint_name = session->endpoint ?
3028 ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>";
3029#endif
3030
3031 ast_debug(3, "%s: Destroying SIP session\n", ast_sip_session_get_name(session));
3032
3033 ast_test_suite_event_notify("SESSION_DESTROYING",
3034 "Endpoint: %s\r\n"
3035 "AOR: %s\r\n"
3036 "Contact: %s"
3037 , endpoint_name
3038 , session->aor ? ast_sorcery_object_get_id(session->aor) : "<none>"
3040 );
3041
3042 /* fire session destroy handler */
3044
3045 /* remove all registered supplements */
3047 AST_LIST_HEAD_DESTROY(&session->supplements);
3048
3049 /* remove all saved media stats */
3050 AST_VECTOR_RESET(&session->media_stats, ast_free);
3051 AST_VECTOR_FREE(&session->media_stats);
3052
3054 ao2_cleanup(session->datastores);
3055 ast_sip_session_media_state_free(session->active_media_state);
3056 ast_sip_session_media_state_free(session->pending_media_state);
3057
3060 ao2_cleanup(session->endpoint);
3061 ao2_cleanup(session->aor);
3062 ao2_cleanup(session->contact);
3063 ao2_cleanup(session->direct_media_cap);
3064
3065 ast_dsp_free(session->dsp);
3066
3067 if (session->inv_session) {
3068 struct pjsip_dialog *dlg = session->inv_session->dlg;
3069
3070 /* The INVITE session uses the dialog pool for memory, so we need to
3071 * decrement its reference first before that of the dialog.
3072 */
3073
3074#ifdef HAVE_PJSIP_INV_SESSION_REF
3075 pjsip_inv_dec_ref(session->inv_session);
3076#endif
3077 pjsip_dlg_dec_session(dlg, &session_module);
3078 }
3079
3080 ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name);
3081}
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1968
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
static void handle_session_destroy(struct ast_sip_session *session)
void ast_sip_session_remove_supplements(struct ast_sip_session *session)
Remove supplements from a SIP session.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189

References ao2_cleanup, ast_debug, ast_dsp_free(), ast_free, AST_LIST_HEAD_DESTROY, ast_party_id_free(), ast_sip_session_get_name(), ast_sip_session_media_state_free(), ast_sip_session_remove_supplements(), ast_sorcery_object_get_id(), ast_strdupa, ast_taskprocessor_unreference(), ast_test_suite_event_notify, AST_VECTOR_FREE, AST_VECTOR_RESET, flush_delayed_requests(), handle_session_destroy(), session, and session_module.

Referenced by ast_sip_session_alloc().

◆ session_end()

static int session_end ( void *  vsession)
static

Definition at line 4634 of file res_pjsip_session.c.

4635{
4636 struct ast_sip_session *session = vsession;
4637
4638 /* Stop the scheduled termination */
4640
4641 /* Session is dead. Notify the supplements. */
4643
4644 return 0;
4645}
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 4657 of file res_pjsip_session.c.

4658{
4659 struct ast_sip_session *session = vsession;
4660
4661 ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL);
4662 ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL);
4663
4664 /* Now we can release the ref that was held by session->inv_session */
4666 return 0;
4667}

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

4815{
4816 struct ast_sip_session *session;
4817
4818 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
4819 return 0;
4820 }
4821
4822 /*
4823 * We are locking because ast_sip_dialog_get_session() needs
4824 * the dialog locked to get the session by other threads.
4825 */
4826 pjsip_dlg_inc_lock(inv->dlg);
4827 session = inv->mod_data[id];
4828 inv->mod_data[id] = NULL;
4829 pjsip_dlg_dec_lock(inv->dlg);
4830
4831 /*
4832 * Pass the session ref held by session->inv_session to
4833 * session_end_completion().
4834 */
4835 if (session
4837 /* Do it anyway even though this is not the right thread. */
4839 }
4840
4841 return 1;
4842}

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

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

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

◆ session_inv_on_media_update()

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

Definition at line 5491 of file res_pjsip_session.c.

5492{
5493 struct ast_sip_session *session = inv->mod_data[session_module.id];
5494 const pjmedia_sdp_session *local, *remote;
5496
5497 if (ast_shutdown_final()) {
5498 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5499 }
5500
5501 session = inv->mod_data[session_module.id];
5502 if (!session || !session->channel) {
5503 /*
5504 * If we don't have a session or channel then we really
5505 * don't care about media updates.
5506 * Just ignore
5507 */
5508 SCOPE_EXIT_RTN("%s: No channel or session\n", ast_sip_session_get_name(session));
5509 }
5510
5511 if (session->endpoint) {
5512 int bail = 0;
5513
5514 /*
5515 * If following_fork is set, then this is probably the result of a
5516 * forked INVITE and SDP asnwers coming from the different fork UAS
5517 * destinations. In this case updated_sdp_answer will also be set.
5518 *
5519 * If only updated_sdp_answer is set, then this is the non-forking
5520 * scenario where the same UAS just needs to change something like
5521 * the media port.
5522 */
5523
5524 if (inv->following_fork) {
5525 if (session->endpoint->media.rtp.follow_early_media_fork) {
5526 ast_trace(-1, "%s: Following early media fork with different To tags\n", ast_sip_session_get_name(session));
5527 } else {
5528 ast_trace(-1, "%s: Not following early media fork with different To tags\n", ast_sip_session_get_name(session));
5529 bail = 1;
5530 }
5531 }
5532#ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS
5533 else if (inv->updated_sdp_answer) {
5534 if (session->endpoint->media.rtp.accept_multiple_sdp_answers) {
5535 ast_trace(-1, "%s: Accepting updated SDP with same To tag\n", ast_sip_session_get_name(session));
5536 } else {
5537 ast_trace(-1, "%s: Ignoring updated SDP answer with same To tag\n", ast_sip_session_get_name(session));
5538 bail = 1;
5539 }
5540 }
5541#endif
5542 if (bail) {
5544 }
5545 }
5546
5547 if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||
5548 (pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {
5550 ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
5551 ast_queue_hangup(session->channel);
5552 SCOPE_EXIT_RTN("%s: Couldn't get active or local or remote negotiator. Hanging up\n", ast_sip_session_get_name(session));
5553 }
5554
5555 if (handle_negotiated_sdp(session, local, remote)) {
5556 ast_sip_session_media_state_reset(session->pending_media_state);
5557 SCOPE_EXIT_RTN("%s: handle_negotiated_sdp failed. Resetting pending media state\n", ast_sip_session_get_name(session));
5558 }
5560}
int ast_shutdown_final(void)
Definition asterisk.c:1883
#define AST_CAUSE_BEARERCAPABILITY_NOTAVAIL
Definition causes.h:130
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition channel.c:1182
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Definition channel.c:2498
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)

References AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, ast_channel_hangupcause_set(), ast_channel_name(), ast_queue_hangup(), ast_set_hangupsource(), ast_shutdown_final(), ast_sip_session_get_name(), ast_sip_session_media_state_reset(), ast_trace, handle_negotiated_sdp(), SCOPE_ENTER, SCOPE_EXIT_RTN, session, session_module, and status.

◆ session_inv_on_new_session()

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

Definition at line 4809 of file res_pjsip_session.c.

4810{
4811 /* XXX STUB */
4812}

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

5563{
5564 struct ast_sip_session *session;
5565 const pjsip_sip_uri *uri;
5566
5567 if (ast_shutdown_final()) {
5568 return PJSIP_REDIRECT_STOP;
5569 }
5570
5571 session = inv->mod_data[session_module.id];
5572 if (!session || !session->channel) {
5573 return PJSIP_REDIRECT_STOP;
5574 }
5575
5576 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_PJSIP) {
5577 return PJSIP_REDIRECT_ACCEPT;
5578 }
5579
5580 if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
5581 return PJSIP_REDIRECT_STOP;
5582 }
5583
5585
5586 uri = pjsip_uri_get_uri(target);
5587
5588 if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
5590
5591 ast_copy_pj_str(exten, &uri->user, sizeof(exten));
5592
5593 /*
5594 * We may want to match in the dialplan without any user
5595 * options getting in the way.
5596 */
5598
5599 ast_channel_call_forward_set(session->channel, exten);
5600 } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
5601 char target_uri[PJSIP_MAX_URL_SIZE];
5602 /* PJSIP/ + endpoint length + / + max URL size */
5603 char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
5604
5605 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
5606 sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
5607 ast_channel_call_forward_set(session->channel, forward);
5608 }
5609
5610 return PJSIP_REDIRECT_STOP;
5611}
#define AST_MAX_EXTENSION
Definition channel.h:134
@ AST_SIP_REDIRECT_URI_CORE
Definition res_pjsip.h:750
@ AST_SIP_REDIRECT_URI_PJSIP
Definition res_pjsip.h:752
@ AST_SIP_REDIRECT_USER
Definition res_pjsip.h:748
@ AST_SIP_SESSION_BEFORE_REDIRECTING

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

◆ session_inv_on_rx_offer()

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

Definition at line 5369 of file res_pjsip_session.c.

5370{
5371 struct ast_sip_session *session = inv->mod_data[session_module.id];
5372 pjmedia_sdp_session *answer;
5374
5375 if (ast_shutdown_final()) {
5376 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
5377 }
5378
5379 session = inv->mod_data[session_module.id];
5380 if (handle_incoming_sdp(session, offer)) {
5381 ast_sip_session_media_state_reset(session->pending_media_state);
5382 SCOPE_EXIT_RTN("%s: handle_incoming_sdp failed\n", ast_sip_session_get_name(session));
5383 }
5384
5385 if ((answer = create_local_sdp(inv, session, offer, 0))) {
5386 pjsip_inv_set_sdp_answer(inv, answer);
5387 SCOPE_EXIT_RTN("%s: Set SDP answer\n", ast_sip_session_get_name(session));
5388 }
5389 SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));
5390}

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

4729{
4730 pjsip_event_id_e type;
4731 struct ast_sip_session *session = inv->mod_data[session_module.id];
4732 SCOPE_ENTER(1, "%s Event: %s Inv State: %s\n", ast_sip_session_get_name(session),
4733 pjsip_event_str(e->type), pjsip_inv_state_name(inv->state));
4734
4735 if (ast_shutdown_final()) {
4736 SCOPE_EXIT_RTN("Shutting down\n");
4737 }
4738
4739 if (e) {
4740 print_debug_details(inv, NULL, e);
4741 type = e->type;
4742 } else {
4743 type = PJSIP_EVENT_UNKNOWN;
4744 }
4745
4746 session = inv->mod_data[session_module.id];
4747 if (!session) {
4748 SCOPE_EXIT_RTN("No session\n");
4749 }
4750
4751 switch(type) {
4752 case PJSIP_EVENT_TX_MSG:
4753 break;
4754 case PJSIP_EVENT_RX_MSG:
4755 handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);
4756 break;
4757 case PJSIP_EVENT_TSX_STATE:
4758 ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),
4759 pjsip_event_str(e->body.tsx_state.type));
4760 /* Transaction state changes are prompted by some other underlying event. */
4761 switch(e->body.tsx_state.type) {
4762 case PJSIP_EVENT_TX_MSG:
4763 break;
4764 case PJSIP_EVENT_RX_MSG:
4765 if (!check_request_status(inv, e)) {
4766 handle_incoming_before_media(inv, session, e->body.tsx_state.src.rdata);
4767 }
4768 break;
4769 case PJSIP_EVENT_TRANSPORT_ERROR:
4770 case PJSIP_EVENT_TIMER:
4771 /*
4772 * Check the request status on transport error or timeout. A transport
4773 * error can occur when a TCP socket closes and that can be the result
4774 * of a 503. Also we may need to failover on a timeout (408).
4775 */
4776 check_request_status(inv, e);
4777 break;
4778 case PJSIP_EVENT_USER:
4779 case PJSIP_EVENT_UNKNOWN:
4780 case PJSIP_EVENT_TSX_STATE:
4781 /* Inception? */
4782 break;
4783 }
4784 break;
4785 case PJSIP_EVENT_TRANSPORT_ERROR:
4786 case PJSIP_EVENT_TIMER:
4787 case PJSIP_EVENT_UNKNOWN:
4788 case PJSIP_EVENT_USER:
4789 default:
4790 break;
4791 }
4792
4793 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
4794 if (session->defer_end) {
4795 ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));
4796 session->ended_while_deferred = 1;
4797 SCOPE_EXIT_RTN("Deferring\n");
4798 }
4799
4800 if (ast_sip_push_task(session->serializer, session_end, session)) {
4801 /* Do it anyway even though this is not the right thread. */
4803 }
4804 }
4805
4807}
#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 4844 of file res_pjsip_session.c.

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

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

◆ session_media_dtor()

static void session_media_dtor ( void *  obj)
static

Definition at line 478 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_media_state_add().

◆ session_media_set_handler()

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

Set an SDP stream handler for a corresponding session media.

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

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

Definition at line 454 of file res_pjsip_session.c.

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

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

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

◆ session_on_rx_request()

static pj_bool_t session_on_rx_request ( pjsip_rx_data *  rdata)
static

Called when a new SIP request comes into PJSIP.

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

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

Definition at line 4312 of file res_pjsip_session.c.

4313{
4314 pj_status_t handled = PJ_FALSE;
4315 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4316 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4317 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4318 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4319 char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4320 int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4321 SCOPE_ENTER(1, "%s Request: %.*s %s\n", ast_sip_session_get_name(session),
4322 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), res ? req_uri : "");
4323
4324 switch (req.method.id) {
4325 case PJSIP_INVITE_METHOD:
4326 if (dlg) {
4327 ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
4328 break;
4329 }
4330 handled = PJ_TRUE;
4332 break;
4333 default:
4334 /* Handle other in-dialog methods if their supplements have been registered */
4335 handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
4336 has_supplement(inv_session->mod_data[session_module.id], rdata);
4337 break;
4338 }
4339
4340 SCOPE_EXIT_RTN_VALUE(handled, "%s Handled request %.*s %s ? %s\n", ast_sip_session_get_name(session),
4341 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name), req_uri,
4342 handled == PJ_TRUE ? "yes" : "no");
4343}
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 4282 of file res_pjsip_session.c.

4283{
4284
4285 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4286 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
4287 pjsip_inv_session *inv_session = dlg ? pjsip_dlg_get_inv_session(dlg) : NULL;
4288 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4289 SCOPE_ENTER(1, "%s Method: %.*s Status: %d\n", ast_sip_session_get_name(session),
4290 (int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
4291
4292 SCOPE_EXIT_RTN_VALUE(PJ_FALSE);
4293}

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

4261{
4262
4263 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
4264 pjsip_inv_session *inv_session = (dlg ? pjsip_dlg_get_inv_session(dlg) : NULL);
4265 struct ast_sip_session *session = (inv_session ? inv_session->mod_data[session_module.id] : NULL);
4266 SCOPE_ENTER(1, "%s TSX State: %s Inv State: %s\n", ast_sip_session_get_name(session),
4267 pjsip_tsx_state_str(tsx->state), inv_session ? pjsip_inv_state_name(inv_session->state) : "unknown");
4268
4269 if (session) {
4270 ast_trace(2, "Topology: Pending: %s Active: %s\n",
4271 ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)),
4272 ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
4273 }
4274
4276}

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

4347{
4348 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
4350 if (session) {
4352 }
4353
4354 return PJ_SUCCESS;
4355}

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

5625{
5627 pjsip_sdp_info *sdp_info;
5628 pjmedia_sdp_session *sdp;
5629 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
5631 int stream;
5632
5633 /*
5634 * If there's no transport_state or body, just return.
5635 */
5636 if (ast_strlen_zero(transport->external_media_address) || !transport_state || !tdata->msg->body) {
5637 return;
5638 }
5639
5640 sdp_info = pjsip_get_sdp_info(tdata->pool, tdata->msg->body, NULL, &pjsip_media_type_application_sdp);
5641 if (sdp_info->sdp_err != PJ_SUCCESS || !sdp_info->sdp) {
5642 return;
5643 }
5644 sdp = sdp_info->sdp;
5645
5646 if (sdp->conn) {
5647 char host[NI_MAXHOST];
5648 struct ast_sockaddr our_sdp_addr = { { 0, } };
5649
5650 ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
5651 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
5652
5653 /* Reversed check here. We don't check the remote
5654 * endpoint being in our local net, but whether our
5655 * outgoing session IP is local. If it is, we'll do
5656 * rewriting. No localnet configured? Always rewrite. */
5657 if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {
5658 ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),
5659 ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5660 pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5661 pj_strassign(&sdp->origin.addr, &sdp->conn->addr);
5662 }
5663 }
5664
5665 for (stream = 0; stream < sdp->media_count; ++stream) {
5666 /* See if there are registered handlers for this media stream type */
5667 char media[20];
5669 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
5670
5671 /* We need a null-terminated version of the media string */
5672 ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
5673
5674 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
5675 if (!handler_list) {
5676 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session),
5677 media);
5678 continue;
5679 }
5680 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
5681 if (handler->change_outgoing_sdp_stream_media_address) {
5682 handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
5683 }
5684 }
5685 }
5686
5687}
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:3956
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
#define ast_sip_transport_is_local(transport_state, addr)
Definition res_pjsip.h:213
Structure for SIP transport information.
Definition res_pjsip.h:117
const ast_string_field external_media_address
Definition res_pjsip.h:241
Socket address structure.
Definition netsock2.h:97

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

Referenced by load_module().

◆ session_reinvite_on_rx_request()

static pj_bool_t session_reinvite_on_rx_request ( pjsip_rx_data *  rdata)
static

Definition at line 2854 of file res_pjsip_session.c.

2855{
2856 pjsip_dialog *dlg;
2858 pjsip_rdata_sdp_info *sdp_info;
2859 int deferred;
2860
2861 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
2862 !(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
2864 !session->channel) {
2865 return PJ_FALSE;
2866 }
2867
2868 if (session->inv_session->invite_tsx) {
2869 /* There's a transaction in progress so bail now and let pjproject send 491 */
2870 return PJ_FALSE;
2871 }
2872
2873 if (session->deferred_reinvite) {
2874 pj_str_t key, deferred_key;
2875 pjsip_tx_data *tdata;
2876
2877 /* We use memory from the new request on purpose so the deferred reinvite pool does not grow uncontrollably */
2878 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &rdata->msg_info.cseq->method, rdata);
2879 pjsip_tsx_create_key(rdata->tp_info.pool, &deferred_key, PJSIP_ROLE_UAS, &session->deferred_reinvite->msg_info.cseq->method,
2880 session->deferred_reinvite);
2881
2882 /* If this is a retransmission ignore it */
2883 if (!pj_strcmp(&key, &deferred_key)) {
2884 return PJ_TRUE;
2885 }
2886
2887 /* Otherwise this is a new re-invite, so reject it */
2888 if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) {
2889 if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) {
2890 pjsip_tx_data_dec_ref(tdata);
2891 }
2892 }
2893
2894 return PJ_TRUE;
2895 }
2896
2897 if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
2898 (sdp_info->sdp_err != PJ_SUCCESS)) {
2899 return PJ_FALSE;
2900 }
2901
2902 if (!sdp_info->sdp) {
2903 return PJ_FALSE;
2904 }
2905
2906 deferred = sdp_requires_deferral(session, sdp_info->sdp);
2907 if (deferred == -1) {
2908 ast_sip_session_media_state_reset(session->pending_media_state);
2909 return PJ_FALSE;
2910 } else if (!deferred) {
2911 return PJ_FALSE;
2912 }
2913
2914 pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
2915
2916 return PJ_TRUE;
2917}
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 3580 of file res_pjsip_session.c.

3581{
3582 struct ast_sip_session *session = entry->user_data;
3583
3586 }
3587}
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 3565 of file res_pjsip_session.c.

3566{
3567 struct ast_sip_session *session = data;
3568
3569 if (session->defer_terminate) {
3570 session->defer_terminate = 0;
3571 if (session->inv_session) {
3573 }
3574 }
3575
3576 ao2_ref(session, -1);
3577 return 0;
3578}

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

1750{
1751 struct ast_party_id effective_id;
1752 struct ast_party_id connected_id;
1753 pj_pool_t *dlg_pool;
1754 pjsip_fromto_hdr *dlg_info;
1755 pjsip_contact_hdr *dlg_contact;
1756 pjsip_name_addr *dlg_info_name_addr;
1757 pjsip_sip_uri *dlg_info_uri;
1758 pjsip_sip_uri *dlg_contact_uri;
1759 int restricted;
1760 const char *pjsip_from_domain;
1761
1762 if (!session->channel || session->saved_from_hdr) {
1763 return;
1764 }
1765
1766 /* We need to save off connected_id for RPID/PAI generation */
1767 ast_party_id_init(&connected_id);
1768 ast_channel_lock(session->channel);
1769 effective_id = ast_channel_connected_effective_id(session->channel);
1770 ast_party_id_copy(&connected_id, &effective_id);
1771 ast_channel_unlock(session->channel);
1772
1773 restricted =
1775
1776 /* Now set up dlg->local.info so pjsip can correctly generate From */
1777
1778 dlg_pool = session->inv_session->dlg->pool;
1779 dlg_info = session->inv_session->dlg->local.info;
1780 dlg_contact = session->inv_session->dlg->local.contact;
1781 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1782 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1783 dlg_contact_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(dlg_contact->uri);
1784
1785 if (session->endpoint->id.trust_outbound || !restricted) {
1786 ast_sip_modify_id_header(dlg_pool, dlg_info, &connected_id);
1787 if (ast_sip_get_use_callerid_contact() && ast_strlen_zero(session->endpoint->contact_user)) {
1788 pj_strdup2(dlg_pool, &dlg_contact_uri->user, S_COR(connected_id.number.valid, connected_id.number.str, ""));
1789 }
1790 }
1791
1792 ast_party_id_free(&connected_id);
1793
1794 if (!ast_strlen_zero(session->endpoint->fromuser)) {
1795 dlg_info_name_addr->display.ptr = NULL;
1796 dlg_info_name_addr->display.slen = 0;
1797 pj_strdup2(dlg_pool, &dlg_info_uri->user, session->endpoint->fromuser);
1798 }
1799
1800 if (!ast_strlen_zero(session->endpoint->fromdomain)) {
1801 pj_strdup2(dlg_pool, &dlg_info_uri->host, session->endpoint->fromdomain);
1802 }
1803
1804 /*
1805 * Channel variable for compatibility with chan_sip SIPFROMDOMAIN
1806 */
1807 ast_channel_lock(session->channel);
1808 pjsip_from_domain = pbx_builtin_getvar_helper(session->channel, "SIPFROMDOMAIN");
1809 if (!ast_strlen_zero(pjsip_from_domain)) {
1810 ast_debug(3, "%s: From header domain reset by channel variable SIPFROMDOMAIN (%s)\n",
1811 ast_sip_session_get_name(session), pjsip_from_domain);
1812 pj_strdup2(dlg_pool, &dlg_info_uri->host, pjsip_from_domain);
1813 }
1814 ast_channel_unlock(session->channel);
1815
1816 /* We need to save off the non-anonymized From for RPID/PAI generation (for domain) */
1817 session->saved_from_hdr = pjsip_hdr_clone(dlg_pool, dlg_info);
1818 ast_sip_add_usereqphone(session->endpoint, dlg_pool, session->saved_from_hdr->uri);
1819
1820 /* In chan_sip, fromuser and fromdomain trump restricted so we only
1821 * anonymize if they're not set.
1822 */
1823 if (restricted) {
1824 /* fromuser doesn't provide a display name so we always set it */
1825 pj_strdup2(dlg_pool, &dlg_info_name_addr->display, "Anonymous");
1826
1827 if (ast_strlen_zero(session->endpoint->fromuser)) {
1828 pj_strdup2(dlg_pool, &dlg_info_uri->user, "anonymous");
1829 }
1830
1831 if (ast_sip_get_use_callerid_contact() && ast_strlen_zero(session->endpoint->contact_user)) {
1832 pj_strdup2(dlg_pool, &dlg_contact_uri->user, "anonymous");
1833 }
1834
1835 if (ast_strlen_zero(session->endpoint->fromdomain)) {
1836 pj_strdup2(dlg_pool, &dlg_info_uri->host, "anonymous.invalid");
1837 }
1838 } else {
1839 ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri);
1840 }
1841}
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri)
Add 'user=phone' parameter to URI if enabled and user is a phone number.
Definition res_pjsip.c:928
unsigned int ast_sip_get_use_callerid_contact(void)
Retrieve the global setting 'use_callerid_contact'.
void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id)
Set name and number information on an identity header.
Definition res_pjsip.c:2870

References ast_channel_connected_effective_id(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_party_id_copy(), ast_party_id_free(), ast_party_id_init(), ast_party_id_presentation(), AST_PRES_ALLOWED, AST_PRES_RESTRICTION, ast_sip_add_usereqphone(), ast_sip_get_use_callerid_contact(), ast_sip_modify_id_header(), ast_sip_session_get_name(), ast_strlen_zero(), NULL, ast_party_id::number, pbx_builtin_getvar_helper(), S_COR, session, ast_party_number::str, and ast_party_number::valid.

Referenced by ast_sip_session_create_invite().

◆ set_mid_and_bundle_group()

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

Definition at line 655 of file res_pjsip_session.c.

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

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

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

◆ set_outstanding_invite_timeout()

static int set_outstanding_invite_timeout ( struct ast_sip_session *  session)
static

Definition at line 1688 of file res_pjsip_session.c.

1689{
1690 pjsip_transaction *tsx;
1691 pj_status_t status;
1692
1693 if (!session->inv_session || !session->inv_session->invite_tsx) {
1694 return 0;
1695 }
1696
1697 tsx = session->inv_session->invite_tsx;
1698 if (tsx->role != PJSIP_ROLE_UAC || tsx->method.id != PJSIP_INVITE_METHOD
1699 || tsx->state >= PJSIP_TSX_STATE_COMPLETED) {
1700 return 0;
1701 }
1702
1703 status = pjsip_tsx_set_timeout(tsx, pjsip_cfg()->tsx.td);
1704 if (status != PJ_SUCCESS && status != PJ_EEXISTS) {
1705 char errmsg[PJ_ERR_MSG_SIZE];
1706
1707 pj_strerror(status, errmsg, sizeof(errmsg));
1708 ast_log(LOG_WARNING, "%s: Failed to set timeout on outstanding INVITE transaction: %s\n",
1710 return 0;
1711 }
1712
1713 return 1;
1714}

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

Referenced by ast_sip_session_terminate().

◆ set_remote_mslabel_and_stream_group()

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

Definition at line 693 of file res_pjsip_session.c.

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

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

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

◆ setup_outbound_invite_auth()

static int setup_outbound_invite_auth ( pjsip_dialog *  dlg)
static

Definition at line 3321 of file res_pjsip_session.c.

3322{
3323 pj_status_t status;
3324
3325 ++dlg->sess_count;
3326 status = pjsip_dlg_add_usage(dlg, &outbound_invite_auth_module, NULL);
3327 --dlg->sess_count;
3328
3329 return status != PJ_SUCCESS ? -1 : 0;
3330}

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

3085{
3086 struct ast_sip_channel_pvt *channel = obj;
3087
3088 ao2_cleanup(channel->pvt);
3089 ao2_cleanup(channel->session);
3090}

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

3622{
3623 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
3624 &session->scheduled_termination, session->scheduled_termination.id)) {
3625 ao2_ref(session, -1);
3626 }
3627}

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

2305{
2306 pjsip_inv_session *inv_session = session->inv_session;
2307 pjmedia_sdp_session *new_sdp = NULL;
2308 pjsip_tx_data *tdata;
2309 int res = -1;
2310 SCOPE_ENTER(3, "%s: New SDP? %s Queued? %s DP: %s DA: %s\n", ast_sip_session_get_name(session),
2311 generate_new_sdp ? "yes" : "no", queued ? "yes" : "no",
2312 pending_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)) : "none",
2313 active_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)) : "none");
2314
2315 if (pending_media_state && (!pending_media_state->topology || !generate_new_sdp)) {
2316
2317 ast_sip_session_media_state_free(pending_media_state);
2318 ast_sip_session_media_state_free(active_media_state);
2319 SCOPE_EXIT_RTN_VALUE(-1, "%s: Not sending reinvite because %s%s\n", ast_sip_session_get_name(session),
2320 pending_media_state->topology == NULL ? "pending topology is null " : "",
2321 !generate_new_sdp ? "generate_new_sdp is false" : "");
2322 }
2323
2324 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
2325 /* Don't try to do anything with a hung-up call */
2326 ast_sip_session_media_state_free(pending_media_state);
2327 ast_sip_session_media_state_free(active_media_state);
2328 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because of disconnected state\n",
2330 }
2331
2332 /* If the dialog has not yet been established we have to defer until it has */
2333 if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
2334 res = delay_request(session, on_request_creation, on_sdp_creation, on_response,
2335 generate_new_sdp,
2338 pending_media_state, active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2339 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because dialog has not been established\n",
2341 }
2342
2344 if (inv_session->invite_tsx) {
2345 /* We can't send a reinvite yet, so delay it */
2346 res = delay_request(session, on_request_creation, on_sdp_creation,
2347 on_response, generate_new_sdp, DELAYED_METHOD_INVITE, pending_media_state,
2348 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2349 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding transaction\n",
2351 } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {
2352 /* Initial INVITE transaction failed to progress us to a confirmed state
2353 * which means re-invites are not possible
2354 */
2355 ast_sip_session_media_state_free(pending_media_state);
2356 ast_sip_session_media_state_free(active_media_state);
2357 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because not in confirmed state\n",
2359 }
2360 }
2361
2362 if (generate_new_sdp) {
2363 /* SDP can only be generated if current negotiation has already completed */
2364 if (inv_session->neg
2365 && pjmedia_sdp_neg_get_state(inv_session->neg)
2366 != PJMEDIA_SDP_NEG_STATE_DONE) {
2367 res = delay_request(session, on_request_creation, on_sdp_creation,
2368 on_response, generate_new_sdp,
2370 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2371 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2372 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay session refresh with new SDP because SDP negotiation is not yet done\n",
2374 }
2375
2376 /* If an explicitly requested media state has been provided use it instead of any pending one */
2377 if (pending_media_state) {
2378 int index;
2379 int type_streams[AST_MEDIA_TYPE_END] = {0};
2380
2381 ast_trace(-1, "%s: Pending media state exists\n", ast_sip_session_get_name(session));
2382
2383 /* Media state conveys a desired media state, so if there are outstanding
2384 * delayed requests we need to ensure we go into the queue and not jump
2385 * ahead. If we sent this media state now then updates could go out of
2386 * order.
2387 */
2388 if (!queued && !AST_LIST_EMPTY(&session->delayed_requests)) {
2389 res = delay_request(session, on_request_creation, on_sdp_creation,
2390 on_response, generate_new_sdp,
2392 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2393 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2394 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding requests\n",
2396 }
2397
2398 /*
2399 * Attempt to resolve only if objects are available, and it's not
2400 * switching to or from an image type.
2401 */
2402 if (active_media_state && active_media_state->topology &&
2403 (!active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] ==
2404 !pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE])) {
2405
2406 struct ast_sip_session_media_state *new_pending_state;
2407
2408 ast_trace(-1, "%s: Active media state exists and is%s equal to pending\n", ast_sip_session_get_name(session),
2409 !ast_stream_topology_equal(active_media_state->topology,pending_media_state->topology) ? " not" : "");
2410 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)));
2411 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)));
2412 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)));
2413 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)));
2414
2416 pending_media_state, active_media_state, session->active_media_state, 1);
2417 if (new_pending_state) {
2418 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)));
2419 ast_sip_session_media_state_free(pending_media_state);
2420 pending_media_state = new_pending_state;
2421 } else {
2422 ast_sip_session_media_state_reset(pending_media_state);
2423 ast_sip_session_media_state_free(active_media_state);
2424 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Unable to merge media states\n", ast_sip_session_get_name(session));
2425 }
2426 }
2427
2428 /* Prune the media state so the number of streams fit within the configured limits - we do it here
2429 * so that the index of the resulting streams in the SDP match. If we simply left the streams out
2430 * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that
2431 * are configurable on the endpoint.
2432 */
2433 ast_trace(-1, "%s: Pruning and checking formats of streams\n", ast_sip_session_get_name(session));
2434
2435 for (index = 0; index < ast_stream_topology_get_count(pending_media_state->topology); ++index) {
2436 struct ast_stream *existing_stream = NULL;
2437 struct ast_stream *stream = ast_stream_topology_get_stream(pending_media_state->topology, index);
2438 SCOPE_ENTER(4, "%s: Checking stream %s\n", ast_sip_session_get_name(session),
2439 ast_stream_get_name(stream));
2440
2441 if (session->active_media_state->topology &&
2442 index < ast_stream_topology_get_count(session->active_media_state->topology)) {
2443 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2444 ast_trace(-1, "%s: Found existing stream %s\n", ast_sip_session_get_name(session),
2445 ast_stream_get_name(existing_stream));
2446 }
2447
2448 if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {
2449 if (index < AST_VECTOR_SIZE(&pending_media_state->sessions)) {
2450 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&pending_media_state->sessions, index);
2451
2452 ao2_cleanup(session_media);
2453 AST_VECTOR_REMOVE(&pending_media_state->sessions, index, 1);
2454 }
2455
2456 ast_stream_topology_del_stream(pending_media_state->topology, index);
2457 ast_trace(-1, "%s: Dropped overlimit stream %s\n", ast_sip_session_get_name(session),
2458 ast_stream_get_name(stream));
2459
2460 /* A stream has potentially moved into our spot so we need to jump back so we process it */
2461 index -= 1;
2462 SCOPE_EXIT_EXPR(continue);
2463 }
2464
2465 /* No need to do anything with stream if it's media state is removed */
2467 /* If there is no existing stream we can just not have this stream in the topology at all. */
2468 if (!existing_stream) {
2469 ast_trace(-1, "%s: Dropped removed stream %s\n", ast_sip_session_get_name(session),
2470 ast_stream_get_name(stream));
2471 ast_stream_topology_del_stream(pending_media_state->topology, index);
2472 /* TODO: Do we need to remove the corresponding media state? */
2473 index -= 1;
2474 }
2475 SCOPE_EXIT_EXPR(continue);
2476 }
2477
2478 /* Enforce the configured allowed codecs on audio and video streams */
2480 !ast_stream_get_metadata(stream, "pjsip_session_refresh")) {
2481 struct ast_format_cap *joint_cap;
2482
2484 if (!joint_cap) {
2485 ast_sip_session_media_state_free(pending_media_state);
2486 ast_sip_session_media_state_free(active_media_state);
2487 res = -1;
2488 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to alloc format caps\n", ast_sip_session_get_name(session));
2489 }
2490 ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap);
2491 if (!ast_format_cap_count(joint_cap)) {
2492 ao2_ref(joint_cap, -1);
2493
2494 if (!existing_stream) {
2495 /* If there is no existing stream we can just not have this stream in the topology
2496 * at all.
2497 */
2498 ast_stream_topology_del_stream(pending_media_state->topology, index);
2499 index -= 1;
2500 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2502 } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) ||
2503 strcmp(ast_stream_get_name(stream), ast_stream_get_name(existing_stream))) {
2504 /* If the underlying stream is a different type or different name then we have to
2505 * mark it as removed, as it is replacing an existing stream. We do this so order
2506 * is preserved.
2507 */
2509 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2511 } else {
2512 /* However if the stream is otherwise remaining the same we can keep the formats
2513 * that exist on it already which allows media to continue to flow. We don't modify
2514 * the format capabilities but do need to cast it so that ao2_bump can raise the
2515 * reference count.
2516 */
2517 joint_cap = ao2_bump((struct ast_format_cap *)ast_stream_get_formats(existing_stream));
2518 }
2519 }
2520 ast_stream_set_formats(stream, joint_cap);
2521 ao2_cleanup(joint_cap);
2522 }
2523
2524 ++type_streams[ast_stream_get_type(stream)];
2525
2526 SCOPE_EXIT();
2527 }
2528
2529 if (session->active_media_state->topology) {
2530 /* SDP is a fun thing. Take for example the fact that streams are never removed. They just become
2531 * declined. To better handle this in the case where something requests a topology change for fewer
2532 * streams than are currently present we fill in the topology to match the current number of streams
2533 * that are active.
2534 */
2535
2536 for (index = ast_stream_topology_get_count(pending_media_state->topology);
2537 index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) {
2538 struct ast_stream *stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2539 struct ast_stream *cloned;
2540 int position;
2541 SCOPE_ENTER(4, "%s: Stream %s not in pending\n", ast_sip_session_get_name(session),
2542 ast_stream_get_name(stream));
2543
2544 cloned = ast_stream_clone(stream, NULL);
2545 if (!cloned) {
2546 ast_sip_session_media_state_free(pending_media_state);
2547 ast_sip_session_media_state_free(active_media_state);
2548 res = -1;
2549 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to clone stream %s\n",
2551 }
2552
2554 position = ast_stream_topology_append_stream(pending_media_state->topology, cloned);
2555 if (position < 0) {
2556 ast_stream_free(cloned);
2557 ast_sip_session_media_state_free(pending_media_state);
2558 ast_sip_session_media_state_free(active_media_state);
2559 res = -1;
2560 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to append cloned stream\n",
2562 }
2563 SCOPE_EXIT("%s: Appended empty stream in position %d to make counts match\n",
2565 }
2566
2567 /*
2568 * We can suppress this re-invite if the pending topology is equal to the currently
2569 * active topology.
2570 */
2571 if (ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
2572 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)));
2573 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)));
2574 ast_sip_session_media_state_free(pending_media_state);
2575 ast_sip_session_media_state_free(active_media_state);
2576 /* For external consumers we return 0 to say success, but internally for
2577 * send_delayed_request we return a separate value to indicate that this
2578 * session refresh would be redundant so we didn't send it
2579 */
2580 SCOPE_EXIT_RTN_VALUE(queued ? 1 : 0, "%s: Topologies are equal. Not sending re-invite\n",
2582 }
2583 }
2584
2585 ast_sip_session_media_state_free(session->pending_media_state);
2586 session->pending_media_state = pending_media_state;
2587 }
2588
2590 if (!new_sdp) {
2591 ast_sip_session_media_state_reset(session->pending_media_state);
2592 ast_sip_session_media_state_free(active_media_state);
2593 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to generate session refresh SDP. Not sending session refresh\n",
2595 }
2596 if (on_sdp_creation) {
2597 if (on_sdp_creation(session, new_sdp)) {
2598 ast_sip_session_media_state_reset(session->pending_media_state);
2599 ast_sip_session_media_state_free(active_media_state);
2600 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_sdp_creation failed\n", ast_sip_session_get_name(session));
2601 }
2602 }
2603 }
2604
2606 if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
2607 if (generate_new_sdp) {
2608 ast_sip_session_media_state_reset(session->pending_media_state);
2609 }
2610 ast_sip_session_media_state_free(active_media_state);
2611 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create reinvite properly\n", ast_sip_session_get_name(session));
2612 }
2613 } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
2614 if (generate_new_sdp) {
2615 ast_sip_session_media_state_reset(session->pending_media_state);
2616 }
2617 ast_sip_session_media_state_free(active_media_state);
2618 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create UPDATE properly\n", ast_sip_session_get_name(session));
2619 }
2620 if (on_request_creation) {
2621 if (on_request_creation(session, tdata)) {
2622 if (generate_new_sdp) {
2623 ast_sip_session_media_state_reset(session->pending_media_state);
2624 }
2625 ast_sip_session_media_state_free(active_media_state);
2626 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));
2627 }
2628 }
2629 ast_sip_session_send_request_with_cb(session, tdata, on_response);
2630 ast_sip_session_media_state_free(active_media_state);
2631
2632end:
2633 SCOPE_EXIT_RTN_VALUE(res, "%s: Sending session refresh SDP via %s\n", ast_sip_session_get_name(session),
2634 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE");
2635}
int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
Find the compatible formats between two capabilities structures.
Definition format_cap.c:636
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition format_cap.c:403
static struct ast_sip_session_media_state * resolve_refresh_media_states(const char *session_name, struct ast_sip_session_media_state *delayed_pending_state, struct ast_sip_session_media_state *delayed_active_state, struct ast_sip_session_media_state *current_active_state, int run_post_validation)
static pjmedia_sdp_session * generate_session_refresh_sdp(struct ast_sip_session *session)
int ast_stream_topology_del_stream(struct ast_stream_topology *topology, unsigned int position)
Delete a specified stream from the given topology.
Definition stream.c:828
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition stream.c:365
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition stream.c:330
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
unsigned int position
The position of the stream in the topology.
Definition stream.c:90
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition vector.h:440

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

Referenced by ast_sip_session_refresh(), and send_delayed_request().

◆ stream_destroy()

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

Definition at line 465 of file res_pjsip_session.c.

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

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

Referenced by session_media_dtor().

◆ uac_invite_tsx_terminates_dialog()

static int uac_invite_tsx_terminates_dialog ( pjsip_transaction *  tsx)
static

Definition at line 1721 of file res_pjsip_session.c.

1722{
1723 if (tsx->role != PJSIP_ROLE_UAC || tsx->method.id != PJSIP_INVITE_METHOD
1724 || tsx->state < PJSIP_TSX_STATE_COMPLETED) {
1725 return 0;
1726 }
1727
1728 return tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST
1729 || (tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT
1730 && !pjsip_cfg()->endpt.keep_inv_after_tsx_timeout);
1731}

Referenced by session_inv_on_tsx_state_changed().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6278 of file res_pjsip_session.c.

6279{
6281
6282#ifdef TEST_FRAMEWORK
6283 AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6284#endif
6291 return 0;
6292}
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 1629 of file res_pjsip_session.c.

1630{
1631 struct ast_sip_session *session = vsession;
1632 int res;
1633
1634 if (session->inv_session->invite_tsx) {
1636 } else {
1638 }
1639
1640 return res;
1641}

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6300 of file res_pjsip_session.c.

◆ inv_callback

pjsip_inv_callback inv_callback
static

Definition at line 5613 of file res_pjsip_session.c.

5613 {
5614 .on_state_changed = session_inv_on_state_changed,
5615 .on_new_session = session_inv_on_new_session,
5616 .on_tsx_state_changed = session_inv_on_tsx_state_changed,
5617 .on_rx_offer = session_inv_on_rx_offer,
5618 .on_create_offer = session_inv_on_create_offer,
5619 .on_media_update = session_inv_on_media_update,
5620 .on_redirected = session_inv_on_redirected,
5621};
static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
static void session_inv_on_create_offer(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)

Referenced by load_module().

◆ nat_hook

struct ast_sip_nat_hook* nat_hook
static

NAT hook for modifying outgoing messages with SDP.

Definition at line 86 of file res_pjsip_session.c.

Referenced by load_module(), and unload_module().

◆ outbound_invite_auth_module

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

Definition at line 3305 of file res_pjsip_session.c.

3305 {
3306 .name = {"Outbound INVITE Auth", 20},
3307 .priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
3308 .on_rx_response = outbound_invite_auth,
3309};

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

◆ sdp_handlers

struct ao2_container* sdp_handlers
static

Registered SDP stream handlers.

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

Definition at line 95 of file res_pjsip_session.c.

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

◆ session_module

pjsip_module session_module
static

Definition at line 2707 of file res_pjsip_session.c.

2707 {
2708 .name = {"Session Module", 14},
2709 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
2710 .on_rx_request = session_on_rx_request,
2711 .on_rx_response = session_on_rx_response,
2712 .on_tsx_state = session_on_tsx_state,
2713 .on_tx_response = session_on_tx_response,
2714};
static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata)
Called when a new SIP request comes into PJSIP.
static pj_status_t session_on_tx_response(pjsip_tx_data *tdata)
static void session_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
static pj_bool_t session_on_rx_response(pjsip_rx_data *rdata)

Referenced by __print_debug_details(), ast_sip_dialog_get_session(), ast_sip_session_alloc(), ast_sip_session_create_outgoing(), ast_sip_session_send_request_with_cb(), ast_sip_session_terminate(), check_request_status(), load_module(), outbound_invite_auth(), pre_session_setup(), session_destructor(), session_inv_on_create_offer(), session_inv_on_media_update(), session_inv_on_redirected(), session_inv_on_rx_offer(), session_inv_on_state_changed(), session_inv_on_tsx_state_changed(), session_on_rx_request(), session_on_rx_response(), session_on_tsx_state(), and unload_module().

◆ session_reinvite_module

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

Definition at line 2933 of file res_pjsip_session.c.

2933 {
2934 .name = { "Session Re-Invite Module", 24 },
2935 .priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
2936 .on_rx_request = session_reinvite_on_rx_request,
2937};

Referenced by load_module(), and unload_module().