struct ast_cel_event_record record = {
.version = AST_CEL_EVENT_RECORD_VERSION,
};
+ RAII_VAR(char *, tenant_id, NULL, ast_free);
if (!enablecel) {
return;
}
}
+ if (!ast_strlen_zero(record.tenant_id)) {
+ ast_asprintf(&tenant_id, "TenantID: %s\r\n", record.tenant_id);
+ }
+
manager_event(EVENT_FLAG_CALL, "CEL",
"EventName: %s\r\n"
"AccountCode: %s\r\n"
"AMAFlags: %s\r\n"
"UniqueID: %s\r\n"
"LinkedID: %s\r\n"
+ "%s"
"Userfield: %s\r\n"
"Peer: %s\r\n"
"PeerAccount: %s\r\n"
ast_channel_amaflags2string(record.amaflag),
record.unique_id,
record.linked_id,
+ !ast_strlen_zero(tenant_id) ? tenant_id : "",
record.user_field,
record.peer,
record.peer_account,
struct ast_sip_channel_pvt *channel;
struct ast_variable *var;
struct ast_stream_topology *topology;
+ struct ast_channel_initializers initializers = {
+ .version = AST_CHANNEL_INITIALIZERS_VERSION,
+ .tenantid = session->endpoint->tenantid,
+ };
SCOPE_ENTER(1, "%s\n", ast_sip_session_get_name(session));
if (!(pvt = ao2_alloc_options(sizeof(*pvt), chan_pjsip_pvt_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK))) {
SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't create pvt\n");
}
- chan = ast_channel_alloc_with_endpoint(1, state,
+ chan = ast_channel_alloc_with_initializers(1, state,
S_COR(session->id.number.valid, session->id.number.str, ""),
S_COR(session->id.name.valid, session->id.name.str, ""),
session->endpoint->accountcode,
exten, session->endpoint->context,
assignedids, requestor, 0,
- session->endpoint->persistent, "PJSIP/%s-%08x",
+ session->endpoint->persistent, &initializers, "PJSIP/%s-%08x",
ast_sorcery_object_get_id(session->endpoint),
(unsigned) ast_atomic_fetchadd_int((int *) &chan_idx, +1));
if (!chan) {
for (var = session->endpoint->channel_vars; var; var = var->next) {
char buf[512];
pbx_builtin_setvar_helper(chan, var->name, ast_get_encoded_str(
- var->value, buf, sizeof(buf)));
+ var->value, buf, sizeof(buf)));
}
ast_channel_stage_snapshot_done(chan);
; AOC updates can be sent using the AOCMessage AMI action or come
; from PRI channels.
; (default: no)
+;
+; tenantid =
+ ; Sets the tenant ID for this endpoint. It can be read in dialplan
+ ; with the CHANNEL function, and it can be changed later via dialplan
+ ; using the same CHANNEL function if needed. Setting tenant ID here
+ ; will cause it to show up on channel creation and the initial
+ ; channel snapshot.
;==========================AUTH SECTION OPTIONS=========================
--- /dev/null
+"""add pjsip tenantid
+
+Revision ID: 655054a68ad5
+Revises: bd9c5159c7ea
+Create Date: 2024-06-11 11:18:41.466929
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '655054a68ad5'
+down_revision = '2b7c507d7d12'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('tenantid', sa.String(80)))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'tenantid')
<enum name="linkedid">
<para>R/O returns the linkedid if available, otherwise returns the uniqueid.</para>
</enum>
+ <enum name="tenantid">
+ <para>R/W The channel tenantid.</para>
+ </enum>
<enum name="max_forwards">
<para>R/W The maximum number of forwards allowed.</para>
</enum>
}
} else if (!strcasecmp(data, "device_name")) {
ret = ast_channel_get_device_name(chan, buf, len);
+ } else if (!strcasecmp(data, "tenantid")) {
+ locked_copy_string(chan, buf, ast_channel_tenantid(chan), len);
} else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
ret = -1;
ret = ast_max_forwards_set(chan, max_forwards);
ast_channel_unlock(chan);
}
+ } else if (!strcasecmp(data, "tenantid")) {
+ ast_channel_tenantid_set(chan, value);
} else if (!ast_channel_tech(chan)->func_channel_write
|| ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) {
ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
char uniqueid[AST_MAX_UNIQUEID];
/*! Linked group Identifier */
char linkedid[AST_MAX_UNIQUEID];
+ /*! Channel tenant Identifier */
+ char tenantid[AST_MAX_TENANT_ID];
+ /*! Channel tenant Identifier of the last person we talked to */
+ char peertenantid[AST_MAX_TENANT_ID];
/*! User field */
char userfield[AST_MAX_USER_FIELD];
/*! Sequence field */
* \brief struct ABI version
* \note This \b must be incremented when the struct changes.
*/
- #define AST_CEL_EVENT_RECORD_VERSION 2
+ #define AST_CEL_EVENT_RECORD_VERSION 3
/*!
* \brief struct ABI version
* \note This \b must stay as the first member.
const char *peer_account;
const char *unique_id;
const char *linked_id;
+ const char *tenant_id;
uint amaflag;
const char *user_field;
const char *peer;
*/
#define AST_MAX_PUBLIC_UNIQUEID 149
+#define AST_MAX_TENANT_ID 64 /*!< Max length of a channel tenant_id */
+
/*!
* The number of buckets to store channels or channel information
*/
const char *uniqueid2;
};
+/*!
+ * \brief Helper struct for initializing additional channel information on channel creation.
+ * \since 18.25.0
+ */
+struct ast_channel_initializers {
+ /*!
+ * \brief struct ABI version
+ * \note This \b must be incremented when the struct changes.
+ */
+ #define AST_CHANNEL_INITIALIZERS_VERSION 1
+ /*!
+ * \brief struct ABI version
+ * \note This \b must stay as the first member.
+ */
+ uint32_t version;
+ const char *tenantid;
+};
+
/*!
* \brief Forward declaration
*/
const char *file, int line, const char *function,
const char *name_fmt, ...);
+/*!
+ * \brief Create a channel structure
+ * \since 18.25.0
+ *
+ * \retval NULL failure
+ * \retval non-NULL successfully allocated channel
+ *
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
+ * \note By default, new channels are set to the "s" extension
+ * and "default" context.
+ * \note Same as __ast_channel_alloc but with ast_channel_initializers struct.
+ */
+struct ast_channel * __attribute__((format(printf, 16, 17)))
+ __ast_channel_alloc_with_initializers(int needqueue, int state, const char *cid_num,
+ const char *cid_name, const char *acctcode,
+ const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
+ const struct ast_channel *requestor, enum ama_flags amaflag,
+ struct ast_endpoint *endpoint, struct ast_channel_initializers *initializers,
+ const char *file, int line, const char *function,
+ const char *name_fmt, ...);
+
/*!
* \brief Create a channel structure
*
__ast_channel_alloc((needqueue), (state), (cid_num), (cid_name), (acctcode), (exten), (context), (assignedids), (requestor), (amaflag), (endpoint), \
__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+#define ast_channel_alloc_with_initializers(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag, endpoint, initializers, ...) \
+ __ast_channel_alloc_with_initializers((needqueue), (state), (cid_num), (cid_name), (acctcode), (exten), (context), (assignedids), (requestor), (amaflag), (endpoint), \
+ (initializers), __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+
+
/*!
* \brief Create a fake channel structure
*
const char *ast_channel_call_forward(const struct ast_channel *chan);
const char *ast_channel_uniqueid(const struct ast_channel *chan);
const char *ast_channel_linkedid(const struct ast_channel *chan);
+const char *ast_channel_tenantid(const struct ast_channel *chan);
+void ast_channel_tenantid_set(struct ast_channel *chan, const char *value);
const char *ast_channel_parkinglot(const struct ast_channel *chan);
const char *ast_channel_hangupsource(const struct ast_channel *chan);
const char *ast_channel_dialcontext(const struct ast_channel *chan);
#define ast_channel_internal_alloc(destructor, assignedid, requestor) __ast_channel_internal_alloc(destructor, assignedid, requestor, __FILE__, __LINE__, __PRETTY_FUNCTION__)
struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *file, int line, const char *function);
+struct ast_channel *__ast_channel_internal_alloc_with_initializers(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids,
+ const struct ast_channel *requestor, const struct ast_channel_initializers *initializers, const char *file, int line, const char *function);
void ast_channel_internal_finalize(struct ast_channel *chan);
int ast_channel_internal_is_finalized(struct ast_channel *chan);
void ast_channel_internal_cleanup(struct ast_channel *chan);
* Payload type: UINT
*/
AST_EVENT_IE_NODE_ID = 0x003e,
+
+ /*!
+ * \brief Channel Event TenantID
+ * Used by: AST_EVENT_CEL
+ * Payload type: STR
+ */
+ AST_EVENT_IE_CEL_TENANTID = 0x003f,
/*! \brief Must be the last IE value +1 */
- AST_EVENT_IE_TOTAL = 0x003f,
+ AST_EVENT_IE_TOTAL = 0x0040,
};
/*!
AST_STRING_FIELD(incoming_mwi_mailbox);
/*! STIR/SHAKEN profile to use */
AST_STRING_FIELD(stir_shaken_profile);
+ /*! Tenant ID for the endpoint */
+ AST_STRING_FIELD(tenantid);
);
/*! Configuration for extensions */
struct ast_sip_endpoint_extensions extensions;
AST_STRING_FIELD(userfield); /*!< Userfield for CEL billing */
AST_STRING_FIELD(language); /*!< The default spoken language for the channel */
AST_STRING_FIELD(type); /*!< Type of channel technology */
+ AST_STRING_FIELD(tenantid); /*!< Channel tenant identifier */
);
struct timeval creationtime; /*!< The time of channel creation */
int tech_properties; /*!< Properties of the channel's technology */
struct ast_flags flags; /*!< Flags on the CDR */
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(linkedid); /*!< Linked ID. Cached here as it may change out from party A, which must be immutable */
- AST_STRING_FIELD(uniqueid); /*!< Unique id of party A. Cached here as it is the master CDR container key */
+ AST_STRING_FIELD(uniqueid); /*!< Unique id of party A. Cached here as it is the master CDR container key */
+ AST_STRING_FIELD(tenantid); /*!< Tenant ID. Cached here because the value can be manipulated through dialplan */
AST_STRING_FIELD(name); /*!< Channel name of party A. Cached here as the party A address may change */
AST_STRING_FIELD(bridge); /*!< The bridge the party A happens to be in. */
AST_STRING_FIELD(appl); /*!< The last accepted application party A was in */
ast_string_field_set(cdr, uniqueid, chan->base->uniqueid);
ast_string_field_set(cdr, name, chan->base->name);
ast_string_field_set(cdr, linkedid, chan->peer->linkedid);
+ ast_string_field_set(cdr, tenantid, chan->base->tenantid);
cdr->disposition = AST_CDR_NULL;
cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
cdr->lastevent = *event_time;
ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
+ ast_copy_string(cdr_copy->tenantid, it_cdr->tenantid, sizeof(cdr_copy->tenantid));
/* Party B */
if (party_b) {
if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
}
+ ast_copy_string(cdr_copy->peertenantid, party_b->base->tenantid, sizeof(cdr_copy->peertenantid));
}
if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
ast_copy_string(workspace, cdr->uniqueid, workspacelen);
} else if (!strcasecmp(name, "linkedid")) {
ast_copy_string(workspace, cdr->linkedid, workspacelen);
+ } else if (!strcasecmp(name, "tenantid")) {
+ ast_copy_string(workspace, cdr->tenantid, workspacelen);
+ } else if (!strcasecmp(name, "peertenantid")) {
+ ast_copy_string(workspace, cdr->peertenantid, workspacelen);
} else if (!strcasecmp(name, "userfield")) {
ast_copy_string(workspace, cdr->userfield, workspacelen);
} else if (!strcasecmp(name, "sequence")) {
"accountcode",
"uniqueid",
"linkedid",
+ "tenantid",
"userfield",
"sequence",
NULL
ast_copy_string(value, party_a->base->uniqueid, length);
} else if (!strcasecmp(name, "linkedid")) {
ast_copy_string(value, cdr_obj->linkedid, length);
+ } else if (!strcasecmp(name, "tenantid")) {
+ ast_copy_string(value, party_a->base->tenantid, length);
+ } else if (!strcasecmp(name, "peertenantid")) {
+ if (party_b) {
+ ast_copy_string(value, party_b->base->tenantid, length);
+ } else {
+ ast_copy_string(value, "", length);
+ }
} else if (!strcasecmp(name, "userfield")) {
ast_copy_string(value, cdr_obj->party_a.userfield, length);
} else if (!strcasecmp(name, "sequence")) {
AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->account,
AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->base->uniqueid,
AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->linkedid,
+ AST_EVENT_IE_CEL_TENANTID, AST_EVENT_IE_PLTYPE_STR, snapshot->base->tenantid,
AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->base->userfield,
AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer, ""),
r->peer_account = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEERACCT), "");
r->unique_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
r->linked_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
+ r->tenant_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_TENANTID), "");
r->amaflag = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
r->user_field = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
r->peer = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
__ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char *cid_name,
const char *acctcode, const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
const struct ast_channel *requestor, enum ama_flags amaflag, struct ast_endpoint *endpoint,
- const char *file, int line,
+ struct ast_channel_initializers *initializers, const char *file, int line,
const char *function, const char *name_fmt, va_list ap)
{
struct ast_channel *tmp;
return NULL;
}
- tmp = __ast_channel_internal_alloc(ast_channel_destructor, assignedids, requestor,
+ tmp = __ast_channel_internal_alloc_with_initializers(ast_channel_destructor, assignedids, requestor, initializers,
file, line, function);
if (!tmp) {
/* Channel structure allocation failure. */
va_start(ap, name_fmt);
result = __ast_channel_alloc_ap(needqueue, state, cid_num, cid_name, acctcode, exten, context,
- assignedids, requestor, amaflag, endpoint, file, line, function, name_fmt, ap);
+ assignedids, requestor, amaflag, endpoint, NULL, file, line, function, name_fmt, ap);
+ va_end(ap);
+
+ return result;
+}
+
+struct ast_channel *__ast_channel_alloc_with_initializers(int needqueue, int state, const char *cid_num,
+ const char *cid_name, const char *acctcode,
+ const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
+ const struct ast_channel *requestor, enum ama_flags amaflag,
+ struct ast_endpoint *endpoint, struct ast_channel_initializers *initializers,
+ const char *file, int line, const char *function,
+ const char *name_fmt, ...)
+{
+ va_list ap;
+ struct ast_channel *result;
+
+ va_start(ap, name_fmt);
+ result = __ast_channel_alloc_ap(needqueue, state, cid_num, cid_name, acctcode, exten, context,
+ assignedids, requestor, amaflag, endpoint, initializers, file, line, function, name_fmt, ap);
va_end(ap);
return result;
time_t creation_time; /*!< Creation time */
int creation_unique; /*!< sub-second unique value */
char unique_id[AST_MAX_UNIQUEID]; /*!< Unique Identifier */
+ char tenant_id[AST_MAX_TENANT_ID]; /*!< Multi-tenant identifier */
};
/*!
return chan->linkedid.unique_id;
}
+const char *ast_channel_tenantid(const struct ast_channel *chan)
+{
+ /* It's ok for tenantid to be empty, so no need to assert */
+ return chan->linkedid.tenant_id;
+}
+
+void ast_channel_tenantid_set(struct ast_channel *chan, const char *value)
+{
+ if (ast_strlen_zero(value)) {
+ return;
+ }
+ ast_copy_string(chan->linkedid.tenant_id, value, sizeof(chan->linkedid.tenant_id));
+ ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+}
+
const char *ast_channel_appl(const struct ast_channel *chan)
{
return chan->appl;
#define DIALED_CAUSES_BUCKETS 37
-struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *file, int line, const char *function)
+struct ast_channel *__ast_channel_internal_alloc_with_initializers(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids,
+ const struct ast_channel *requestor, const struct ast_channel_initializers *initializers, const char *file, int line, const char *function)
{
struct ast_channel *tmp;
return ast_channel_unref(tmp);
}
+ /* Check initializers validity here for early abort. Unfortunately, we can't do much here because
+ * tenant ID is part of linked ID, which would overwrite it further down. */
+ if (initializers) {
+ if (initializers->version == 0) {
+ ast_log(LOG_ERROR, "Channel initializers must have a non-zero version.\n");
+ return ast_channel_unref(tmp);
+ } else if (initializers->version != AST_CHANNEL_INITIALIZERS_VERSION) {
+ ast_log(LOG_ERROR, "ABI mismatch for ast_channel_initializers. "
+ "Please ensure all modules were compiled for "
+ "this version of Asterisk.\n");
+ return ast_channel_unref(tmp);
+ }
+ }
+
/* set the creation time in the uniqueid */
tmp->uniqueid.creation_time = time(NULL);
tmp->uniqueid.creation_unique = ast_atomic_fetchadd_int(&uniqueint, 1);
tmp->linkedid = tmp->uniqueid;
}
+ /* Things like tenant ID need to be set here, otherwise they would be overwritten by
+ * things like inheriting linked ID above. */
+ if (initializers) {
+ ast_copy_string(tmp->linkedid.tenant_id, initializers->tenantid, sizeof(tmp->linkedid.tenant_id));
+ }
+
AST_VECTOR_INIT(&tmp->fds, AST_MAX_FDS);
/* Force all channel snapshot segments to be created on first use, so we don't have to check if
return tmp;
}
+struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids,
+ const struct ast_channel *requestor, const char *file, int line, const char *function)
+{
+ return __ast_channel_internal_alloc_with_initializers(destructor, assignedids, requestor, NULL, file, line, function);
+}
+
struct ast_channel *ast_channel_internal_oldest_linkedid(struct ast_channel *a, struct ast_channel *b)
{
ast_assert(a->linkedid.creation_time != 0);
ast_callid callid;
char callid_buf[32];
int stream_num;
+ RAII_VAR(char *, tenant_id, NULL, ast_free);
switch (cmd) {
case CLI_INIT:
ast_callid_strnprint(callid_buf, sizeof(callid_buf), callid);
}
+ if (!ast_strlen_zero(ast_channel_tenantid(chan))) {
+ ast_asprintf(&tenant_id, " TenantID: %s\n", ast_channel_tenantid(chan));
+ }
+
ast_str_append(&output, 0,
" -- General --\n"
" Name: %s\n"
" Type: %s\n"
" UniqueID: %s\n"
" LinkedID: %s\n"
+ "%s"
" Caller ID: %s\n"
" Caller ID Name: %s\n"
"Connected Line ID: %s\n"
ast_channel_tech(chan)->type,
ast_channel_uniqueid(chan),
ast_channel_linkedid(chan),
+ !ast_strlen_zero(tenant_id) ? tenant_id : "",
S_COR(ast_channel_caller(chan)->id.number.valid,
ast_channel_caller(chan)->id.number.str, "(N/A)"),
S_COR(ast_channel_caller(chan)->id.name.valid,
[AST_EVENT_IE_PRESENCE_STATE] = { AST_EVENT_IE_PLTYPE_UINT, "PresenceState" },
[AST_EVENT_IE_PRESENCE_SUBTYPE] = { AST_EVENT_IE_PLTYPE_STR, "PresenceSubtype" },
[AST_EVENT_IE_PRESENCE_MESSAGE] = { AST_EVENT_IE_PLTYPE_STR, "PresenceMessage" },
+ [AST_EVENT_IE_CEL_TENANTID] = { AST_EVENT_IE_PLTYPE_STR, "TenantID" },
};
const char *ast_event_get_type_name(const struct ast_event *event)
return NULL;
}
+ if (!ast_strlen_zero(snapshot->base->tenantid)) {
+ ast_str_append(&out, 0, "%sTenantid: %s\r\n", prefix, snapshot->base->tenantid);
+ }
+
if (snapshot->manager_vars) {
struct ast_var_t *var;
char *val;
ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
ast_string_field_set(snapshot, language, ast_channel_language(chan));
+ ast_string_field_set(snapshot, tenantid, ast_channel_tenantid(chan));
snapshot->creationtime = ast_channel_creationtime(chan);
snapshot->tech_properties = ast_channel_tech(chan)->properties;
ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
}
+ if (!ast_strlen_zero(snapshot->base->tenantid)) {
+ ast_json_object_set(json_chan, "tenantid", ast_json_string_create(snapshot->base->tenantid));
+ }
+
return json_chan;
}
res = 0;
}
} else
+ if (strcmp("tenantid", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field tenantid failed validation\n");
+ res = 0;
+ }
+ } else
{
ast_log(LOG_ERROR,
"ARI Channel has undocumented field %s\n",
* - name: string (required)
* - protocol_id: string (required)
* - state: string (required)
+ * - tenantid: string
* Dialed
* DialplanCEP
* - app_data: string (required)
dialplan application such as <emphasis>Ringing</emphasis>.</para>
</description>
</configOption>
+ <configOption name="tenantid" default="">
+ <synopsis>The tenant ID for this endpoint.</synopsis>
+ <description><para>
+ Sets the tenant ID for this endpoint. When a channel is created,
+ tenantid will be set to this value. It can be changed via dialplan
+ later if needed.
+ </para></description>
+ </configOption>
<configOption name="timers_min_se" default="90">
<synopsis>Minimum session timers expiration period</synopsis>
<description><para>
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_mechanisms", "", security_mechanism_handler, security_mechanism_to_str, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_negotiation", "no", security_negotiation_handler, security_negotiation_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_aoc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, send_aoc));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tenantid", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, tenantid));
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
"caller_rdnis": {
"type": "string",
"description": "The Caller ID RDNIS"
+ },
+ "tenantid": {
+ "required": false,
+ "type": "string",
+ "description": "The Tenant ID for the channel"
}
}
}