diff --git a/cel/cel_manager.c b/cel/cel_manager.c index e485aab496..12671bc4a3 100644 --- a/cel/cel_manager.c +++ b/cel/cel_manager.c @@ -229,6 +229,7 @@ static void manager_log(struct ast_event *event) struct ast_cel_event_record record = { .version = AST_CEL_EVENT_RECORD_VERSION, }; + RAII_VAR(char *, tenant_id, NULL, ast_free); if (!enablecel) { return; @@ -252,6 +253,10 @@ static void manager_log(struct ast_event *event) } } + 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" @@ -269,6 +274,7 @@ static void manager_log(struct ast_event *event) "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" @@ -290,6 +296,7 @@ static void manager_log(struct ast_event *event) 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, diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index e3d982c690..dc3e66636e 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -552,19 +552,23 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s 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) { @@ -664,7 +668,7 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s 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); diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 6b8936b2d4..61c8846b8f 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -998,6 +998,13 @@ ; 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========================= diff --git a/contrib/ast-db-manage/config/versions/655054a68ad5_add_pjsip_tenantid.py b/contrib/ast-db-manage/config/versions/655054a68ad5_add_pjsip_tenantid.py new file mode 100644 index 0000000000..f64a8d8089 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/655054a68ad5_add_pjsip_tenantid.py @@ -0,0 +1,22 @@ +"""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') diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 2ee5165751..19c7243080 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -273,6 +273,9 @@ R/O returns the linkedid if available, otherwise returns the uniqueid. + + R/W The channel tenantid. + R/W The maximum number of forwards allowed. @@ -565,6 +568,8 @@ static int func_channel_read(struct ast_channel *chan, const char *function, } } 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; @@ -737,6 +742,8 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio 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", diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h index 06307c91f2..788a879720 100644 --- a/include/asterisk/cdr.h +++ b/include/asterisk/cdr.h @@ -317,6 +317,10 @@ struct ast_cdr { 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 */ diff --git a/include/asterisk/cel.h b/include/asterisk/cel.h index 81f375be77..7444938ce6 100644 --- a/include/asterisk/cel.h +++ b/include/asterisk/cel.h @@ -140,7 +140,7 @@ struct ast_cel_event_record { * \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. @@ -164,6 +164,7 @@ struct ast_cel_event_record { 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; diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 0ee66a6f2f..4747ee2c43 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -146,6 +146,8 @@ extern "C" { */ #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 */ @@ -606,6 +608,24 @@ struct ast_assigned_ids { 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 */ @@ -1244,6 +1264,27 @@ struct ast_channel * __attribute__((format(printf, 15, 16))) 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 * @@ -1263,6 +1304,11 @@ struct ast_channel * __attribute__((format(printf, 15, 16))) __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 * @@ -4151,6 +4197,8 @@ const char *ast_channel_userfield(const struct ast_channel *chan); 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); diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h index 774c9b03c1..1b994fa9b4 100644 --- a/include/asterisk/channel_internal.h +++ b/include/asterisk/channel_internal.h @@ -23,6 +23,8 @@ #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); diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h index b9b87e25ff..d4e0033f6a 100644 --- a/include/asterisk/event_defs.h +++ b/include/asterisk/event_defs.h @@ -311,8 +311,15 @@ enum ast_event_ie_type { * 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, }; /*! diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index d0e1e59223..dc66a40184 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -987,6 +987,8 @@ struct ast_sip_endpoint { 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; diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index 73771864a6..5b58be5204 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -109,6 +109,7 @@ struct ast_channel_snapshot_base { 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 */ diff --git a/main/cdr.c b/main/cdr.c index 0bf319b8b7..ee261241b0 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -765,7 +765,8 @@ struct cdr_object { 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 */ @@ -1094,6 +1095,7 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan, co 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; @@ -1362,6 +1364,7 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr) 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) { @@ -1370,6 +1373,7 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr) 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)); @@ -3166,6 +3170,10 @@ void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char 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")) { @@ -3232,6 +3240,7 @@ static const char * const cdr_readonly_vars[] = { "accountcode", "uniqueid", "linkedid", + "tenantid", "userfield", "sequence", NULL @@ -3353,6 +3362,14 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na 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")) { diff --git a/main/cel.c b/main/cel.c index d41543c27a..98d31b551a 100644 --- a/main/cel.c +++ b/main/cel.c @@ -554,6 +554,7 @@ struct ast_event *ast_cel_create_event_with_time(struct ast_channel_snapshot *sn 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, ""), @@ -853,6 +854,7 @@ int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record * 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), ""); diff --git a/main/channel.c b/main/channel.c index 57533c82fb..4eae7fee74 100644 --- a/main/channel.c +++ b/main/channel.c @@ -733,7 +733,7 @@ static struct ast_channel *__attribute__((format(printf, 15, 0))) __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; @@ -752,7 +752,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char 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. */ @@ -964,7 +964,26 @@ struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *ci 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; diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index bc0fb4c641..8f3227779a 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -57,6 +57,7 @@ struct ast_channel_id { 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 */ }; /*! @@ -316,6 +317,21 @@ const char *ast_channel_linkedid(const struct ast_channel *chan) 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; @@ -1350,7 +1366,8 @@ static int pvt_cause_cmp_fn(void *obj, void *vstr, int flags) #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; @@ -1371,6 +1388,20 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), 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); @@ -1396,6 +1427,12 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), 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 @@ -1406,6 +1443,12 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), 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); diff --git a/main/cli.c b/main/cli.c index 19355ab6db..db9a86e574 100644 --- a/main/cli.c +++ b/main/cli.c @@ -1659,6 +1659,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_callid callid; char callid_buf[32]; int stream_num; + RAII_VAR(char *, tenant_id, NULL, ast_free); switch (cmd) { case CLI_INIT: @@ -1717,12 +1718,17 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar 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" @@ -1753,6 +1759,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar 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, diff --git a/main/event.c b/main/event.c index 2b73cd7385..7c8af91475 100644 --- a/main/event.c +++ b/main/event.c @@ -189,6 +189,7 @@ static const struct ie_map { [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) diff --git a/main/manager_channels.c b/main/manager_channels.c index 344a2487a7..1ffd36d1bc 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -543,6 +543,10 @@ struct ast_str *ast_manager_build_channel_state_string_prefix( 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; diff --git a/main/stasis_channels.c b/main/stasis_channels.c index a84f18968e..193f8bf438 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -285,6 +285,7 @@ static struct ast_channel_snapshot_base *channel_snapshot_base_create(struct ast 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; @@ -1329,6 +1330,10 @@ struct ast_json *ast_channel_snapshot_to_json( 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; } diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index a5ba5cc768..e7773d2683 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -1165,6 +1165,15 @@ int ast_ari_validate_channel(struct ast_json *json) 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", diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index f350c8de33..39df8b4866 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -1356,6 +1356,7 @@ ari_validator ast_ari_validate_application_fn(void); * - name: string (required) * - protocol_id: string (required) * - state: string (required) + * - tenantid: string * Dialed * DialplanCEP * - app_data: string (required) diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml index 74024a45e8..2de4620387 100644 --- a/res/res_pjsip/pjsip_config.xml +++ b/res/res_pjsip/pjsip_config.xml @@ -683,6 +683,14 @@ dialplan application such as Ringing. + + The tenant ID for this endpoint. + + 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. + + Minimum session timers expiration period diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 58a50c484a..c83ee33179 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -2303,6 +2303,7 @@ int ast_res_pjsip_initialize_configuration(void) 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"); diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index 1b49329fcf..2a1d0a0cb2 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -2191,6 +2191,11 @@ "caller_rdnis": { "type": "string", "description": "The Caller ID RDNIS" + }, + "tenantid": { + "required": false, + "type": "string", + "description": "The Tenant ID for the channel" } } }