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

Go to the source code of this file.

Data Structures

struct  ast_sip_session_delayed_request
 Structure used for sending delayed requests. More...
 
struct  ast_sip_session_suspender
 struct controlling the suspension of the session's serializer. More...
 
struct  new_invite
 
struct  sdp_handler_list
 
struct  sip_session_media_bundle_group
 Bundle group building structure. More...
 

Macros

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

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Session resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static pjsip_inv_callback inv_callback
 
static struct ast_sip_nat_hooknat_hook
 NAT hook for modifying outgoing messages with SDP. More...
 
static pjsip_module outbound_invite_auth_module
 
static struct ao2_containersdp_handlers
 Registered SDP stream handlers. More...
 
static pjsip_module session_module
 
static pjsip_module session_reinvite_module
 

Macro Definition Documentation

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Definition at line 1226 of file res_pjsip_session.c.

◆ DEFAULT_NUM_SESSION_MEDIA

#define DEFAULT_NUM_SESSION_MEDIA   2

Definition at line 61 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 1739 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 1737 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 1738 of file res_pjsip_session.c.

◆ MEDIA_BUCKETS

#define MEDIA_BUCKETS   7

Definition at line 1227 of file res_pjsip_session.c.

◆ MOD_DATA_NAT_HOOK

#define MOD_DATA_NAT_HOOK   "nat_hook"

Definition at line 58 of file res_pjsip_session.c.

◆ MOD_DATA_ON_RESPONSE

#define MOD_DATA_ON_RESPONSE   "on_response"

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

◆ SDP_HANDLER_BUCKETS

#define SDP_HANDLER_BUCKETS   11

Definition at line 55 of file res_pjsip_session.c.

◆ STATE_NONE

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

Definition at line 1736 of file res_pjsip_session.c.

◆ STATE_REMOVED

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

Definition at line 1735 of file res_pjsip_session.c.

◆ STREAM_REMOVED

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

Definition at line 1734 of file res_pjsip_session.c.

Enumeration Type Documentation

◆ delayed_method

Enumerator
DELAYED_METHOD_INVITE 
DELAYED_METHOD_UPDATE 
DELAYED_METHOD_BYE 

Definition at line 1295 of file res_pjsip_session.c.

1295  {
1299 };
@ 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 3644 of file res_pjsip_session.c.

3644  {
3645  /*! The extension was successfully found */
3647  /*! The extension specified in the RURI was not found */
3649  /*! The extension specified in the RURI was a partial match */
3651  /*! The RURI is of an unsupported scheme */
3653 };
@ 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 4358 of file res_pjsip_session.c.

4359 {
4360  int id = session_module.id;
4361  struct ast_sip_session *session = NULL;
4362 
4363  if (!DEBUG_ATLEAST(5)) {
4364  /* Debug not spamy enough */
4365  return;
4366  }
4367 
4368  ast_log(LOG_DEBUG, "Function %s called on event %s\n",
4369  function, pjsip_event_str(e->type));
4370  if (!inv) {
4371  ast_log(LOG_DEBUG, "Transaction %p does not belong to an inv_session?\n", tsx);
4372  ast_log(LOG_DEBUG, "The transaction state is %s\n",
4373  pjsip_tsx_state_str(tsx->state));
4374  return;
4375  }
4376  if (id > -1) {
4377  session = inv->mod_data[session_module.id];
4378  }
4379  if (!session) {
4380  ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv);
4381  } else {
4382  ast_log(LOG_DEBUG, "The state change pertains to the endpoint '%s(%s)'\n",
4384  session->channel ? ast_channel_name(session->channel) : "");
4385  }
4386  if (inv->invite_tsx) {
4387  ast_log(LOG_DEBUG, "The inv session still has an invite_tsx (%p)\n",
4388  inv->invite_tsx);
4389  } else {
4390  ast_log(LOG_DEBUG, "The inv session does NOT have an invite_tsx\n");
4391  }
4392  if (tsx) {
4393  ast_log(LOG_DEBUG, "The %s %.*s transaction involved in this state change is %p\n",
4394  pjsip_role_name(tsx->role),
4395  (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
4396  tsx);
4397  ast_log(LOG_DEBUG, "The current transaction state is %s\n",
4398  pjsip_tsx_state_str(tsx->state));
4399  ast_log(LOG_DEBUG, "The transaction state change event is %s\n",
4400  pjsip_event_str(e->body.tsx_state.type));
4401  } else {
4402  ast_log(LOG_DEBUG, "There is no transaction involved in this state change\n");
4403  }
4404  ast_log(LOG_DEBUG, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
4405 }
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)
Definition: logger.h:440
#define LOG_DEBUG
Definition: logger.h:242
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:2312
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 6155 of file res_pjsip_session.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

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

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

Referenced by create_local_sdp().

◆ add_sdp_streams()

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

Definition at line 4968 of file res_pjsip_session.c.

4972 {
4973  struct ast_sip_session_sdp_handler *handler = session_media->handler;
4974  RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
4975  int res = 0;
4976  SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
4977  ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
4978 
4979  if (handler) {
4980  /* if an already assigned handler reports a catastrophic error, fail */
4981  res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
4982  if (res < 0) {
4983  SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
4984  }
4985  SCOPE_EXIT_RTN_VALUE(0, "Had handler\n");
4986  }
4987 
4988  handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY);
4989  if (!handler_list) {
4990  SCOPE_EXIT_RTN_VALUE(0, "No handlers\n");
4991  }
4992 
4993  /* no handler for this stream type and we have a list to search */
4994  AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
4995  if (handler == session_media->handler) {
4996  continue;
4997  }
4998  res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream);
4999  if (res < 0) {
5000  /* catastrophic error */
5001  SCOPE_EXIT_RTN_VALUE(-1, "Coudn't create sdp stream\n");
5002  }
5003  if (res > 0) {
5004  /* Handled by this handler. Move to the next stream */
5005  session_media_set_handler(session_media, handler);
5006  SCOPE_EXIT_RTN_VALUE(0, "Handled\n");
5007  }
5008  }
5009 
5010  /* streams that weren't handled won't be included in generated outbound SDP */
5011  SCOPE_EXIT_RTN_VALUE(0, "Not handled\n");
5012 }
#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:347
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Definition: logger.h:900
#define SCOPE_ENTER(level,...)
Definition: logger.h:881
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.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
static struct ao2_container * sdp_handlers
Registered SDP stream handlers.
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:1165
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:936

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

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

2976 {
2977  struct ast_sip_channel_pvt *channel = ao2_alloc(sizeof(*channel), sip_channel_destroy);
2978 
2979  if (!channel) {
2980  return NULL;
2981  }
2982 
2983  ao2_ref(pvt, +1);
2984  channel->pvt = pvt;
2985  ao2_ref(session, +1);
2986  channel->session = session;
2987 
2988  return channel;
2989 }
#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 3629 of file res_pjsip_session.c.

3630 {
3631  pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
3632  struct ast_sip_session *session;
3633 
3634  if (!inv_session ||
3635  !(session = inv_session->mod_data[session_module.id])) {
3636  return NULL;
3637  }
3638 
3639  ao2_ref(session, +1);
3640 
3641  return session;
3642 }
struct pjsip_inv_session * inv_session

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

Referenced by assign_uuid(), refer_incoming_attended_request(), refer_incoming_invite_request(), 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 1273 of file res_pjsip_session.c.

1274 {
1275  ast_assert(datastore != NULL);
1276  ast_assert(datastore->info != NULL);
1277  ast_assert(ast_strlen_zero(datastore->uid) == 0);
1278 
1279  if (!ao2_link(session->datastores, datastore)) {
1280  return -1;
1281  }
1282  return 0;
1283 }
#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:734

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

Referenced by add_header(), chan_pjsip_incoming_request(), chan_pjsip_session_begin(), handle_incoming_request(), incoming_request(), 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 2991 of file res_pjsip_session.c.

2993 {
2995  struct ast_sip_session *ret_session;
2996  int dsp_features = 0;
2997 
2999  if (!session) {
3000  return NULL;
3001  }
3002 
3003  AST_LIST_HEAD_INIT(&session->supplements);
3004  AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
3005  ast_party_id_init(&session->id);
3006 
3008  if (!session->direct_media_cap) {
3009  return NULL;
3010  }
3013  if (!session->datastores) {
3014  return NULL;
3015  }
3016  session->active_media_state = ast_sip_session_media_state_alloc();
3017  if (!session->active_media_state) {
3018  return NULL;
3019  }
3020  session->pending_media_state = ast_sip_session_media_state_alloc();
3021  if (!session->pending_media_state) {
3022  return NULL;
3023  }
3024  if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
3025  return NULL;
3026  }
3027 
3029  dsp_features |= DSP_FEATURE_DIGIT_DETECT;
3030  }
3031  if (endpoint->faxdetect) {
3032  dsp_features |= DSP_FEATURE_FAX_DETECT;
3033  }
3034  if (dsp_features) {
3035  session->dsp = ast_dsp_new();
3036  if (!session->dsp) {
3037  return NULL;
3038  }
3039 
3040  ast_dsp_set_features(session->dsp, dsp_features);
3041  }
3042 
3043  session->endpoint = ao2_bump(endpoint);
3044 
3045  if (rdata) {
3046  /*
3047  * We must continue using the serializer that the original
3048  * INVITE came in on for the dialog. There may be
3049  * retransmissions already enqueued in the original
3050  * serializer that can result in reentrancy and message
3051  * sequencing problems.
3052  */
3053  session->serializer = ast_sip_get_distributor_serializer(rdata);
3054  } else {
3055  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
3056 
3057  /* Create name with seq number appended. */
3058  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outsess/%s",
3060 
3061  session->serializer = ast_sip_create_serializer(tps_name);
3062  }
3063  if (!session->serializer) {
3064  return NULL;
3065  }
3068 
3069  /* When a PJSIP INVITE session is created it is created with a reference
3070  * count of 1, with that reference being managed by the underlying state
3071  * of the INVITE session itself. When the INVITE session transitions to
3072  * a DISCONNECTED state that reference is released. This means we can not
3073  * rely on that reference to ensure the INVITE session remains for the
3074  * lifetime of our session. To ensure it does we add our own reference
3075  * and release it when our own session goes away, ensuring that the INVITE
3076  * session remains for the lifetime of session.
3077  */
3078 
3079 #ifdef HAVE_PJSIP_INV_SESSION_REF
3080  if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
3081  ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3082  return NULL;
3083  }
3084 #endif
3085 
3086  pjsip_dlg_inc_session(inv_session->dlg, &session_module);
3087  inv_session->mod_data[session_module.id] = ao2_bump(session);
3088  session->contact = ao2_bump(contact);
3089  session->inv_session = inv_session;
3090 
3091  session->dtmf = endpoint->dtmf;
3092  session->moh_passthrough = endpoint->moh_passthrough;
3093 
3095  /* Release the ref held by session->inv_session */
3096  ao2_ref(session, -1);
3097  return NULL;
3098  }
3099 
3100  session->authentication_challenge_count = 0;
3101 
3102  /* Fire session begin handlers */
3104 
3105  /* Avoid unnecessary ref manipulation to return a session */
3106  ret_session = session;
3107  session = NULL;
3108  return ret_session;
3109 }
@ 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:1751
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1748
#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:1758
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:5170
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define LOG_ERROR
Definition: logger.h:286
@ AST_SIP_DTMF_AUTO
Definition: res_pjsip.h:438
@ AST_SIP_DTMF_INBAND
Definition: res_pjsip.h:434
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
static void handle_session_begin(struct ast_sip_session *session)
#define DATASTORE_BUCKETS
static void session_destructor(void *obj)
static int datastore_cmp(void *obj, void *arg, int flags)
static int datastore_hash(const void *obj, int flags)
int ast_sip_session_add_supplements(struct ast_sip_session *session)
Add supplements to a SIP session.
Definition: pjsip_session.c:90
unsigned int moh_passthrough
Definition: res_pjsip.h:923
enum ast_sip_dtmf_mode dtmf
Definition: res_pjsip.h:901
unsigned int faxdetect
Definition: res_pjsip.h:913
struct ast_sip_endpoint * endpoint
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

References ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_bump, ao2_cleanup, ao2_container_alloc_hash, ao2_ref, ast_dsp_new(), ast_dsp_set_features(), ast_format_cap_alloc, AST_FORMAT_CAP_FLAG_DEFAULT, AST_LIST_HEAD_INIT, AST_LIST_HEAD_INIT_NOLOCK, ast_log, ast_party_id_init(), ast_sip_create_serializer(), ast_sip_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), AST_SIP_DTMF_AUTO, AST_SIP_DTMF_INBAND, ast_sip_get_distributor_serializer(), ast_sip_session_add_supplements(), ast_sip_session_media_state_alloc(), ast_sorcery_object_get_id(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, AST_VECTOR_INIT, 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 1243 of file res_pjsip_session.c.

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

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

Referenced by add_header(), chan_pjsip_incoming_request(), chan_pjsip_session_begin(), handle_incoming_request(), incoming_request(), 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 2848 of file res_pjsip_session.c.

2849 {
2850  pjmedia_sdp_session *offer;
2852 
2853  if (!(offer = create_local_sdp(session->inv_session, session, NULL))) {
2854  pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
2855  SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create offer\n");
2856  }
2857 
2858  pjsip_inv_set_local_sdp(session->inv_session, offer);
2859  pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE);
2860 #ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS
2861  if (!session->endpoint->preferred_codec_only) {
2862  pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE);
2863  }
2864 #endif
2865 
2866  /*
2867  * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the
2868  * From in the initial INVITE will be wrong but the rest of the messages will be OK.
2869  */
2871 
2872  if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
2873  SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
2874  }
2875 
2877 }
static struct pjmedia_sdp_session * create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
static void set_from_header(struct ast_sip_session *session)

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

3321 {
3322  const char *uri = NULL;
3323  RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup);
3324  RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
3325  pjsip_timer_setting timer;
3326  pjsip_dialog *dlg;
3327  struct pjsip_inv_session *inv_session;
3329  struct ast_sip_session *ret_session;
3330  SCOPE_ENTER(1, "%s %s Topology: %s\n", ast_sorcery_object_get_id(endpoint), request_user,
3331  ast_str_tmp(256, ast_stream_topology_to_str(req_topology, &STR_TMP)));
3332 
3333  /* If no location has been provided use the AOR list from the endpoint itself */
3334  if (location || !contact) {
3335  location = S_OR(location, endpoint->aors);
3336 
3338  &found_aor, &found_contact);
3339  if (!found_contact || ast_strlen_zero(found_contact->uri)) {
3340  uri = location;
3341  } else {
3342  uri = found_contact->uri;
3343  }
3344  } else {
3345  uri = contact->uri;
3346  }
3347 
3348  /* If we still have no URI to dial fail to create the session */
3349  if (ast_strlen_zero(uri)) {
3350  ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
3352  SCOPE_EXIT_RTN_VALUE(NULL, "No URI\n");
3353  }
3354 
3355  if (!(dlg = ast_sip_create_dialog_uac(endpoint, uri, request_user))) {
3356  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create dialog\n");
3357  }
3358 
3359  if (setup_outbound_invite_auth(dlg)) {
3360  pjsip_dlg_terminate(dlg);
3361  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't setup auth\n");
3362  }
3363 
3364  if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions.flags, &inv_session) != PJ_SUCCESS) {
3365  pjsip_dlg_terminate(dlg);
3366  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create uac\n");
3367  }
3368 #if defined(HAVE_PJSIP_REPLACE_MEDIA_STREAM) || defined(PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE)
3369  inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
3370 #endif
3371 
3372  pjsip_timer_setting_default(&timer);
3373  timer.min_se = endpoint->extensions.timer.min_se;
3374  timer.sess_expires = endpoint->extensions.timer.sess_expires;
3375  pjsip_timer_init_session(inv_session, &timer);
3376 
3377  session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact,
3378  inv_session, NULL);
3379  if (!session) {
3380  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3381  return NULL;
3382  }
3383  session->aor = ao2_bump(found_aor);
3384  session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;
3385 
3387 
3388  if (ast_stream_topology_get_count(req_topology) > 0) {
3389  /* get joint caps between req_topology and endpoint topology */
3390  int i;
3391 
3392  for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {
3393  struct ast_stream *req_stream;
3394  struct ast_stream *clone_stream;
3395 
3396  req_stream = ast_stream_topology_get_stream(req_topology, i);
3397 
3398  if (ast_stream_get_state(req_stream) == AST_STREAM_STATE_REMOVED) {
3399  continue;
3400  }
3401 
3402  clone_stream = ast_sip_session_create_joint_call_stream(session, req_stream);
3403  if (!clone_stream || ast_stream_get_format_count(clone_stream) == 0) {
3404  ast_stream_free(clone_stream);
3405  continue;
3406  }
3407 
3408  if (!session->pending_media_state->topology) {
3409  session->pending_media_state->topology = ast_stream_topology_alloc();
3410  if (!session->pending_media_state->topology) {
3411  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3412  ao2_ref(session, -1);
3413  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create topology\n");
3414  }
3415  }
3416 
3417  if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) {
3418  ast_stream_free(clone_stream);
3419  continue;
3420  }
3421  }
3422  }
3423 
3424  if (!session->pending_media_state->topology) {
3425  /* Use the configured topology on the endpoint as the pending one */
3426  session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology);
3427  if (!session->pending_media_state->topology) {
3428  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3429  ao2_ref(session, -1);
3430  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't clone topology\n");
3431  }
3432  }
3433 
3434  if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3435  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3436  /* Since we are not notifying ourselves that the INVITE session is being terminated
3437  * we need to manually drop its reference to session
3438  */
3439  ao2_ref(session, -1);
3440  SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't add usage\n");
3441  }
3442 
3443  /* Avoid unnecessary ref manipulation to return a session */
3444  ret_session = session;
3445  session = NULL;
3446  SCOPE_EXIT_RTN_VALUE(ret_session);
3447 }
static struct ast_timer * timer
Definition: chan_iax2.c:357
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:1759
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:4065
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition: res_pjsip.h:1087
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
static int setup_outbound_invite_auth(pjsip_dialog *dlg)
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.
@ 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_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition: stream.h:78
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
int ast_stream_get_format_count(const struct ast_stream *stream)
Get the count of the current negotiated formats of a stream.
Definition: stream.c:358
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
#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:376
Contact associated with an address of record.
Definition: res_pjsip.h:297
struct ast_sip_timer_options timer
Definition: res_pjsip.h:612
struct ast_party_id self
Definition: res_pjsip.h:663
struct ast_stream_topology * topology
Definition: res_pjsip.h:814
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:891
const ast_string_field aors
Definition: res_pjsip.h:881
struct ast_sip_endpoint_extensions extensions
Definition: res_pjsip.h:883
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:885
unsigned int sess_expires
Definition: res_pjsip.h:599
unsigned int min_se
Definition: res_pjsip.h:597

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::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, and ast_sip_endpoint_media_configuration::topology.

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

3556 {
3557  pj_time_val delay = { .sec = 60, };
3558  int res;
3559 
3560  /* The session should not have an active deferred termination request. */
3561  ast_assert(!session->defer_terminate);
3562 
3563  session->defer_terminate = 1;
3564 
3565  session->defer_end = 1;
3566  session->ended_while_deferred = 0;
3567 
3568  ao2_ref(session, +1);
3569  pj_timer_entry_init(&session->scheduled_termination, 0, session, session_termination_cb);
3570 
3571  res = (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
3572  &session->scheduled_termination, &delay) != PJ_SUCCESS) ? -1 : 0;
3573  if (res) {
3574  session->defer_terminate = 0;
3575  ao2_ref(session, -1);
3576  }
3577  return res;
3578 }
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3755
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 3595 of file res_pjsip_session.c.

3596 {
3597  if (!session->defer_terminate) {
3598  /* Already canceled or timer fired. */
3599  return;
3600  }
3601 
3602  session->defer_terminate = 0;
3603 
3604  if (session->terminate_while_deferred) {
3605  /* Complete the termination started by the upper layer. */
3607  }
3608 
3609  /* Stop the termination timer if it is still running. */
3611 }
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 3613 of file res_pjsip_session.c.

3614 {
3615  if (!session->defer_end) {
3616  return;
3617  }
3618 
3619  session->defer_end = 0;
3620 
3621  if (session->ended_while_deferred) {
3622  /* Complete the session end started by the remote hangup. */
3623  ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
3624  session->ended_while_deferred = 0;
3626  }
3627 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:451
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 1285 of file res_pjsip_session.c.

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

References ao2_find, name, OBJ_KEY, and session.

Referenced by add_header(), channel_read_pjsip(), direct_media_mitigate_glare(), handle_outgoing_response(), incoming_request(), read_header(), read_headers(), remove_header(), session_refresh_state_get_or_alloc(), t38_automatic_reject(), t38_state_get_or_alloc(), and update_header().

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

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

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

Referenced by add_sdp_streams(), answer(), apply_negotiated_sdp_stream(), 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_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(), handle_incoming_before_media(), handle_incoming_request(), handle_incoming_response(), handle_incoming_sdp(), handle_negotiated_sdp(), handle_negotiated_sdp_session_media(), handle_new_invite_request(), handle_outgoing_request(), handle_outgoing_response(), invite_collision_timeout(), invite_proceeding(), invite_terminated(), negotiate_incoming_sdp_stream(), new_invite(), on_topology_change_response(), outbound_invite_auth(), pbx_start_incoming_request(), reschedule_reinvite(), resend_reinvite(), sdp_requires_deferral(), send_delayed_request(), send_topology_change_refresh(), session_destructor(), 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(), and sip_session_refresh().

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

360 {
361  int index;
362 
363  if (!session->pending_media_state->topology) {
364  ast_log(LOG_WARNING, "Pending topology was NULL for channel '%s'\n",
365  session->channel ? ast_channel_name(session->channel) : "unknown");
366  return 0;
367  }
368 
370  return 0;
371  }
372 
373  for (index = 0; index < ast_stream_topology_get_count(session->pending_media_state->topology); ++index) {
374  if (ast_stream_get_type(ast_stream_topology_get_stream(session->pending_media_state->topology, index)) !=
375  ast_stream_get_type(stream)) {
376  continue;
377  }
378 
379  return ast_stream_topology_get_stream(session->pending_media_state->topology, index) == stream ? 1 : 0;
380  }
381 
382  return 0;
383 }
#define LOG_WARNING
Definition: logger.h:275
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 385 of file res_pjsip_session.c.

387 {
388  struct ast_sip_session_media_read_callback_state callback_state = {
389  .fd = fd,
390  .read_callback = callback,
391  .session = session_media,
392  };
393 
394  /* The contents of the vector are whole structs and not pointers */
395  return AST_VECTOR_APPEND(&session->pending_media_state->read_callbacks, callback_state);
396 }
Structure which contains read callback information.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

References AST_VECTOR_APPEND, ast_sip_session_media_read_callback_state::fd, and session.

Referenced by apply_negotiated_sdp_stream().

◆ ast_sip_session_media_get_transport()

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

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

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

Definition at line 414 of file res_pjsip_session.c.

415 {
416  int index;
417 
418  if (!session->endpoint->media.bundle || ast_strlen_zero(session_media->mid)) {
419  return session_media;
420  }
421 
422  for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
423  struct ast_sip_session_media *bundle_group_session_media;
424 
425  bundle_group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
426 
427  /* The first session which is in the bundle group is considered the authoritative session for transport */
428  if (bundle_group_session_media->bundle_group == session_media->bundle_group) {
429  return bundle_group_session_media;
430  }
431  }
432 
433  return session_media;
434 }

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

400 {
401  if (session_media->write_callback) {
402  if (session_media->write_callback == callback) {
403  return 0;
404  }
405 
406  return -1;
407  }
408 
409  session_media->write_callback = callback;
410 
411  return 0;
412 }
ast_sip_session_media_write_cb write_callback
The write callback when writing frames.

References ast_sip_session_media::write_callback.

Referenced by apply_negotiated_sdp_stream().

◆ ast_sip_session_media_state_add()

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

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

Since
15.0.0

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

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

Definition at line 490 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_media_state_alloc()

struct ast_sip_session_media_state* ast_sip_session_media_state_alloc ( void  )

Allocate a session media state structure.

Since
15.0.0
Return values
non-NULLsuccess
NULLfailure

Definition at line 238 of file res_pjsip_session.c.

239 {
242 }
#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 297 of file res_pjsip_session.c.

298 {
299  struct ast_sip_session_media_state *cloned;
300  int index;
301 
302  if (!media_state) {
303  return NULL;
304  }
305 
307  AST_VECTOR_SIZE(&media_state->sessions),
308  AST_VECTOR_SIZE(&media_state->read_callbacks));
309  if (!cloned) {
310  return NULL;
311  }
312 
313  if (media_state->topology) {
314  cloned->topology = ast_stream_topology_clone(media_state->topology);
315  if (!cloned->topology) {
317  return NULL;
318  }
319  }
320 
321  for (index = 0; index < AST_VECTOR_SIZE(&media_state->sessions); ++index) {
322  struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index);
324 
325  ao2_bump(session_media);
326  if (AST_VECTOR_REPLACE(&cloned->sessions, index, session_media)) {
327  ao2_cleanup(session_media);
328  }
330  !cloned->default_session[type]) {
331  cloned->default_session[type] = session_media;
332  }
333  }
334 
335  for (index = 0; index < AST_VECTOR_SIZE(&media_state->read_callbacks); ++index) {
337 
339  }
340 
341  return cloned;
342 }
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::@293 read_callbacks
Added read callbacks - these are whole structs and not pointers.
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:668

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

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

◆ ast_sip_session_media_state_free()

void ast_sip_session_media_state_free ( struct ast_sip_session_media_state media_state)

Free a session media state structure.

Since
15.0.0

Definition at line 344 of file res_pjsip_session.c.

345 {
346  if (!media_state) {
347  return;
348  }
349 
350  /* This will reset the internal state so we only have to free persistent things */
352 
353  AST_VECTOR_FREE(&media_state->sessions);
354  AST_VECTOR_FREE(&media_state->read_callbacks);
355 
356  ast_free(media_state);
357 }
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174

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

Referenced by ast_sip_session_media_state_clone(), delay_request(), delayed_request_free(), handle_negotiated_sdp(), reschedule_reinvite(), resolve_refresh_media_states(), session_destructor(), sip_session_refresh(), t38_create_media_state(), t38_reinvite_response_cb(), 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 278 of file res_pjsip_session.c.

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

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

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

◆ ast_sip_session_media_stats_save()

void ast_sip_session_media_stats_save ( struct ast_sip_session sip_session,
struct ast_sip_session_media_state media_state 
)

Save a media stats.

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

Definition at line 244 of file res_pjsip_session.c.

245 {
246  int i;
247  int ret;
248 
249  if (!media_state || !sip_session) {
250  return;
251  }
252 
253  for (i = 0; i < AST_VECTOR_SIZE(&media_state->sessions); i++) {
254  struct ast_rtp_instance_stats *stats_tmp = NULL;
255  struct ast_sip_session_media *media = AST_VECTOR_GET(&media_state->sessions, i);
256  if (!media || !media->rtp) {
257  continue;
258  }
259 
260  stats_tmp = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
261  if (!stats_tmp) {
262  return;
263  }
264 
265  ret = ast_rtp_instance_get_stats(media->rtp, stats_tmp, AST_RTP_INSTANCE_STAT_ALL);
266  if (ret) {
267  ast_free(stats_tmp);
268  continue;
269  }
270 
271  /* remove all the duplicated stats if exist */
273 
274  AST_VECTOR_APPEND(&sip_session->media_stats, stats_tmp);
275  }
276 }
#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:182
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
Retrieve statistics about an RTP instance.
Definition: rtp_engine.c:2438
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sip_session::@296 media_stats
#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition: vector.h:488

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

Referenced by ast_sip_session_terminate(), and handle_negotiated_sdp().

◆ ast_sip_session_refresh()

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

Send a reinvite or UPDATE on a session.

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

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

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

Definition at line 2525 of file res_pjsip_session.c.

2531 {
2532  return sip_session_refresh(session, on_request_creation, on_sdp_creation,
2533  on_response, method, generate_new_sdp, media_state, NULL, 0);
2534 }
const char * method
Definition: res_pjsip.c:4372
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 2536 of file res_pjsip_session.c.

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

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

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

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.

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

1291 {
1292  ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
1293 }
#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(), 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 2799 of file res_pjsip_session.c.

2800 {
2801  if (!session->deferred_reinvite) {
2802  return;
2803  }
2804 
2805  if (session->channel) {
2806  pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(),
2807  session->deferred_reinvite, NULL, NULL);
2808  }
2809  pjsip_rx_data_free_cloned(session->deferred_reinvite);
2810  session->deferred_reinvite = NULL;
2811 }

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

2844 {
2846 }
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 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 2819 of file res_pjsip_session.c.

2821 {
2822  pjsip_inv_session *inv_session = session->inv_session;
2823 
2824  /* For every request except BYE we disallow sending of the message when
2825  * the session has been disconnected. A BYE request is special though
2826  * because it can be sent again after the session is disconnected except
2827  * with credentials.
2828  */
2829  if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED &&
2830  tdata->msg->line.req.method.id != PJSIP_BYE_METHOD) {
2831  return;
2832  }
2833 
2834  ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id,
2835  MOD_DATA_ON_RESPONSE, on_response);
2836 
2838  pjsip_inv_send_msg(session->inv_session, tdata);
2839 
2840  return;
2841 }
#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:2750
#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 2577 of file res_pjsip_session.c.

2578 {
2580  pjsip_inv_send_msg(session->inv_session, tdata);
2581  return;
2582 }
static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)

References handle_outgoing_response(), and session.

Referenced by answer(), ast_sip_session_terminate(), chan_pjsip_incoming_request(), indicate(), new_invite(), 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 3156 of file res_pjsip_session.c.

3157 {
3158  struct ast_sip_session_suspender *suspender;
3159  int res;
3160 
3161  ast_assert(session->suspended == NULL);
3162 
3163  if (ast_taskprocessor_is_task(session->serializer)) {
3164  /* I am the session's serializer thread so I cannot suspend. */
3165  return;
3166  }
3167 
3168  if (ast_taskprocessor_is_suspended(session->serializer)) {
3169  /* The serializer already suspended. */
3170  return;
3171  }
3172 
3173  suspender = ao2_alloc(sizeof(*suspender), sip_session_suspender_dtor);
3174  if (!suspender) {
3175  /* We will just have to hope that the system does not deadlock */
3176  return;
3177  }
3178  ast_cond_init(&suspender->cond_suspended, NULL);
3179  ast_cond_init(&suspender->cond_complete, NULL);
3180 
3181  ao2_ref(suspender, +1);
3182  res = ast_sip_push_task(session->serializer, sip_session_suspend_task, suspender);
3183  if (res) {
3184  /* We will just have to hope that the system does not deadlock */
3185  ao2_ref(suspender, -2);
3186  return;
3187  }
3188 
3189  session->suspended = suspender;
3190 
3191  /* Wait for the serializer to get suspended. */
3192  ao2_lock(suspender);
3193  while (!suspender->suspended) {
3194  ast_cond_wait(&suspender->cond_suspended, ao2_object_get_lockaddr(suspender));
3195  }
3196  ao2_unlock(suspender);
3197 
3198  ast_taskprocessor_suspend(session->serializer);
3199 }
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5175
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
#define ast_cond_init(cond, attr)
Definition: lock.h:199
static int sip_session_suspend_task(void *data)
static void sip_session_suspender_dtor(void *vdoomed)
struct controlling the suspension of the session's serializer.
int ast_taskprocessor_is_suspended(struct ast_taskprocessor *tps)
Get the task processor suspend status.
int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
Am I the given taskprocessor's current task.
int ast_taskprocessor_suspend(struct ast_taskprocessor *tps)
Indicate the taskprocessor is suspended.

References ao2_alloc, ao2_lock, ao2_object_get_lockaddr(), ao2_ref, ao2_unlock, ast_assert, ast_cond_init, ast_cond_wait, ast_sip_push_task(), ast_taskprocessor_is_suspended(), ast_taskprocessor_is_task(), ast_taskprocessor_suspend(), ast_sip_session_suspender::cond_complete, ast_sip_session_suspender::cond_suspended, NULL, session, sip_session_suspend_task(), sip_session_suspender_dtor(), and ast_sip_session_suspender::suspended.

Referenced by chan_pjsip_indicate().

◆ ast_sip_session_terminate()

void ast_sip_session_terminate ( struct ast_sip_session session,
int  response 
)

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

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

Definition at line 3452 of file res_pjsip_session.c.

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

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

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

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

Referenced by unload_module().

◆ ast_sip_session_unsuspend()

void ast_sip_session_unsuspend ( struct ast_sip_session session)

Request the session serializer be unsuspended.

Since
12.7.0
Parameters
sessionWhich session to unsuspend the serializer.

Definition at line 3201 of file res_pjsip_session.c.

3202 {
3203  struct ast_sip_session_suspender *suspender = session->suspended;
3204 
3205  if (!suspender) {
3206  /* Nothing to do */
3207  return;
3208  }
3209  session->suspended = NULL;
3210 
3211  /* Signal that the serializer task suspension is now complete. */
3212  ao2_lock(suspender);
3213  suspender->complete = 1;
3214  ast_cond_signal(&suspender->cond_complete);
3215  ao2_unlock(suspender);
3216 
3217  ao2_ref(suspender, -1);
3218 
3219  ast_taskprocessor_unsuspend(session->serializer);
3220 }
#define ast_cond_signal(cond)
Definition: lock.h:201
int ast_taskprocessor_unsuspend(struct ast_taskprocessor *tps)
Indicate the taskprocessor is unsuspended.

References ao2_lock, ao2_ref, ao2_unlock, ast_cond_signal, ast_taskprocessor_unsuspend(), ast_sip_session_suspender::complete, ast_sip_session_suspender::cond_complete, NULL, and session.

Referenced by chan_pjsip_indicate().

◆ check_content_disposition()

static int check_content_disposition ( pjsip_rx_data *  rdata)
static

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

Definition at line 3890 of file res_pjsip_session.c.

3891 {
3892  pjsip_msg_body *body = rdata->msg_info.msg->body;
3893  pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
3894 
3895  if (body && ctype_hdr &&
3898  pjsip_multipart_part *part = pjsip_multipart_get_first_part(body);
3899  while (part != NULL) {
3901  return 1;
3902  }
3903  part = pjsip_multipart_get_next_part(body, part);
3904  }
3905  }
3906  return 0;
3907 }
#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:5304
pjsip_media_type pjsip_media_type_multipart_mixed
Definition: res_pjsip.c:5885
pjsip_media_type pjsip_media_type_multipart_alternative
Definition: res_pjsip.c:5884
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 3866 of file res_pjsip_session.c.

3867 {
3868  pjsip_hdr *hdr = part->hdr.next;
3869  static const pj_str_t str_handling_required = {"handling=required", 16};
3870 
3871  while (hdr != &part->hdr) {
3872  if (hdr->type == PJSIP_H_OTHER) {
3873  pjsip_generic_string_hdr *generic_hdr = (pjsip_generic_string_hdr*)hdr;
3874 
3875  if (!pj_stricmp2(&hdr->name, "Content-Disposition") &&
3876  pj_stristr(&generic_hdr->hvalue, &str_handling_required) &&
3877  !check_sdp_content_type_supported(&part->body->content_type)) {
3878  return 1;
3879  }
3880  }
3881  hdr = hdr->next;
3882  }
3883 
3884  return 0;
3885 }
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 1582 of file res_pjsip_session.c.

1584 {
1585  ao2_ref(session, +1);
1586  if (ast_sip_push_task(session->serializer, cb, session)) {
1587  ao2_ref(session, -1);
1588  }
1589 }

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

4572 {
4573  struct ast_sip_session *session = inv->mod_data[session_module.id];
4574  pjsip_transaction *tsx = e->body.tsx_state.tsx;
4575 
4576  if (tsx->status_code != 503 && tsx->status_code != 408) {
4577  return 0;
4578  }
4579 
4580  if (!ast_sip_failover_request(tsx->last_tx)) {
4581  return 0;
4582  }
4583 
4584  pjsip_inv_uac_restart(inv, PJ_FALSE);
4585  /*
4586  * Bump the ref since it will be on a new transaction and
4587  * we don't want it to go away along with the old transaction.
4588  */
4589  pjsip_tx_data_add_ref(tsx->last_tx);
4590  ast_sip_session_send_request(session, tsx->last_tx);
4591  return 1;
4592 }
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:4908

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

3855 {
3856  pjsip_media_type app_sdp;
3857  pjsip_media_type_init2(&app_sdp, "application", "sdp");
3858 
3859  if (!pjsip_media_type_cmp(content_type, &app_sdp, 0)) {
3860  return 1;
3861  }
3862 
3863  return 0;
3864 }

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 
)
static

Definition at line 5092 of file res_pjsip_session.c.

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

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

2890 {
2891  const struct ast_datastore *datastore1 = obj;
2892  const struct ast_datastore *datastore2 = arg;
2893  const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
2894 
2895  ast_assert(datastore1->uid != NULL);
2896  ast_assert(uid2 != NULL);
2897 
2898  return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
2899 }
@ 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 2879 of file res_pjsip_session.c.

2880 {
2881  const struct ast_datastore *datastore = obj;
2882  const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
2883 
2884  ast_assert(uid != NULL);
2885 
2886  return ast_str_hash(uid);
2887 }
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1235

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

1600 {
1605 
1606  if (!delay) {
1609  SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1610  }
1611 
1612  if (method == DELAYED_METHOD_BYE || queue_head) {
1613  /* Send BYE as early as possible */
1614  AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
1615  } else {
1616  AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
1617  }
1619 }
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
static struct ast_sip_session_delayed_request * delayed_request_alloc(enum delayed_method method, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, struct ast_sip_session_media_state *pending_media_state, struct ast_sip_session_media_state *active_media_state)
ast_sip_session_sdp_creation_cb on_sdp_creation
struct ast_sip_session_media_state * active_media_state
struct ast_sip_session_media_state * pending_media_state
ast_sip_session_response_cb on_response

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

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

◆ delayed_method2str()

static const char* delayed_method2str ( enum delayed_method  method)
static

Definition at line 1310 of file res_pjsip_session.c.

1311 {
1312  const char *str = "<unknown>";
1313 
1314  switch (method) {
1315  case DELAYED_METHOD_INVITE:
1316  str = "INVITE";
1317  break;
1318  case DELAYED_METHOD_UPDATE:
1319  str = "UPDATE";
1320  break;
1321  case DELAYED_METHOD_BYE:
1322  str = "BYE";
1323  break;
1324  }
1325 
1326  return str;
1327 }
const char * str
Definition: app_jack.c:147

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

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

◆ delayed_request_alloc()

static struct ast_sip_session_delayed_request* delayed_request_alloc ( enum delayed_method  method,
ast_sip_session_request_creation_cb  on_request_creation,
ast_sip_session_sdp_creation_cb  on_sdp_creation,
ast_sip_session_response_cb  on_response,
int  generate_new_sdp,
struct ast_sip_session_media_state pending_media_state,
struct ast_sip_session_media_state active_media_state 
)
static

◆ delayed_request_free()

static void delayed_request_free ( struct ast_sip_session_delayed_request delay)
static

◆ does_method_match()

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

Definition at line 4140 of file res_pjsip_session.c.

4141 {
4142  pj_str_t method;
4143 
4144  if (ast_strlen_zero(supplement_method)) {
4145  return PJ_TRUE;
4146  }
4147 
4148  pj_cstr(&method, supplement_method);
4149 
4150  return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
4151 }
static const pjsip_method message_method
Definition: res_pjsip.c:4369

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

◆ generate_session_refresh_sdp()

static pjmedia_sdp_session* generate_session_refresh_sdp ( struct ast_sip_session session)
static

Definition at line 1621 of file res_pjsip_session.c.

1622 {
1623  pjsip_inv_session *inv_session = session->inv_session;
1624  const pjmedia_sdp_session *previous_sdp = NULL;
1626 
1627  if (inv_session->neg) {
1628  if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
1629  pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
1630  } else {
1631  pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
1632  }
1633  }
1634  SCOPE_EXIT_RTN_VALUE(create_local_sdp(inv_session, session, previous_sdp));
1635 }

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

3666 {
3667  pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
3668  pjsip_sip_uri *sip_ruri;
3669  struct ast_features_pickup_config *pickup_cfg;
3670  const char *pickupexten;
3671 
3672  if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
3674  }
3675 
3676  sip_ruri = pjsip_uri_get_uri(ruri);
3677  ast_copy_pj_str(session->exten, &sip_ruri->user, sizeof(session->exten));
3678 
3679  /*
3680  * We may want to match in the dialplan without any user
3681  * options getting in the way.
3682  */
3684 
3685  pickup_cfg = ast_get_chan_features_pickup_config(NULL); /* session->channel doesn't exist yet, using NULL */
3686  if (!pickup_cfg) {
3687  ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",
3689  pickupexten = "";
3690  } else {
3691  pickupexten = ast_strdupa(pickup_cfg->pickupexten);
3692  ao2_ref(pickup_cfg, -1);
3693  }
3694 
3695  if (!strcmp(session->exten, pickupexten) ||
3696  ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
3697  /*
3698  * Save off the INVITE Request-URI in case it is
3699  * needed: CHANNEL(pjsip,request_uri)
3700  */
3701  session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri);
3702 
3703  return SIP_GET_DEST_EXTEN_FOUND;
3704  }
3705 
3706  /*
3707  * Check for partial match via overlap dialling (if enabled)
3708  */
3709  if (session->endpoint->allow_overlap && (
3710  !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
3711  ast_canmatch_extension(NULL, session->endpoint->context, session->exten, 1, NULL))) {
3712  /* Overlap partial match */
3714  }
3715 
3717 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
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:4173
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:4188
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3114
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:5277
Configuration relating to call pickup.

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

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

4482 {
4483  if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
4485  } else {
4486  handle_incoming_response(session, rdata, response_priority);
4487  }
4488 
4489  return 0;
4490 }
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 4594 of file res_pjsip_session.c.

4596 {
4597  pjsip_msg *msg;
4598  ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4599  "request" : "response");
4600 
4601 
4603  msg = rdata->msg_info.msg;
4604  if (msg->type == PJSIP_REQUEST_MSG
4605  && msg->line.req.method.id == PJSIP_ACK_METHOD
4606  && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
4607  pjsip_tx_data *tdata;
4608 
4609  /*
4610  * SDP negotiation failed on an incoming call that delayed
4611  * negotiation and then gave us an invalid SDP answer. We
4612  * need to send a BYE to end the call because of the invalid
4613  * SDP answer.
4614  */
4615  ast_debug(1,
4616  "%s: Ending session due to incomplete SDP negotiation. %s\n",
4618  pjsip_rx_data_get_info(rdata));
4619  if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
4620  && tdata) {
4622  }
4623  }
4624 }
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 4409 of file res_pjsip_session.c.

4410 {
4411  struct ast_sip_session_supplement *supplement;
4412  struct pjsip_request_line req = rdata->msg_info.msg->line.req;
4413  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));
4414 
4415  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4416  if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
4417  if (supplement->incoming_request(session, rdata)) {
4418  break;
4419  }
4420  }
4421  }
4422 
4424 }
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
A supplement to SIP message processing.
int(* incoming_request)(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Called on incoming SIP request This method can indicate a failure in processing in its return....

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

Referenced by handle_incoming(), and new_invite().

◆ handle_incoming_response()

static void handle_incoming_response ( struct ast_sip_session session,
pjsip_rx_data *  rdata,
enum ast_sip_session_response_priority  response_priority 
)
static

Definition at line 4460 of file res_pjsip_session.c.

4462 {
4463  struct ast_sip_session_supplement *supplement;
4464  struct pjsip_status_line status = rdata->msg_info.msg->line.status;
4465  SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4466  status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
4467 
4468  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4469  if (!(supplement->response_priority & response_priority)) {
4470  continue;
4471  }
4472  if (supplement->incoming_response && does_method_match(&rdata->msg_info.cseq->method.name, supplement->method)) {
4473  supplement->incoming_response(session, rdata);
4474  }
4475  }
4476 
4478 }
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 764 of file res_pjsip_session.c.

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

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

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

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

Referenced by session_inv_on_media_update().

◆ handle_negotiated_sdp_session_media()

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

Definition at line 964 of file res_pjsip_session.c.

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

4049 {
4050  RAII_VAR(struct ast_sip_endpoint *, endpoint,
4052  static const pj_str_t identity_str = { "Identity", 8 };
4053  const pj_str_t use_identity_header_str = {
4056  };
4057  pjsip_inv_session *inv_session = NULL;
4058  struct ast_sip_session *session;
4059  struct new_invite invite;
4060  char *req_uri = TRACE_ATLEAST(1) ? ast_alloca(256) : "";
4061  int res = TRACE_ATLEAST(1) ? pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, req_uri, 256) : 0;
4062  SCOPE_ENTER(1, "Request: %s\n", res ? req_uri : "");
4063 
4064  ast_assert(endpoint != NULL);
4065 
4066  if ((endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_VERIFY) &&
4067  !ast_sip_rdata_get_header_value(rdata, identity_str)) {
4068  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
4069  AST_STIR_SHAKEN_RESPONSE_CODE_USE_IDENTITY_HEADER, &use_identity_header_str, NULL, NULL);
4070  ast_debug(3, "No Identity header when we require one\n");
4071  return;
4072  }
4073 
4074  inv_session = pre_session_setup(rdata, endpoint);
4075  if (!inv_session) {
4076  /* pre_session_setup() returns a response on failure */
4077  SCOPE_EXIT_RTN("Failure in pre session setup\n");
4078  }
4079 
4080  /*
4081  * Upon a successful pre_session_setup the associated dialog is returned locked
4082  * and with an added reference. Well actually two references. One added when the
4083  * dialog itself was created, and another added when the pjsip invite session was
4084  * created and the dialog was added to it.
4085  *
4086  * In order to ensure the dialog's, and any of its internal attributes, lifetimes
4087  * we'll hold the lock and maintain the reference throughout the entire new invite
4088  * handling process. See ast_sip_create_dialog_uas_locked for more details but,
4089  * basically we do this to make sure a transport failure does not destroy the dialog
4090  * and/or transaction out from underneath us between pjsip calls. Alternatively, we
4091  * could probably release the lock if we needed to, but then we'd have to re-lock and
4092  * check the dialog and transaction prior to every pjsip call.
4093  *
4094  * That means any off nominal/failure paths in this function must remove the associated
4095  * dialog reference added at dialog creation, and remove the lock. As well the
4096  * referenced pjsip invite session must be "cleaned up", which should also then
4097  * remove its reference to the dialog at that time.
4098  *
4099  * Nominally we'll unlock the dialog, and release the reference when all new invite
4100  * process handling has successfully completed.
4101  */
4102 
4103  session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
4104  if (!session) {
4105  /* Dialog's lock and reference are removed in new_invite_initial_answer */
4106  if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4107  /* Terminate the session if it wasn't done in the answer */
4108  pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
4109  }
4110  SCOPE_EXIT_RTN("Couldn't create session\n");
4111  }
4112  session->call_direction = AST_SIP_SESSION_INCOMING_CALL;
4113 
4114  /*
4115  * The current thread is supposed be the session serializer to prevent
4116  * any initial INVITE retransmissions from trying to setup the same
4117  * call again.
4118  */
4120 
4121  invite.session = session;
4122  invite.rdata = rdata;
4123  new_invite(&invite);
4124 
4125  /*
4126  * The dialog lock and reference added at dialog creation time must be
4127  * maintained throughout the new invite process. Since we're pretty much
4128  * done at this point with things it's safe to go ahead and remove the lock
4129  * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
4130  *
4131  * Note, any future functionality added that does work using the dialog must
4132  * be done before this.
4133  */
4134  pjsip_dlg_dec_lock(inv_session->dlg);
4135 
4136  SCOPE_EXIT("Request: %s Session: %s\n", req_uri, ast_sip_session_get_name(session));
4137  ao2_ref(session, -1);
4138 }
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define TRACE_ATLEAST(level)
Definition: logger.h:627
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.
#define AST_STIR_SHAKEN_RESPONSE_CODE_USE_IDENTITY_HEADER
Definition: res_pjsip.h:68
char * ast_sip_rdata_get_header_value(pjsip_rx_data *rdata, const pj_str_t str)
Get a specific header value from rdata.
Definition: res_pjsip.c:3580
@ AST_SIP_STIR_SHAKEN_VERIFY
Definition: res_pjsip.h:551
#define AST_STIR_SHAKEN_RESPONSE_STR_USE_IDENTITY_HEADER
Definition: res_pjsip.h:76
static int new_invite(struct new_invite *invite)
static pjsip_inv_session * pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
static int new_invite_initial_answer(pjsip_inv_session *inv_session, pjsip_rx_data *rdata, int answer_code, int terminate_code, pj_bool_t notify)
@ AST_SIP_SESSION_INCOMING_CALL
An entity with which Asterisk communicates.
Definition: res_pjsip.h:854
pjsip_rx_data * rdata
INVITE request itself.

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

Referenced by session_on_rx_request().

◆ handle_outgoing_request()

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

Definition at line 4492 of file res_pjsip_session.c.

4493 {
4494  struct ast_sip_session_supplement *supplement;
4495  struct pjsip_request_line req = tdata->msg->line.req;
4496  SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4497  (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4498 
4499  ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4500 
4501  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4502  if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
4503  supplement->outgoing_request(session, tdata);
4504  }
4505  }
4507 }
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 4509 of file res_pjsip_session.c.

4510 {
4511  struct ast_sip_session_supplement *supplement;
4512  struct pjsip_status_line status = tdata->msg->line.status;
4513  pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
4514  SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4515  (int) pj_strlen(&cseq->method.name),
4516  pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
4517  pj_strbuf(&status.reason));
4518 
4519 
4520  if (!cseq) {
4521  SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4523  }
4524 
4525  ast_sip_message_apply_transport(session->endpoint->transport, tdata);
4526 
4527  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4528  if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
4529  supplement->outgoing_response(session, tdata);
4530  }
4531  }
4532 
4534 }
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
Definition: logger.h:917
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().

◆ handle_session_begin()

static void handle_session_begin ( struct ast_sip_session session)
static

Definition at line 4426 of file res_pjsip_session.c.

4427 {
4428  struct ast_sip_session_supplement *iter;
4429 
4430  AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4431  if (iter->session_begin) {
4432  iter->session_begin(session);
4433  }
4434  }
4435 }
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 4437 of file res_pjsip_session.c.

4438 {
4439  struct ast_sip_session_supplement *iter;
4440 
4441  AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4442  if (iter->session_destroy) {
4443  iter->session_destroy(session);
4444  }
4445  }
4446 }
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 4448 of file res_pjsip_session.c.

4449 {
4450  struct ast_sip_session_supplement *iter;
4451 
4452  /* Session is dead. Notify the supplements. */
4453  AST_LIST_TRAVERSE(&session->supplements, iter, next) {
4454  if (iter->session_end) {
4455  iter->session_end(session);
4456  }
4457  }
4458 }
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 4153 of file res_pjsip_session.c.

4154 {
4155  struct ast_sip_session_supplement *supplement;
4156  struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
4157 
4158  if (!session) {
4159  return PJ_FALSE;
4160  }
4161 
4162  AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
4163  if (does_method_match(&method->name, supplement->method)) {
4164  return PJ_TRUE;
4165  }
4166  }
4167  return PJ_FALSE;
4168 }

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

216 {
217  struct ast_sip_session_media_state *media_state;
218 
219  media_state = ast_calloc(1, sizeof(*media_state));
220  if (!media_state) {
221  return NULL;
222  }
223 
224  if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) {
225  ast_free(media_state);
226  return NULL;
227  }
228 
229  if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) {
230  AST_VECTOR_FREE(&media_state->sessions);
231  ast_free(media_state);
232  return NULL;
233  }
234 
235  return media_state;
236 }

References ast_calloc, ast_free, AST_VECTOR_FREE, AST_VECTOR_INIT, NULL, ast_sip_session_media_state::read_callbacks, 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 1538 of file res_pjsip_session.c.

1539 {
1540  struct ast_sip_session *session = vsession;
1541  int res;
1543 
1544  if (session->inv_session->invite_tsx) {
1545  /*
1546  * INVITE transaction still active. Let it send
1547  * the collision re-INVITE when it terminates.
1548  */
1549  ao2_ref(session, -1);
1550  res = 0;
1551  } else {
1552  res = invite_terminated(session);
1553  }
1554 
1556 }
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 1440 of file res_pjsip_session.c.

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

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

Referenced by session_inv_on_tsx_state_changed(), and update_completed().

◆ invite_terminated()

static int invite_terminated ( void *  vsession)
static

Definition at line 1487 of file res_pjsip_session.c.

1488 {
1489  struct ast_sip_session *session = vsession;
1490  struct ast_sip_session_delayed_request *delay;
1491  int found = 0;
1492  int res = 0;
1493  int timer_running;
1495 
1496  /* re-INVITE collision timer running? */
1497  timer_running = pj_timer_entry_running(&session->rescheduled_reinvite);
1498 
1499  AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
1500  switch (delay->method) {
1501  case DELAYED_METHOD_INVITE:
1502  if (!timer_running) {
1503  found = 1;
1504  }
1505  break;
1506  case DELAYED_METHOD_UPDATE:
1507  case DELAYED_METHOD_BYE:
1508  found = 1;
1509  break;
1510  }
1511  if (found) {
1513  ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1514  delayed_method2str(delay->method));
1515  res = send_delayed_request(session, delay);
1516  delayed_request_free(delay);
1517  if (!res) {
1518  break;
1519  }
1520  }
1521  }
1523 
1524  ao2_ref(session, -1);
1526 }

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

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