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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Session resource" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static pjsip_inv_callback inv_callback
 
static struct ast_sip_nat_hooknat_hook
 NAT hook for modifying outgoing messages with SDP.
 
static pjsip_module outbound_invite_auth_module
 
static struct ao2_containersdp_handlers
 Registered SDP stream handlers.
 
static pjsip_module session_module
 
static pjsip_module session_reinvite_module
 

Macro Definition Documentation

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Definition at line 1237 of file res_pjsip_session.c.

◆ DEFAULT_NUM_SESSION_MEDIA

#define DEFAULT_NUM_SESSION_MEDIA   2

Definition at line 63 of file res_pjsip_session.c.

◆ GET_STREAM_NAME_SAFE

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

Definition at line 1750 of file res_pjsip_session.c.

◆ GET_STREAM_SAFE

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

Definition at line 1748 of file res_pjsip_session.c.

◆ GET_STREAM_STATE_SAFE

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

Definition at line 1749 of file res_pjsip_session.c.

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1238 of file res_pjsip_session.c.

◆ MOD_DATA_ON_RESPONSE

#define MOD_DATA_ON_RESPONSE   "on_response"

Definition at line 60 of file res_pjsip_session.c.

◆ print_debug_details

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

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

◆ STATE_REMOVED

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

Definition at line 1746 of file res_pjsip_session.c.

◆ STREAM_REMOVED

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

Definition at line 1745 of file res_pjsip_session.c.

Enumeration Type Documentation

◆ delayed_method

Enumerator
DELAYED_METHOD_INVITE 
DELAYED_METHOD_UPDATE 
DELAYED_METHOD_BYE 

Definition at line 1306 of file res_pjsip_session.c.

1306 {
1310};
@ DELAYED_METHOD_INVITE
@ DELAYED_METHOD_BYE
@ DELAYED_METHOD_UPDATE

◆ sip_get_destination_result

Enumerator
SIP_GET_DEST_EXTEN_FOUND 

The extension was successfully found

SIP_GET_DEST_EXTEN_NOT_FOUND 

The extension specified in the RURI was not found

SIP_GET_DEST_EXTEN_PARTIAL 

The extension specified in the RURI was a partial match

SIP_GET_DEST_UNSUPPORTED_URI 

The RURI is of an unsupported scheme

Definition at line 3599 of file res_pjsip_session.c.

3599 {
3600 /*! The extension was successfully found */
3602 /*! The extension specified in the RURI was not found */
3604 /*! The extension specified in the RURI was a partial match */
3606 /*! The RURI is of an unsupported scheme */
3608};
@ 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 4340 of file res_pjsip_session.c.

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

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

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

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

Referenced by create_local_sdp().

◆ add_sdp_streams()

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

Definition at line 4955 of file res_pjsip_session.c.

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

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

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

Referenced by chan_pjsip_new().

◆ ast_sip_dialog_get_session()

struct ast_sip_session * ast_sip_dialog_get_session ( pjsip_dialog *  dlg)

Retrieves a session from a dialog.

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

Definition at line 3547 of file res_pjsip_session.c.

3548{
3549 pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3550 struct ast_sip_session *session;
3551
3552 if (!inv_session ||
3553 !(session = inv_session->mod_data[session_module.id])) {
3554 return NULL;
3555 }
3556
3557 ao2_ref(session, +1);
3558
3559 return session;
3560}
struct pjsip_inv_session * inv_session

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

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

◆ ast_sip_session_add_datastore()

int ast_sip_session_add_datastore ( struct ast_sip_session session,
struct ast_datastore datastore 
)

Add a datastore to a SIP session.

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

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

Definition at line 1284 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_alloc()

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

Allocate a new SIP session.

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

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

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

Definition at line 3010 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_create_outgoing(), and handle_new_invite_request().

◆ ast_sip_session_alloc_datastore()

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

Alternative for ast_datastore_alloc()

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

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

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

Definition at line 1254 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_create_invite()

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

Creates an INVITE request.

Parameters
sessionStarting session for the INVITE
tdataThe created request.

Definition at line 2867 of file res_pjsip_session.c.

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

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

Referenced by call().

◆ ast_sip_session_create_outgoing()

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

Create a new outgoing SIP session.

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

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

Definition at line 3236 of file res_pjsip_session.c.

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

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

Referenced by request().

◆ ast_sip_session_defer_termination()

int ast_sip_session_defer_termination ( struct ast_sip_session session)

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

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

Definition at line 3473 of file res_pjsip_session.c.

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

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

Referenced by refer_incoming_attended_request(), and refer_incoming_blind_request().

◆ ast_sip_session_defer_termination_cancel()

void ast_sip_session_defer_termination_cancel ( struct ast_sip_session session)

Cancel a pending deferred termination.

Parameters
sessionThe session to cancel a deferred termination on.

Definition at line 3513 of file res_pjsip_session.c.

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

3532{
3533 if (!session->defer_end) {
3534 return;
3535 }
3536
3537 session->defer_end = 0;
3538
3539 if (session->ended_while_deferred) {
3540 /* Complete the session end started by the remote hangup. */
3541 ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3542 session->ended_while_deferred = 0;
3544 }
3545}
#define ast_debug(level,...)
Log a DEBUG message.
static int session_end(void *vsession)

References ast_debug, ast_sip_session_get_name(), session, and session_end().

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

◆ ast_sip_session_get_datastore()

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

Retrieve a session datastore.

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

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

Definition at line 1296 of file res_pjsip_session.c.

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

References ao2_find, name, OBJ_KEY, and session.

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

◆ ast_sip_session_get_dialog()

pjsip_dialog * ast_sip_session_get_dialog ( const struct ast_sip_session session)

Retrieves a dialog from a session.

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

Definition at line 3562 of file res_pjsip_session.c.

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

References ast_sip_session::inv_session, NULL, and session.

◆ ast_sip_session_get_name()

const char * ast_sip_session_get_name ( const struct ast_sip_session session)

Get the channel or endpoint name associated with the session.

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

Definition at line 117 of file res_pjsip_session.c.

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

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

Referenced by add_date_header(), add_eprofile_to_channel(), add_fingerprints_if_present(), add_sdp_streams(), answer(), apply_negotiated_sdp_stream(), ast_sip_session_add_reason_header(), ast_sip_session_create_invite(), ast_sip_session_end_if_deferred(), ast_sip_session_media_state_add(), ast_sip_session_regenerate_answer(), ast_sip_session_terminate(), call(), chan_pjsip_call(), chan_pjsip_incoming_ack(), chan_pjsip_incoming_prack(), chan_pjsip_incoming_request(), chan_pjsip_incoming_response(), chan_pjsip_incoming_response_update_cause(), chan_pjsip_new(), chan_pjsip_session_begin(), chan_pjsip_session_end(), create_local_sdp(), create_outgoing_sdp_stream(), delay_request(), generate_session_refresh_sdp(), get_codecs(), get_destination(), handle_incoming_before_media(), handle_incoming_request(), handle_incoming_request(), handle_incoming_response(), handle_incoming_sdp(), handle_negotiated_sdp(), handle_negotiated_sdp_session_media(), handle_new_invite_request(), handle_outgoing_request(), handle_outgoing_request(), handle_outgoing_response(), invite_collision_timeout(), invite_proceeding(), invite_terminated(), negotiate_incoming_sdp_stream(), new_invite(), on_topology_change_response(), outbound_invite_auth(), pbx_start_incoming_request(), process_failure(), reason_header_outgoing_response(), reschedule_reinvite(), resend_reinvite(), sdp_requires_deferral(), send_delayed_request(), send_topology_change_refresh(), session_destructor(), session_inv_on_create_offer(), session_inv_on_media_update(), session_inv_on_rx_offer(), session_inv_on_state_changed(), session_inv_on_tsx_state_changed(), session_on_rx_request(), session_on_rx_response(), session_on_tsx_state(), session_outgoing_nat_hook(), set_caps(), set_from_header(), set_incoming_call_offer_cap(), 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 3573 of file res_pjsip_session.c.

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

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::@278 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::@279 read_callbacks
Added read callbacks - these are whole structs and not pointers.
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition vector.h:679

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

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

◆ ast_sip_session_media_state_free()

void ast_sip_session_media_state_free ( struct ast_sip_session_media_state media_state)

Free a session media state structure.

Since
15.0.0

Definition at line 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:636
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition vector.h:582

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

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

◆ ast_sip_session_media_stats_save()

void ast_sip_session_media_stats_save ( struct ast_sip_session sip_session,
struct ast_sip_session_media_state media_state 
)

Save a media stats.

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

Definition at line 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::@282 media_stats
#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition vector.h:499

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

Referenced by ast_sip_session_terminate(), and handle_negotiated_sdp().

◆ ast_sip_session_refresh()

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

Send a reinvite or UPDATE on a session.

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

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

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

Definition at line 2536 of file res_pjsip_session.c.

2542{
2543 return sip_session_refresh(session, on_request_creation, on_sdp_creation,
2544 on_response, method, generate_new_sdp, media_state, NULL, 0);
2545}
const char * method
Definition res_pjsip.c:1273
static int sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state, int queued)

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

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

◆ ast_sip_session_regenerate_answer()

int ast_sip_session_regenerate_answer ( struct ast_sip_session session,
ast_sip_session_sdp_creation_cb  on_sdp_creation 
)

Regenerate SDP Answer.

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

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

Definition at line 2547 of file res_pjsip_session.c.

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

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

Referenced by dtmf_mode_refresh_cb().

◆ ast_sip_session_register_sdp_handler()

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

Register an SDP handler.

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

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

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

Definition at line 147 of file res_pjsip_session.c.

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

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

Referenced by load_module(), and load_module().

◆ ast_sip_session_remove_datastore()

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

Remove a session datastore from the session.

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

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

Definition at line 1301 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_resume_reinvite()

void ast_sip_session_resume_reinvite ( struct ast_sip_session session)

Resumes processing of a deferred incoming re-invite.

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

Definition at line 2818 of file res_pjsip_session.c.

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

References ast_sip_get_pjsip_endpoint(), NULL, and session.

Referenced by t38_automatic_reject(), and t38_interpret_parameters().

◆ ast_sip_session_send_request()

void ast_sip_session_send_request ( struct ast_sip_session session,
pjsip_tx_data *  tdata 
)

Send a SIP request.

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

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

Definition at line 2862 of file res_pjsip_session.c.

2863{
2865}
void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response)
Send a SIP request and get called back when a response is received.

References ast_sip_session_send_request_with_cb(), NULL, and session.

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

◆ ast_sip_session_send_request_with_cb()

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

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

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

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

Definition at line 2838 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_send_response()

void ast_sip_session_send_response ( struct ast_sip_session session,
pjsip_tx_data *  tdata 
)

Send a SIP response.

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

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

Definition at line 2588 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_suspend()

void ast_sip_session_suspend ( struct ast_sip_session session)

Request and wait for the session serializer to be suspended.

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

Definition at line 3130 of file res_pjsip_session.c.

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

References ast_taskpool_serializer_suspend(), and session.

Referenced by chan_pjsip_indicate().

◆ ast_sip_session_terminate()

void ast_sip_session_terminate ( struct ast_sip_session session,
int  response 
)

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

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

Definition at line 3370 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_unregister_sdp_handler()

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

Unregister an SDP handler.

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

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

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

References ast_taskpool_serializer_unsuspend(), and session.

Referenced by chan_pjsip_indicate().

◆ check_content_disposition()

static int check_content_disposition ( pjsip_rx_data *  rdata)
static

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

Definition at line 3868 of file res_pjsip_session.c.

3869{
3870 pjsip_msg_body *body = rdata->msg_info.msg->body;
3871 pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3872
3873 if (body && ctype_hdr &&
3876 pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3877 while (part != NULL) {
3879 return 1;
3880 }
3881 part = pjsip_multipart_get_next_part(body, part);
3882 }
3883 }
3884 return 0;
3885}
#define SENTINEL
Definition compiler.h:87
int ast_sip_is_media_type_in(pjsip_media_type *a,...) attribute_sentinel
Check if a media type is in a list of others.
Definition res_pjsip.c:2199
pjsip_media_type pjsip_media_type_multipart_mixed
Definition res_pjsip.c:3909
pjsip_media_type pjsip_media_type_multipart_alternative
Definition res_pjsip.c:3908
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 3844 of file res_pjsip_session.c.

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

References check_sdp_content_type_supported().

Referenced by check_content_disposition().

◆ check_delayed_requests()

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

Definition at line 1593 of file res_pjsip_session.c.

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

References ao2_ref, ast_sip_push_task, and session.

Referenced by session_inv_on_tsx_state_changed().

◆ check_request_status()

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

Definition at line 4553 of file res_pjsip_session.c.

4554{
4555 struct ast_sip_session *session = inv->mod_data[session_module.id];
4556 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4557
4558 if (inv->state == PJSIP_INV_STATE_DISCONNECTED && inv->cancelling) {
4559 return 0;
4560 }
4561
4562 if (tsx->status_code != 503 && tsx->status_code != 408) {
4563 return 0;
4564 }
4565
4566 if (!ast_sip_failover_request(tsx->last_tx)) {
4567 return 0;
4568 }
4569
4570 pjsip_inv_uac_restart(inv, PJ_FALSE);
4571 /*
4572 * Bump the ref since it will be on a new transaction and
4573 * we don't want it to go away along with the old transaction.
4574 */
4575 pjsip_tx_data_add_ref(tsx->last_tx);
4577 return 1;
4578}
int ast_sip_failover_request(pjsip_tx_data *tdata)
Set a request to use the next value in the list of resolved addresses.
Definition res_pjsip.c:1810

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

Referenced by session_inv_on_state_changed().

◆ check_sdp_content_type_supported()

static int check_sdp_content_type_supported ( pjsip_media_type *  content_type)
static

Definition at line 3832 of file res_pjsip_session.c.

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

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

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

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

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

Referenced by ast_sip_session_alloc().

◆ datastore_hash()

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

Definition at line 2898 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_alloc().

◆ delay_request()

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

Definition at line 1602 of file res_pjsip_session.c.

1611{
1616
1617 if (!delay) {
1620 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1621 }
1622
1623 if (method == DELAYED_METHOD_BYE || queue_head) {
1624 /* Send BYE as early as possible */
1625 AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1626 } else {
1627 AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1628 }
1630}
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static struct ast_sip_session_delayed_request * delayed_request_alloc(enum delayed_method method, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state)
ast_sip_session_sdp_creation_cb on_sdp_creation
struct ast_sip_session_media_state * active_media_state
struct ast_sip_session_media_state * pending_media_state
ast_sip_session_response_cb on_response

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

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

◆ delayed_method2str()

static const char * delayed_method2str ( enum delayed_method  method)
static

Definition at line 1321 of file res_pjsip_session.c.

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

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

References ast_strlen_zero(), message_method, and method.

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

◆ fetch_callerid_num()

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

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

Definition at line 3585 of file res_pjsip_session.c.

3586{
3587 int res = -1;
3588 struct ast_party_id id;
3589
3590 ast_party_id_init(&id);
3591 if (!ast_sip_set_id_from_invite(rdata, &id, &session->endpoint->id.self, session->endpoint->id.trust_inbound)) {
3592 ast_copy_string(buf, id.number.str, len);
3593 res = 0;
3594 }
3595 ast_party_id_free(&id);
3596 return res;
3597}
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:2798
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
Information needed to identify an endpoint in a call.
Definition channel.h:340
Number structure.

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

Referenced by get_destination().

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session * generate_session_refresh_sdp ( struct ast_sip_session session)
static

Definition at line 1632 of file res_pjsip_session.c.

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

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

Referenced by sip_session_refresh().

◆ get_destination()

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

Determine where in the dialplan a call should go.

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

Parameters
sessionThe inbound SIP session
rdataThe SIP INVITE

Definition at line 3620 of file res_pjsip_session.c.

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

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

Referenced by new_invite().

◆ get_mid_bundle_group()

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

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

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

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

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

4444{
4445 struct ast_sip_session_supplement *supplement;
4446 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4447 SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4448 status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4449
4450 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4451 if (!(supplement->response_priority & response_priority)) {
4452 continue;
4453 }
4454 if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4455 supplement->incoming_response(session, rdata);
4456 }
4457 }
4458
4460}
void(* incoming_response)(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Called on an incoming SIP response This method is always called from a SIP servant thread.
enum ast_sip_session_response_priority response_priority

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

Referenced by handle_incoming().

◆ handle_incoming_sdp()

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

Definition at line 773 of file res_pjsip_session.c.

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

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

Referenced by new_invite(), and session_inv_on_rx_offer().

◆ handle_negotiated_sdp()

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

Definition at line 1072 of file res_pjsip_session.c.

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

References ast_channel_internal_fd_clear(), ast_channel_internal_fd_set(), ast_channel_lock, ast_channel_set_stream_topology(), ast_channel_stream_topology_changed_externally(), ast_channel_unlock, AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED, AST_EXTENDED_FDS, AST_FRAME_CONTROL, ast_log, AST_MEDIA_TYPE_IMAGE, ast_null_frame, ast_queue_frame(), ast_sip_session_get_name(), ast_sip_session_media_state_clone(), ast_sip_session_media_state_free(), ast_sip_session_media_state_reset(), ast_sip_session_media_stats_save(), ast_stream_get_state(), ast_stream_set_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_clone(), ast_stream_topology_equal(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), AST_VECTOR_ELEM_CLEANUP_NOOP, AST_VECTOR_GET, AST_VECTOR_GET_ADDR, AST_VECTOR_RESET, AST_VECTOR_SIZE, ast_sip_session_media::changed, ast_sip_session_media_read_callback_state::fd, handle_negotiated_sdp_session_media(), ast_sip_session_media::handler, ast_frame_subclass::integer, LOG_WARNING, NULL, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, session, session_media_set_handler(), ast_frame::subclass, and SWAP.

Referenced by session_inv_on_media_update().

◆ handle_negotiated_sdp_session_media()

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

Definition at line 973 of file res_pjsip_session.c.

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

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

Referenced by handle_negotiated_sdp().

◆ handle_new_invite_request()

static void handle_new_invite_request ( pjsip_rx_data *  rdata)
static

Definition at line 4031 of file res_pjsip_session.c.

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

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

Referenced by session_on_rx_request().

◆ handle_outgoing_request()

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

Definition at line 4474 of file res_pjsip_session.c.

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

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

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

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

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

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

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

Referenced by session_on_rx_request().

◆ internal_sip_session_media_state_alloc()

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

Definition at line 223 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_media_state_alloc(), and ast_sip_session_media_state_clone().

◆ invite_collision_timeout()

static int invite_collision_timeout ( void *  vsession)
static

Definition at line 1549 of file res_pjsip_session.c.

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

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

Referenced by resend_reinvite().

◆ invite_proceeding()

static int invite_proceeding ( void *  vsession)
static

Definition at line 1451 of file res_pjsip_session.c.

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

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

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

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

◆ is_media_state_valid()

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

Definition at line 1763 of file res_pjsip_session.c.

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

6116{
6117 pjsip_endpoint *endpt;
6118
6121 }
6122 if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
6124 }
6129 if (!sdp_handlers) {
6131 }
6133 pjsip_inv_usage_init(endpt, &inv_callback);
6134 pjsip_100rel_init_module(endpt);
6135 pjsip_timer_init_module(endpt);
6138 }
6141
6143
6145#ifdef TEST_FRAMEWORK
6146 AST_TEST_REGISTER(test_resolve_refresh_media_states);
6147#endif
6149}
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition module.h:478
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
void pjsip_reason_header_load(void)
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:111
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int sdp_handler_list_cmp(void *obj, void *arg, int flags)
static pjsip_module session_reinvite_module
#define SDP_HANDLER_BUCKETS
static pjsip_module outbound_invite_auth_module
static pjsip_inv_callback inv_callback
static struct ast_sip_nat_hook * nat_hook
NAT hook for modifying outgoing messages with SDP.
static int sdp_handler_list_hash(const void *obj, int flags)
static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Hook for modifying outgoing messages with SDP to contain the proper address information.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition sorcery.c:2126
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition sorcery.c:1808
struct ast_module * self
Definition module.h:356
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition res_pjsip.h:331
#define AST_TEST_REGISTER(cb)
Definition test.h:127

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

◆ media_stats_local_ssrc_cmp()

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

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

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

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

◆ new_invite_initial_answer()

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

Definition at line 3704 of file res_pjsip_session.c.

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

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

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

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

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

Referenced by handle_new_invite_request().

◆ remove_handler()

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

Definition at line 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::@505 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 4262 of file res_pjsip_session.c.

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

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

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

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

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

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

Referenced by invite_proceeding(), and invite_terminated().

◆ session_datastore_destroy()

static void session_datastore_destroy ( void *  obj)
static

Definition at line 1240 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_alloc_datastore().

◆ session_destructor()

static void session_destructor ( void *  obj)
static

Definition at line 2920 of file res_pjsip_session.c.

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

Referenced by ast_sip_session_alloc().

◆ session_end()

static int session_end ( void *  vsession)
static

Definition at line 4518 of file res_pjsip_session.c.

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

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

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

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

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

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

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

4694{
4695 /* XXX STUB */
4696}

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

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

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

◆ session_inv_on_rx_offer()

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

Definition at line 5242 of file res_pjsip_session.c.

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

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

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

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

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

◆ session_media_dtor()

static void session_media_dtor ( void *  obj)
static

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

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

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

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

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

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

4231{
4232 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
4234 if (session) {
4236 }
4237
4238 return PJ_SUCCESS;
4239}

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

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

References ao2_cleanup, ao2_find, ast_copy_pj_str(), ast_debug, AST_LIST_TRAVERSE, ast_sip_dialog_get_session(), ast_sip_get_transport_state(), ast_sip_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 2753 of file res_pjsip_session.c.

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

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

◆ session_termination_cb()

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

Definition at line 3464 of file res_pjsip_session.c.

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

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

References ao2_ref, ast_sip_session_terminate(), and session.

Referenced by session_termination_cb().

◆ set_from_header()

static void set_from_header ( struct ast_sip_session session)
static

Definition at line 1648 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_create_invite().

◆ set_mid_and_bundle_group()

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

Definition at line 655 of file res_pjsip_session.c.

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

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

Referenced by handle_incoming_sdp(), and handle_negotiated_sdp_session_media().

◆ set_remote_mslabel_and_stream_group()

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

Definition at line 693 of file res_pjsip_session.c.

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

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

References NULL, outbound_invite_auth_module, and status.

Referenced by ast_sip_session_create_outgoing().

◆ sip_channel_destroy()

static void sip_channel_destroy ( void *  obj)
static

Destructor for SIP channel.

Definition at line 2986 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_channel_pvt_alloc().

◆ sip_session_defer_termination_stop_timer()

static void sip_session_defer_termination_stop_timer ( struct ast_sip_session session)
static

Definition at line 3505 of file res_pjsip_session.c.

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

References ao2_ref, ast_sip_get_pjsip_endpoint(), and session.

Referenced by ast_sip_session_defer_termination_cancel(), and session_end().

◆ sip_session_refresh()

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

Definition at line 2196 of file res_pjsip_session.c.

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

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

Referenced by ast_sip_session_refresh(), and send_delayed_request().

◆ stream_destroy()

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

Definition at line 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().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6151 of file res_pjsip_session.c.

6152{
6154
6155#ifdef TEST_FRAMEWORK
6156 AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6157#endif
6164 return 0;
6165}
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 1579 of file res_pjsip_session.c.

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

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

Referenced by session_inv_on_tsx_state_changed().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Session resource" , .key = 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 6173 of file res_pjsip_session.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6173 of file res_pjsip_session.c.

◆ inv_callback

pjsip_inv_callback inv_callback
static

Definition at line 5486 of file res_pjsip_session.c.

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

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

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

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

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

Referenced by load_module(), and unload_module().