Add a bunch of options from sip.conf to res_sip.conf
For a complete list of the options added, see the review linked at the bottom of this commit message. (closes issue ASTERISK-21506) reported by Matt Jordan Review: https://reviewboard.asterisk.org/r/2671 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@394759 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
3c86832f9f
commit
c47787feab
|
@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/stasis_endpoints.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/indications.h"
|
||||
|
||||
#include "asterisk/res_sip.h"
|
||||
#include "asterisk/res_sip_session.h"
|
||||
|
@ -601,6 +602,18 @@ static struct ast_channel *gulp_new(struct ast_sip_session *session, int state,
|
|||
ast_channel_named_callgroups_set(chan, session->endpoint->named_callgroups);
|
||||
ast_channel_named_pickupgroups_set(chan, session->endpoint->named_pickupgroups);
|
||||
|
||||
if (!ast_strlen_zero(session->endpoint->language)) {
|
||||
ast_channel_language_set(chan, session->endpoint->language);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(session->endpoint->zone)) {
|
||||
struct ast_tone_zone *zone = ast_get_indication_zone(session->endpoint->zone);
|
||||
if (!zone) {
|
||||
ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", session->endpoint->zone);
|
||||
}
|
||||
ast_channel_zone_set(chan, zone);
|
||||
}
|
||||
|
||||
ast_endpoint_add_channel(session->endpoint->persistent, chan);
|
||||
|
||||
return chan;
|
||||
|
|
|
@ -115,6 +115,10 @@ struct ast_sip_transport {
|
|||
struct ast_sockaddr external_address;
|
||||
/*! Transport state information */
|
||||
struct ast_sip_transport_state *state;
|
||||
/*! QOS DSCP TOS bits */
|
||||
unsigned int tos;
|
||||
/*! QOS COS value */
|
||||
unsigned int cos;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -323,6 +327,26 @@ struct ast_sip_endpoint {
|
|||
AST_STRING_FIELD(external_media_address);
|
||||
/*! Configured voicemail boxes for this endpoint. Used for MWI */
|
||||
AST_STRING_FIELD(mailboxes);
|
||||
/*! Configured RTP engine for this endpoint. */
|
||||
AST_STRING_FIELD(rtp_engine);
|
||||
/*! Configured tone zone for this endpoint. */
|
||||
AST_STRING_FIELD(zone);
|
||||
/*! Configured language for this endpoint. */
|
||||
AST_STRING_FIELD(language);
|
||||
/*! Feature to enact when one-touch recording INFO with Record: On is received */
|
||||
AST_STRING_FIELD(recordonfeature);
|
||||
/*! Feature to enact when one-touch recording INFO with Record: Off is received */
|
||||
AST_STRING_FIELD(recordofffeature);
|
||||
/*! SDP origin username */
|
||||
AST_STRING_FIELD(sdpowner);
|
||||
/*! SDP session name */
|
||||
AST_STRING_FIELD(sdpsession);
|
||||
/*! Default username to place in From header */
|
||||
AST_STRING_FIELD(fromuser);
|
||||
/*! Domain to place in From header */
|
||||
AST_STRING_FIELD(fromdomain);
|
||||
/*! Username to use when sending MWI NOTIFYs to this endpoint */
|
||||
AST_STRING_FIELD(mwi_from);
|
||||
);
|
||||
/*! Identification information for this endpoint */
|
||||
struct ast_party_id id;
|
||||
|
@ -408,6 +432,20 @@ struct ast_sip_endpoint {
|
|||
struct ast_endpoint *persistent;
|
||||
/*! The number of channels at which busy device state is returned */
|
||||
unsigned int devicestate_busy_at;
|
||||
/*! Determines if transfers (using REFER) are allowed by this endpoint */
|
||||
unsigned int allowtransfer;
|
||||
/*! DSCP TOS bits for audio streams */
|
||||
unsigned int tos_audio;
|
||||
/*! Priority for audio streams */
|
||||
unsigned int cos_audio;
|
||||
/*! DSCP TOS bits for video streams */
|
||||
unsigned int tos_video;
|
||||
/*! Priority for video streams */
|
||||
unsigned int cos_video;
|
||||
/*! Indicates if endpoint is allowed to initiate subscriptions */
|
||||
unsigned int allowsubscribe;
|
||||
/*! The minimum allowed expiration for subscriptions from endpoint */
|
||||
unsigned int subminexpiry;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -1057,13 +1095,15 @@ struct ast_sip_body {
|
|||
* \param endpoint Optional. If specified, the request will be created out-of-dialog
|
||||
* to the endpoint.
|
||||
* \param uri Optional. If specified, the request will be sent to this URI rather
|
||||
* this value.
|
||||
* than one configured for the endpoint.
|
||||
* \param[out] tdata The newly-created request
|
||||
* \retval 0 Success
|
||||
* \retval -1 Failure
|
||||
*/
|
||||
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
|
||||
struct ast_sip_endpoint *endpoint, const char *uri, pjsip_tx_data **tdata);
|
||||
struct ast_sip_endpoint *endpoint, const char *uri,
|
||||
pjsip_tx_data **tdata);
|
||||
|
||||
/*!
|
||||
* \brief General purpose method for sending a SIP request
|
||||
|
@ -1308,4 +1348,12 @@ void ast_sip_report_auth_success(struct ast_sip_endpoint *endpoint, pjsip_rx_dat
|
|||
*/
|
||||
void ast_sip_report_auth_challenge_sent(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata);
|
||||
|
||||
void ast_sip_initialize_global_headers(void);
|
||||
void ast_sip_destroy_global_headers(void);
|
||||
|
||||
int ast_sip_add_global_request_header(const char *name, const char *value, int replace);
|
||||
int ast_sip_add_global_response_header(const char *name, const char *value, int replace);
|
||||
|
||||
int ast_sip_initialize_sorcery_global(struct ast_sorcery *sorcery);
|
||||
|
||||
#endif /* _RES_SIP_H */
|
||||
|
|
183
res/res_sip.c
183
res/res_sip.c
|
@ -386,6 +386,96 @@
|
|||
Gulp channel driver will return busy as the device state instead of in use.
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="tonezone">
|
||||
<synopsis>Set which country's indications to use for channels created for this endpoint.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="language">
|
||||
<synopsis>Set the default language to use for channels created for this endpoint.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="one_touch_recording" default="no">
|
||||
<synopsis>Determines whether one-touch recording is allowed for this endpoint.</synopsis>
|
||||
<see-also>
|
||||
<ref type="configOption">recordonfeature</ref>
|
||||
<ref type="configOption">recordofffeature</ref>
|
||||
</see-also>
|
||||
</configOption>
|
||||
<configOption name="recordonfeature" default="automixmon">
|
||||
<synopsis>The feature to enact when one-touch recording is turned on.</synopsis>
|
||||
<description>
|
||||
<para>When an INFO request for one-touch recording arrives with a Record header set to "on", this
|
||||
feature will be enabled for the channel. The feature designated here can be any built-in
|
||||
or dynamic feature defined in features.conf.</para>
|
||||
<note><para>This setting has no effect if the endpoint's one_touch_recording option is disabled</para></note>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="configOption">one_touch_recording</ref>
|
||||
<ref type="configOption">recordofffeature</ref>
|
||||
</see-also>
|
||||
</configOption>
|
||||
<configOption name="recordofffeature" default="automixmon">
|
||||
<synopsis>The feature to enact when one-touch recording is turned off.</synopsis>
|
||||
<description>
|
||||
<para>When an INFO request for one-touch recording arrives with a Record header set to "off", this
|
||||
feature will be enabled for the channel. The feature designated here can be any built-in
|
||||
or dynamic feature defined in features.conf.</para>
|
||||
<note><para>This setting has no effect if the endpoint's one_touch_recording option is disabled</para></note>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="configOption">one_touch_recording</ref>
|
||||
<ref type="configOption">recordonfeature</ref>
|
||||
</see-also>
|
||||
</configOption>
|
||||
<configOption name="rtpengine" default="asterisk">
|
||||
<synopsis>Name of the RTP engine to use for channels created for this endpoint</synopsis>
|
||||
</configOption>
|
||||
<configOption name="allowtransfer" default="yes">
|
||||
<synopsis>Determines whether SIP REFER transfers are allowed for this endpoint</synopsis>
|
||||
</configOption>
|
||||
<configOption name="sdpowner" default="-">
|
||||
<synopsis>String placed as the username portion of an SDP origin (o=) line.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="sdpsession" default="Asterisk">
|
||||
<synopsis>String used for the SDP session (s=) line.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="tos_audio">
|
||||
<synopsis>DSCP TOS bits for audio streams</synopsis>
|
||||
<description><para>
|
||||
See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="tos_video">
|
||||
<synopsis>DSCP TOS bits for video streams</synopsis>
|
||||
<description><para>
|
||||
See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="cos_audio">
|
||||
<synopsis>Priority for audio streams</synopsis>
|
||||
<description><para>
|
||||
See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="cos_video">
|
||||
<synopsis>Priority for video streams</synopsis>
|
||||
<description><para>
|
||||
See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for more information about QoS settings
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="allowsubscribe" default="no">
|
||||
<synopsis>Determines if endpoint is allowed to initiate subscriptions with Asterisk.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="subminexpiry" default="60">
|
||||
<synopsis>The minimum allowed expiry time for subscriptions initiated by the endpoint.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="fromuser">
|
||||
<synopsis>Username to use in From header for requests to this endpoint.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="mwifromuser">
|
||||
<synopsis>Username to use in From header for unsolicited MWI NOTIFYs to this endpoint.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="fromdomain">
|
||||
<synopsis>Domain to user in From header for requests to this endpoint.</synopsis>
|
||||
</configOption>
|
||||
</configObject>
|
||||
<configObject name="auth">
|
||||
<synopsis>Authentication type</synopsis>
|
||||
|
@ -674,6 +764,48 @@
|
|||
</para></description>
|
||||
</configOption>
|
||||
</configObject>
|
||||
<configObject name="system">
|
||||
<synopsis>Options that apply to the SIP stack as well as other system-wide settings</synopsis>
|
||||
<description><para>
|
||||
The settings in this section are global. In addition to being global, the values will
|
||||
not be re-evaluated when a reload is performed. This is because the values must be set
|
||||
before the SIP stack is initialized. The only way to reset these values is to either
|
||||
restart Asterisk, or unload res_sip.so and then load it again.
|
||||
</para></description>
|
||||
<configOption name="timert1" default="500">
|
||||
<synopsis>Set transaction timer T1 value (milliseconds).</synopsis>
|
||||
<description><para>
|
||||
Timer T1 is the base for determining how long to wait before retransmitting
|
||||
requests that receive no response when using an unreliable transport (e.g. UDP).
|
||||
For more information on this timer, see RFC 3261, Section 17.1.1.1.
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="timerb" default="32000">
|
||||
<synopsis>Set transaction timer B value (milliseconds).</synopsis>
|
||||
<description><para>
|
||||
Timer B determines the maximum amount of time to wait after sending an INVITE
|
||||
request before terminating the transaction. It is recommended that this be set
|
||||
to 64 * Timer T1, but it may be set higher if desired. For more information on
|
||||
this timer, see RFC 3261, Section 17.1.1.1.
|
||||
</para></description>
|
||||
</configOption>
|
||||
<configOption name="compactheaders" default="no">
|
||||
<synopsis>Use the short forms of common SIP header names.</synopsis>
|
||||
</configOption>
|
||||
</configObject>
|
||||
<configObject name="global">
|
||||
<synopsis>Options that apply globally to all SIP communications</synopsis>
|
||||
<description><para>
|
||||
The settings in this section are global. Unlike options in the <literal>system</literal>
|
||||
section, these options can be refreshed by performing a reload.
|
||||
</para></description>
|
||||
<configOption name="maxforwards" default="70">
|
||||
<synopsis>Value used in Max-Forwards header for SIP requests.</synopsis>
|
||||
</configOption>
|
||||
<configOption name="useragent" default="Asterisk <Asterisk Version>">
|
||||
<synopsis>Value used in User-Agent header for SIP requests and Server header for SIP responses.</synopsis>
|
||||
</configOption>
|
||||
</configObject>
|
||||
</configFile>
|
||||
</configInfo>
|
||||
***/
|
||||
|
@ -865,7 +997,7 @@ pjsip_endpoint *ast_sip_get_pjsip_endpoint(void)
|
|||
return ast_pjsip_endpoint;
|
||||
}
|
||||
|
||||
static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
|
||||
static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const char *domain, const pj_str_t *target, pjsip_tpselector *selector)
|
||||
{
|
||||
pj_str_t tmp, local_addr;
|
||||
pjsip_uri *uri;
|
||||
|
@ -874,7 +1006,7 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u
|
|||
int local_port;
|
||||
char uuid_str[AST_UUID_STR_LEN];
|
||||
|
||||
if (!user) {
|
||||
if (ast_strlen_zero(user)) {
|
||||
RAII_VAR(struct ast_uuid *, uuid, ast_uuid_generate(), ast_free_ptr);
|
||||
if (!uuid) {
|
||||
return -1;
|
||||
|
@ -910,6 +1042,18 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u
|
|||
type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(domain)) {
|
||||
from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
|
||||
from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
|
||||
"<%s:%s@%s%s%s>",
|
||||
(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
|
||||
user,
|
||||
domain,
|
||||
(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
|
||||
(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the local bound address for the transport that will be used when communicating with the provided URI */
|
||||
if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
|
||||
&local_addr, &local_port) != PJ_SUCCESS) {
|
||||
|
@ -1000,7 +1144,7 @@ pjsip_dialog *ast_sip_create_dialog(const struct ast_sip_endpoint *endpoint, con
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (sip_dialog_create_from(dlg->pool, &local_uri, NULL, &remote_uri, &selector)) {
|
||||
if (sip_dialog_create_from(dlg->pool, &local_uri, endpoint->fromuser, endpoint->fromdomain, &remote_uri, &selector)) {
|
||||
pjsip_dlg_terminate(dlg);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1127,7 +1271,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (sip_dialog_create_from(pool, &from, NULL, &remote_uri, &selector)) {
|
||||
if (sip_dialog_create_from(pool, &from, endpoint ? endpoint->fromuser : NULL,
|
||||
endpoint ? endpoint->fromdomain : NULL, &remote_uri, &selector)) {
|
||||
ast_log(LOG_ERROR, "Unable to create From header for %.*s request to endpoint %s\n",
|
||||
(int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint));
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
|
@ -1150,7 +1295,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
|
|||
}
|
||||
|
||||
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
|
||||
struct ast_sip_endpoint *endpoint, const char *uri, pjsip_tx_data **tdata)
|
||||
struct ast_sip_endpoint *endpoint, const char *uri,
|
||||
pjsip_tx_data **tdata)
|
||||
{
|
||||
const pjsip_method *pmethod = get_pjsip_method(method);
|
||||
|
||||
|
@ -1443,6 +1589,18 @@ int ast_sip_thread_is_servant(void)
|
|||
return *servant_id == SIP_SERVANT_ID;
|
||||
}
|
||||
|
||||
static void remove_request_headers(pjsip_endpoint *endpt)
|
||||
{
|
||||
const pjsip_hdr *request_headers = pjsip_endpt_get_request_headers(endpt);
|
||||
pjsip_hdr *iter = request_headers->next;
|
||||
|
||||
while (iter != request_headers) {
|
||||
pjsip_hdr *to_erase = iter;
|
||||
iter = iter->next;
|
||||
pj_list_erase(to_erase);
|
||||
}
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
/* The third parameter is just copied from
|
||||
|
@ -1480,12 +1638,23 @@ static int load_module(void)
|
|||
ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* PJSIP will automatically try to add a Max-Forwards header. Since we want to control that,
|
||||
* we need to stop PJSIP from doing it automatically
|
||||
*/
|
||||
remove_request_headers(ast_pjsip_endpoint);
|
||||
|
||||
memory_pool = pj_pool_create(&caching_pool.factory, "SIP", 1024, 1024, NULL);
|
||||
if (!memory_pool) {
|
||||
ast_log(LOG_ERROR, "Failed to create memory pool for SIP. Aborting load\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ast_sip_initialize_system()) {
|
||||
ast_log(LOG_ERROR, "Failed to initialize SIP system configuration. Aborting load\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pjsip_tsx_layer_init_module(ast_pjsip_endpoint);
|
||||
pjsip_ua_init_module(ast_pjsip_endpoint, NULL);
|
||||
|
||||
|
@ -1497,6 +1666,8 @@ static int load_module(void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
ast_sip_initialize_global_headers();
|
||||
|
||||
if (ast_res_sip_initialize_configuration()) {
|
||||
ast_log(LOG_ERROR, "Failed to initialize SIP configuration. Aborting load\n");
|
||||
goto error;
|
||||
|
@ -1521,6 +1692,7 @@ return AST_MODULE_LOAD_SUCCESS;
|
|||
error:
|
||||
ast_sip_destroy_distributor();
|
||||
ast_res_sip_destroy_configuration();
|
||||
ast_sip_destroy_global_headers();
|
||||
if (monitor_thread) {
|
||||
stop_monitor_thread();
|
||||
}
|
||||
|
@ -1564,6 +1736,7 @@ static int unload_module(void)
|
|||
{
|
||||
ast_sip_destroy_distributor();
|
||||
ast_res_sip_destroy_configuration();
|
||||
ast_sip_destroy_global_headers();
|
||||
if (monitor_thread) {
|
||||
stop_monitor_thread();
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@
|
|||
LINKER_SYMBOL_PREFIXast_sip_report_auth_failed_challenge_response;
|
||||
LINKER_SYMBOL_PREFIXast_sip_report_auth_success;
|
||||
LINKER_SYMBOL_PREFIXast_sip_report_auth_challenge_sent;
|
||||
LINKER_SYMBOL_PREFIXast_sip_initialize_global_headers;
|
||||
LINKER_SYMBOL_PREFIXast_sip_destroy_global_headers;
|
||||
LINKER_SYMBOL_PREFIXast_sip_add_global_request_header;
|
||||
LINKER_SYMBOL_PREFIXast_sip_add_global_response_header;
|
||||
LINKER_SYMBOL_PREFIXast_sip_initialize_sorcery_global;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* Mark Michelson <mmichelson@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <pjsip.h>
|
||||
#include <pjlib.h>
|
||||
|
||||
#include "asterisk/res_sip.h"
|
||||
#include "asterisk/sorcery.h"
|
||||
#include "asterisk/ast_version.h"
|
||||
|
||||
#define DEFAULT_MAX_FORWARDS 70
|
||||
#define DEFAULT_USERAGENT_PREFIX "Asterisk PBX"
|
||||
|
||||
static char default_useragent[128];
|
||||
|
||||
struct global_config {
|
||||
SORCERY_OBJECT(details);
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(useragent);
|
||||
);
|
||||
/* Value to put in Max-Forwards header */
|
||||
unsigned int max_forwards;
|
||||
};
|
||||
|
||||
static void global_destructor(void *obj)
|
||||
{
|
||||
struct global_config *cfg = obj;
|
||||
|
||||
ast_string_field_free_memory(cfg);
|
||||
}
|
||||
|
||||
static void *global_alloc(const char *name)
|
||||
{
|
||||
struct global_config *cfg = ast_sorcery_generic_alloc(sizeof(*cfg), global_destructor);
|
||||
|
||||
if (!cfg || ast_string_field_init(cfg, 64)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static int global_apply(const struct ast_sorcery *sorcery, void *obj)
|
||||
{
|
||||
struct global_config *cfg = obj;
|
||||
char max_forwards[10];
|
||||
|
||||
snprintf(max_forwards, sizeof(max_forwards), "%u", cfg->max_forwards);
|
||||
|
||||
ast_sip_add_global_request_header("Max-Forwards", max_forwards, 1);
|
||||
ast_sip_add_global_request_header("User-Agent", cfg->useragent, 1);
|
||||
ast_sip_add_global_response_header("Server", cfg->useragent, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_sip_initialize_sorcery_global(struct ast_sorcery *sorcery)
|
||||
{
|
||||
snprintf(default_useragent, sizeof(default_useragent), "%s %s", DEFAULT_USERAGENT_PREFIX, ast_get_version());
|
||||
|
||||
ast_sorcery_apply_default(sorcery, "global", "config", "res_sip.conf,criteria=type=global");
|
||||
|
||||
if (ast_sorcery_object_register(sorcery, "global", global_alloc, NULL, global_apply)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_sorcery_object_field_register(sorcery, "global", "type", "", OPT_NOOP_T, 0, 0);
|
||||
ast_sorcery_object_field_register(sorcery, "global", "maxforwards", __stringify(DEFAULT_MAX_FORWARDS),
|
||||
OPT_UINT_T, 0, FLDSET(struct global_config, max_forwards));
|
||||
ast_sorcery_object_field_register(sorcery, "global", "useragent", default_useragent,
|
||||
OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, useragent));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* Mark Michelson <mmichelson@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <pjsip.h>
|
||||
#include <pjlib.h>
|
||||
|
||||
#include "asterisk/res_sip.h"
|
||||
#include "asterisk/sorcery.h"
|
||||
#include "include/res_sip_private.h"
|
||||
|
||||
#define TIMER_T1_MIN 100
|
||||
#define DEFAULT_TIMER_T1 500
|
||||
#define DEFAULT_TIMER_B 32000
|
||||
|
||||
struct system_config {
|
||||
SORCERY_OBJECT(details);
|
||||
/*! Transaction Timer T1 value */
|
||||
unsigned int timert1;
|
||||
/*! Transaction Timer B value */
|
||||
unsigned int timerb;
|
||||
/*! Should we use short forms for headers? */
|
||||
unsigned int compactheaders;
|
||||
};
|
||||
|
||||
static struct ast_sorcery *system_sorcery;
|
||||
|
||||
static void *system_alloc(const char *name)
|
||||
{
|
||||
struct system_config *system = ast_sorcery_generic_alloc(sizeof(*system), NULL);
|
||||
|
||||
if (!system) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return system;
|
||||
}
|
||||
|
||||
static int system_apply(const struct ast_sorcery *system_sorcery, void *obj)
|
||||
{
|
||||
struct system_config *system = obj;
|
||||
int min_timerb;
|
||||
|
||||
if (system->timert1 < TIMER_T1_MIN) {
|
||||
ast_log(LOG_WARNING, "Timer T1 setting is too low. Setting to %d\n", TIMER_T1_MIN);
|
||||
system->timert1 = TIMER_T1_MIN;
|
||||
}
|
||||
|
||||
min_timerb = 64 * system->timert1;
|
||||
|
||||
if (system->timerb < min_timerb) {
|
||||
ast_log(LOG_WARNING, "Timer B setting is too low. Setting to %d\n", min_timerb);
|
||||
system->timerb = min_timerb;
|
||||
}
|
||||
|
||||
pjsip_cfg()->tsx.t1 = system->timert1;
|
||||
pjsip_cfg()->tsx.td = system->timerb;
|
||||
|
||||
if (system->compactheaders) {
|
||||
extern pj_bool_t pjsip_use_compact_form;
|
||||
pjsip_use_compact_form = PJ_TRUE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_sip_initialize_system(void)
|
||||
{
|
||||
system_sorcery = ast_sorcery_open();
|
||||
if (!system_sorcery) {
|
||||
ast_log(LOG_ERROR, "Failed to open SIP system sorcery\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_sorcery_apply_config(system_sorcery, "res_sip");
|
||||
|
||||
ast_sorcery_apply_default(system_sorcery, "system", "config", "res_sip.conf,criteria=type=system");
|
||||
|
||||
if (ast_sorcery_object_register(system_sorcery, "system", system_alloc, NULL, system_apply)) {
|
||||
ast_sorcery_unref(system_sorcery);
|
||||
system_sorcery = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_sorcery_object_field_register(system_sorcery, "system", "type", "", OPT_NOOP_T, 0, 0);
|
||||
ast_sorcery_object_field_register(system_sorcery, "system", "timert1", __stringify(DEFAULT_TIMER_T1),
|
||||
OPT_UINT_T, 0, FLDSET(struct system_config, timert1));
|
||||
ast_sorcery_object_field_register(system_sorcery, "system", "timerb", __stringify(DEFAULT_TIMER_B),
|
||||
OPT_UINT_T, 0, FLDSET(struct system_config, timerb));
|
||||
ast_sorcery_object_field_register(system_sorcery, "system", "compactheaders", "no",
|
||||
OPT_BOOL_T, 1, FLDSET(struct system_config, compactheaders));
|
||||
|
||||
ast_sorcery_load(system_sorcery);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -79,6 +79,18 @@ static void *transport_alloc(const char *name)
|
|||
return transport;
|
||||
}
|
||||
|
||||
static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos)
|
||||
{
|
||||
if (transport->tos) {
|
||||
qos->flags |= PJ_QOS_PARAM_HAS_DSCP;
|
||||
qos->dscp_val = transport->tos;
|
||||
}
|
||||
if (transport->cos) {
|
||||
qos->flags |= PJ_QOS_PARAM_HAS_SO_PRIO;
|
||||
qos->so_prio = transport->cos;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Apply handler for transports */
|
||||
static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
|
||||
{
|
||||
|
@ -135,12 +147,23 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
|
|||
} else if (transport->host.addr.sa_family == pj_AF_INET6()) {
|
||||
res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport);
|
||||
}
|
||||
|
||||
if (res == PJ_SUCCESS && (transport->tos || transport->cos)) {
|
||||
pj_sock_t sock;
|
||||
pj_qos_params qos_params;
|
||||
|
||||
sock = pjsip_udp_transport_get_socket(transport->state->transport);
|
||||
pj_sock_get_qos_params(sock, &qos_params);
|
||||
set_qos(transport, &qos_params);
|
||||
pj_sock_set_qos_params(sock, &qos_params);
|
||||
}
|
||||
} else if (transport->type == AST_TRANSPORT_TCP) {
|
||||
pjsip_tcp_transport_cfg cfg;
|
||||
|
||||
pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family);
|
||||
cfg.bind_addr = transport->host;
|
||||
cfg.async_cnt = transport->async_operations;
|
||||
set_qos(transport, &cfg.qos_params);
|
||||
|
||||
res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory);
|
||||
} else if (transport->type == AST_TRANSPORT_TLS) {
|
||||
|
@ -148,9 +171,13 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
|
|||
transport->tls.cert_file = pj_str((char*)transport->cert_file);
|
||||
transport->tls.privkey_file = pj_str((char*)transport->privkey_file);
|
||||
transport->tls.password = pj_str((char*)transport->password);
|
||||
set_qos(transport, &transport->tls.qos_params);
|
||||
|
||||
res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory);
|
||||
} else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
|
||||
if (transport->cos || transport->tos) {
|
||||
ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
|
||||
}
|
||||
res = PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -304,6 +331,8 @@ int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery)
|
|||
ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(sorcery, "transport", "localnet", "", transport_localnet_handler, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register(sorcery, "transport", "tos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, tos));
|
||||
ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -55,4 +55,20 @@ int ast_res_sip_init_contact_transports(void);
|
|||
*/
|
||||
int ast_sip_initialize_outbound_authentication(void);
|
||||
|
||||
/*!
|
||||
* \brief Initialize system configuration
|
||||
*
|
||||
* \retval 0 Success
|
||||
* \retval non-zero Failure
|
||||
*/
|
||||
int ast_sip_initialize_system(void);
|
||||
|
||||
/*!
|
||||
* \brief Initialize global configuration
|
||||
*
|
||||
* \retval 0 Success
|
||||
* \retval non-zero Failure
|
||||
*/
|
||||
int ast_sip_initialize_global(void);
|
||||
|
||||
#endif /* RES_SIP_PRIVATE_H_ */
|
||||
|
|
|
@ -658,6 +658,24 @@ int ast_res_sip_initialize_configuration(void)
|
|||
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "namedcallgroup", "", named_groups_handler, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "namedpickupgroup", "", named_groups_handler, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "devicestate_busy_at", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, devicestate_busy_at));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtpengine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, rtp_engine));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tonezone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "language", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, language));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "recordonfeature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, recordonfeature));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "recordofffeature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, recordofffeature));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allowtransfer", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowtransfer));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdpowner", "-", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, sdpowner));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdpsession", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, sdpsession));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, tos_audio));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, tos_video));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, cos_audio));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, cos_video));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allowsubscribe", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowsubscribe));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subminexpiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subminexpiry));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subminexpirey", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subminexpiry));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fromuser", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fromdomain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
|
||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwifromuser", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mwi_from));
|
||||
|
||||
if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
|
||||
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
|
||||
|
@ -696,6 +714,13 @@ int ast_res_sip_initialize_configuration(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (ast_sip_initialize_sorcery_global(sip_sorcery)) {
|
||||
ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
|
||||
ast_sorcery_unref(sip_sorcery);
|
||||
sip_sorcery = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_sorcery_load(sip_sorcery);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* Mark Michelson <mmichelson@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <pjsip.h>
|
||||
#include <pjlib.h>
|
||||
|
||||
#include "asterisk/res_sip.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
|
||||
static pj_status_t add_request_headers(pjsip_tx_data *tdata);
|
||||
static pj_status_t add_response_headers(pjsip_tx_data *tdata);
|
||||
|
||||
/*!
|
||||
* \brief Indicator we've already handled a specific request/response
|
||||
*
|
||||
* PJSIP tends to reuse requests and responses. If we already have added
|
||||
* headers to a request or response, we mark the message with this value
|
||||
* so that we know not to re-add the headers again.
|
||||
*/
|
||||
static unsigned int handled_id = 0xB000B1E5;
|
||||
|
||||
static pjsip_module global_header_mod = {
|
||||
.name = {"Global headers", 13},
|
||||
.priority = PJSIP_MOD_PRIORITY_APPLICATION,
|
||||
.on_tx_request = add_request_headers,
|
||||
.on_tx_response = add_response_headers,
|
||||
};
|
||||
|
||||
struct header {
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(name);
|
||||
AST_STRING_FIELD(value);
|
||||
);
|
||||
AST_LIST_ENTRY(header) next;
|
||||
};
|
||||
|
||||
static struct header *alloc_header(const char *name, const char *value)
|
||||
{
|
||||
struct header *alloc;
|
||||
|
||||
alloc = ast_calloc_with_stringfields(1, struct header, 32);
|
||||
|
||||
if (!alloc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_string_field_set(alloc, name, name);
|
||||
ast_string_field_set(alloc, value, value);
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
static void destroy_header(struct header *to_destroy)
|
||||
{
|
||||
ast_string_field_free_memory(to_destroy);
|
||||
ast_free(to_destroy);
|
||||
}
|
||||
|
||||
AST_RWLIST_HEAD(header_list, header);
|
||||
|
||||
static struct header_list request_headers;
|
||||
static struct header_list response_headers;
|
||||
|
||||
static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *tdata)
|
||||
{
|
||||
struct header *iter;
|
||||
SCOPED_LOCK(lock, headers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
|
||||
if (tdata->mod_data[global_header_mod.id] == &handled_id) {
|
||||
return;
|
||||
}
|
||||
AST_LIST_TRAVERSE(headers, iter, next) {
|
||||
ast_sip_add_header(tdata, iter->name, iter->value);
|
||||
};
|
||||
tdata->mod_data[global_header_mod.id] = &handled_id;
|
||||
}
|
||||
|
||||
static pj_status_t add_request_headers(pjsip_tx_data *tdata)
|
||||
{
|
||||
add_headers_to_message(&request_headers, tdata);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static pj_status_t add_response_headers(pjsip_tx_data *tdata)
|
||||
{
|
||||
add_headers_to_message(&response_headers, tdata);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static void remove_header(struct header_list *headers, const char *to_remove)
|
||||
{
|
||||
struct header *iter;
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(headers, iter, next) {
|
||||
if (!strcasecmp(iter->name, to_remove)) {
|
||||
AST_LIST_REMOVE_CURRENT(next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
}
|
||||
|
||||
static int add_header(struct header_list *headers, const char *name, const char *value, int replace)
|
||||
{
|
||||
struct header *to_add;
|
||||
|
||||
to_add = alloc_header(name, value);
|
||||
if (!to_add) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_RWLIST_WRLOCK(headers);
|
||||
if (replace) {
|
||||
remove_header(headers, name);
|
||||
}
|
||||
AST_LIST_INSERT_TAIL(headers, to_add, next);
|
||||
AST_RWLIST_UNLOCK(headers);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_sip_add_global_request_header(const char *name, const char *value, int replace)
|
||||
{
|
||||
return add_header(&request_headers, name, value, replace);
|
||||
}
|
||||
|
||||
int ast_sip_add_global_response_header(const char *name, const char *value, int replace)
|
||||
{
|
||||
return add_header(&response_headers, name, value, replace);
|
||||
}
|
||||
|
||||
void ast_sip_initialize_global_headers(void)
|
||||
{
|
||||
AST_RWLIST_HEAD_INIT(&request_headers);
|
||||
AST_RWLIST_HEAD_INIT(&response_headers);
|
||||
|
||||
ast_sip_register_service(&global_header_mod);
|
||||
}
|
||||
|
||||
static void destroy_headers(struct header_list *headers)
|
||||
{
|
||||
struct header *iter;
|
||||
|
||||
while ((iter = AST_RWLIST_REMOVE_HEAD(headers, next))) {
|
||||
destroy_header(iter);
|
||||
}
|
||||
AST_RWLIST_HEAD_DESTROY(headers);
|
||||
}
|
||||
|
||||
void ast_sip_destroy_global_headers(void)
|
||||
{
|
||||
destroy_headers(&request_headers);
|
||||
destroy_headers(&response_headers);
|
||||
}
|
|
@ -398,7 +398,9 @@ static void modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const st
|
|||
pj_strdup2(pool, &id_name_addr->display, id->name.str);
|
||||
}
|
||||
|
||||
pj_strdup2(pool, &id_uri->user, id->number.str);
|
||||
if (id->number.valid) {
|
||||
pj_strdup2(pool, &id_uri->user, id->number.str);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -281,6 +281,14 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(endpoint->mwi_from)) {
|
||||
pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);
|
||||
pjsip_name_addr *from_name_addr = (pjsip_name_addr *) from->uri;
|
||||
pjsip_sip_uri *from_uri = pjsip_uri_get_uri(from_name_addr->uri);
|
||||
|
||||
pj_strdup2(tdata->pool, &from_uri->user, endpoint->mwi_from);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case PJSIP_EVSUB_STATE_ACTIVE:
|
||||
state_name = "active";
|
||||
|
|
|
@ -51,12 +51,22 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
|
|||
pjsip_generic_string_hdr *record;
|
||||
int feature_res;
|
||||
char feature_code[AST_FEATURE_MAX_LEN];
|
||||
const char *feature;
|
||||
char *digit;
|
||||
|
||||
record = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &rec_str, NULL);
|
||||
|
||||
/* If we don't have Record header, we have nothing to do */
|
||||
if (!record || (pj_stricmp2(&record->hvalue, "on") && pj_stricmp2(&record->hvalue, "off"))) {
|
||||
if (!record) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pj_stricmp2(&record->hvalue, "on")) {
|
||||
feature = session->endpoint->recordonfeature;
|
||||
} else if (!pj_stricmp2(&record->hvalue, "off")) {
|
||||
feature = session->endpoint->recordofffeature;
|
||||
} else {
|
||||
/* Don't send response because another module may handle this */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -66,13 +76,13 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
|
|||
}
|
||||
|
||||
/* Is this endpoint configured with One Touch Recording? */
|
||||
if (!session->endpoint->one_touch_recording) {
|
||||
if (!session->endpoint->one_touch_recording || ast_strlen_zero(feature)) {
|
||||
send_response(session, 403, rdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_channel_lock(session->channel);
|
||||
feature_res = ast_get_builtin_feature(session->channel, "automixmon", feature_code, sizeof(feature_code));
|
||||
feature_res = ast_get_feature(session->channel, feature, feature_code, sizeof(feature_code));
|
||||
ast_channel_unlock(session->channel);
|
||||
|
||||
if (feature_res || ast_strlen_zero(feature_code)) {
|
||||
|
|
|
@ -616,6 +616,7 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
|
|||
char accept[AST_SIP_MAX_ACCEPT][64];
|
||||
pjsip_accept_hdr *accept_header;
|
||||
pjsip_event_hdr *event_header;
|
||||
pjsip_expires_hdr *expires_header;
|
||||
struct ast_sip_subscription_handler *handler;
|
||||
RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
|
||||
struct ast_sip_subscription *sub;
|
||||
|
@ -624,6 +625,21 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
|
|||
endpoint = ast_pjsip_rdata_get_endpoint(rdata);
|
||||
ast_assert(endpoint != NULL);
|
||||
|
||||
if (!endpoint->allowsubscribe) {
|
||||
ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
|
||||
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
|
||||
|
||||
if (expires_header && expires_header->ivalue < endpoint->subminexpiry) {
|
||||
ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %d\n",
|
||||
expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subminexpiry);
|
||||
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
|
||||
if (!event_header) {
|
||||
ast_log(LOG_WARNING, "Incoming SUBSCRIBE request with no Event header\n");
|
||||
|
|
|
@ -732,6 +732,13 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
|
|||
pjsip_param *replaces;
|
||||
int response;
|
||||
|
||||
if (!session->endpoint->allowtransfer) {
|
||||
pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
|
||||
ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
|
||||
ast_sorcery_object_get_id(session->endpoint));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A Refer-To header is required */
|
||||
if (!(refer_to = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL))) {
|
||||
pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
|
||||
|
|
|
@ -108,7 +108,8 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
|
|||
{
|
||||
struct ast_rtp_engine_ice *ice;
|
||||
|
||||
if (!(session_media->rtp = ast_rtp_instance_new("asterisk", sched, ipv6 ? &address_ipv6 : &address_ipv4, NULL))) {
|
||||
if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->rtp_engine, sched, ipv6 ? &address_ipv6 : &address_ipv4, NULL))) {
|
||||
ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", session->endpoint->rtp_engine);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -132,6 +133,16 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
|
|||
ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
|
||||
}
|
||||
|
||||
if (!strcmp(session_media->stream_type, STR_AUDIO) &&
|
||||
(session->endpoint->tos_audio || session->endpoint->cos_video)) {
|
||||
ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->tos_audio,
|
||||
session->endpoint->cos_audio, "SIP RTP Audio");
|
||||
} else if (!strcmp(session_media->stream_type, STR_VIDEO) &&
|
||||
(session->endpoint->tos_video || session->endpoint->cos_video)) {
|
||||
ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->tos_video,
|
||||
session->endpoint->cos_video, "SIP RTP Video");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1684,7 +1684,6 @@ static int add_sdp_streams(void *obj, void *arg, void *data, int flags)
|
|||
static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
|
||||
{
|
||||
RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup);
|
||||
static const pj_str_t STR_ASTERISK = { "Asterisk", 8 };
|
||||
static const pj_str_t STR_IN = { "IN", 2 };
|
||||
static const pj_str_t STR_IP4 = { "IP4", 3 };
|
||||
static const pj_str_t STR_IP6 = { "IP6", 3 };
|
||||
|
@ -1701,11 +1700,11 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru
|
|||
local->origin.id = offer->origin.id;
|
||||
}
|
||||
|
||||
local->origin.user = STR_ASTERISK;
|
||||
pj_strdup2(inv->pool, &local->origin.user, session->endpoint->sdpowner);
|
||||
local->origin.net_type = STR_IN;
|
||||
local->origin.addr_type = session->endpoint->rtp_ipv6 ? STR_IP6 : STR_IP4;
|
||||
local->origin.addr = *pj_gethostname();
|
||||
local->name = local->origin.user;
|
||||
pj_strdup2(inv->pool, &local->name, session->endpoint->sdpsession);
|
||||
|
||||
/* Now let the handlers add streams of various types, pjmedia will automatically reorder the media streams for us */
|
||||
successful = ao2_callback_data(session->media, OBJ_MULTIPLE, add_sdp_streams, local, session);
|
||||
|
|
Loading…
Reference in New Issue