diff options
-rw-r--r-- | include/asterisk/stasis.h | 40 | ||||
-rw-r--r-- | include/asterisk/stasis_app.h | 7 | ||||
-rw-r--r-- | include/asterisk/stasis_bridges.h | 7 | ||||
-rw-r--r-- | include/asterisk/stasis_channels.h | 7 | ||||
-rw-r--r-- | include/asterisk/stasis_endpoints.h | 5 | ||||
-rw-r--r-- | main/json.c | 2 | ||||
-rw-r--r-- | main/rtp_engine.c | 17 | ||||
-rw-r--r-- | main/stasis_bridges.c | 87 | ||||
-rw-r--r-- | main/stasis_channels.c | 57 | ||||
-rw-r--r-- | main/stasis_endpoints.c | 12 | ||||
-rw-r--r-- | main/stasis_message.c | 6 | ||||
-rw-r--r-- | res/ari/resource_bridges.c | 8 | ||||
-rw-r--r-- | res/ari/resource_channels.c | 22 | ||||
-rw-r--r-- | res/ari/resource_endpoints.c | 22 | ||||
-rw-r--r-- | res/res_stasis.c | 44 | ||||
-rw-r--r-- | res/stasis/app.c | 51 |
16 files changed, 314 insertions, 80 deletions
diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h index 955bdc3fc..6bc5171e0 100644 --- a/include/asterisk/stasis.h +++ b/include/asterisk/stasis.h @@ -187,6 +187,36 @@ struct stasis_message_type; struct stasis_message; /*! + * \brief Structure containing callbacks for Stasis message sanitization + * + * \note If either callback is implemented, both should be implemented since + * not all callers may have access to the full snapshot. + */ +struct stasis_message_sanitizer { + /*! + * \brief Callback which determines whether a channel should be sanitized from + * a message based on the channel's unique ID + * + * \param channel_id The unique ID of the channel + * + * \retval non-zero if the channel should be left out of the message + * \retval zero if the channel should remain in the message + */ + int (*channel_id)(const char *channel_id); + + /*! + * \brief Callback which determines whether a channel should be sanitized from + * a message based on the channel's snapshot + * + * \param snapshot A snapshot generated from the channel + * + * \retval non-zero if the channel should be left out of the message + * \retval zero if the channel should remain in the message + */ + int (*channel_snapshot)(const struct ast_channel_snapshot *snapshot); +}; + +/*! * \brief Virtual table providing methods for messages. * \since 12 */ @@ -198,17 +228,19 @@ struct stasis_message_vtable { * The returned object should be ast_json_unref()'ed. * * \param message Message to convert to JSON string. + * \param sanitize Snapshot sanitization callback. + * * \return Newly allocated JSON message. * \return \c NULL on error. * \return \c NULL if JSON format is not supported. */ - struct ast_json *(*to_json)(struct stasis_message *message); + struct ast_json *(*to_json)(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize); /*! * \brief Build the AMI representation of the message. * * May be \c NULL, or may return \c NULL, to indicate no representation. - * The returned object should be ao2_cleankup()'ed. + * The returned object should be ao2_cleanup()'ed. * * \param message Message to convert to AMI string. * \return Newly allocated \ref ast_manager_event_blob. @@ -292,11 +324,13 @@ const struct timeval *stasis_message_timestamp(const struct stasis_message *msg) * be ast_json_unref()'ed. * * \param message Message to convert to JSON string. + * \param sanitize Snapshot sanitization callback. + * * \return Newly allocated string with JSON message. * \return \c NULL on error. * \return \c NULL if JSON format is not supported. */ -struct ast_json *stasis_message_to_json(struct stasis_message *message); +struct ast_json *stasis_message_to_json(struct stasis_message *message, struct stasis_message_sanitizer *sanitize); /*! * \brief Build the AMI representation of the message. diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index 801b7adb2..4ef55b193 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -532,6 +532,13 @@ void stasis_app_ref(void); */ void stasis_app_unref(void); +/*! + * \brief Get the Stasis message sanitizer for app_stasis applications + * + * \retval The stasis message sanitizer + */ +struct stasis_message_sanitizer *stasis_app_get_sanitizer(void); + /*! @} */ #endif /* _ASTERISK_STASIS_APP_H */ diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h index d82bcffaf..9412bf0b7 100644 --- a/include/asterisk/stasis_bridges.h +++ b/include/asterisk/stasis_bridges.h @@ -231,10 +231,15 @@ void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *cha /*! * \brief Build a JSON object from a \ref ast_bridge_snapshot. + * + * \param snapshot The bridge snapshot to convert to JSON + * \param sanitize The message sanitizer to use on the snapshot + * * \return JSON object representing bridge snapshot. * \return \c NULL on error */ -struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot); +struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot, + const struct stasis_message_sanitizer *sanitize); /*! * \brief Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index 7d9c3efdc..519a4b676 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -541,10 +541,15 @@ void ast_publish_channel_state(struct ast_channel *chan); /*! * \brief Build a JSON object from a \ref ast_channel_snapshot. + * + * \param snapshot The snapshot to convert to JSON + * \param sanitize The message sanitizer to use on the snapshot + * * \return JSON object representing channel snapshot. * \return \c NULL on error */ -struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot); +struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, + const struct stasis_message_sanitizer *sanitize); /*! * \brief Compares the context, exten and priority of two snapshots. diff --git a/include/asterisk/stasis_endpoints.h b/include/asterisk/stasis_endpoints.h index 0ba233bf8..1d56a8fea 100644 --- a/include/asterisk/stasis_endpoints.h +++ b/include/asterisk/stasis_endpoints.h @@ -208,11 +208,14 @@ struct ast_endpoint_snapshot *ast_endpoint_latest_snapshot(const char *tech, * \brief Build a JSON object from a \ref ast_endpoint_snapshot. * * \param snapshot Endpoint snapshot. + * \param sanitize The message sanitizer to use on the snapshot + * * \return JSON object representing endpoint snapshot. * \return \c NULL on error */ struct ast_json *ast_endpoint_snapshot_to_json( - const struct ast_endpoint_snapshot *snapshot); + const struct ast_endpoint_snapshot *snapshot, + const struct stasis_message_sanitizer *sanitize); /*! * \brief Initialization function for endpoint stasis support. diff --git a/main/json.c b/main/json.c index ce4c6cfc9..066a5df17 100644 --- a/main/json.c +++ b/main/json.c @@ -690,7 +690,7 @@ struct ast_json *ast_json_vpack(char const *format, va_list ap) struct ast_json *r = NULL; if (format) { r = (struct ast_json *)json_vpack_ex(&error, 0, format, ap); - if (!r) { + if (!r && !ast_strlen_zero(error.text)) { ast_log(LOG_ERROR, "Error building JSON from '%s': %s.\n", format, error.text); diff --git a/main/rtp_engine.c b/main/rtp_engine.c index b02c6bb1b..c63bab0ea 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -1780,13 +1780,14 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message * ast_str_buffer(packet_string)); } -static struct ast_json *rtcp_report_to_json(struct stasis_message *msg) +static struct ast_json *rtcp_report_to_json(struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize) { struct rtcp_message_payload *payload = stasis_message_data(msg); RAII_VAR(struct ast_json *, json_rtcp_report, NULL, ast_json_unref); RAII_VAR(struct ast_json *, json_rtcp_report_blocks, NULL, ast_json_unref); RAII_VAR(struct ast_json *, json_rtcp_sender_info, NULL, ast_json_unref); - struct ast_json * json_payload; + RAII_VAR(struct ast_json *, json_channel, NULL, ast_json_unref); int i; json_rtcp_report_blocks = ast_json_array_create(); @@ -1835,11 +1836,17 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg) return NULL; } - json_payload = ast_json_pack("{s: O, s: O, s: O}", - "channel", payload->snapshot ? ast_channel_snapshot_to_json(payload->snapshot) : ast_json_null(), + if (payload->snapshot) { + json_channel = ast_channel_snapshot_to_json(payload->snapshot, sanitize); + if (!json_channel) { + return NULL; + } + } + + return ast_json_pack("{s: O, s: O, s: O}", + "channel", payload->snapshot ? json_channel : ast_json_null(), "rtcp_report", json_rtcp_report, "blob", payload->blob); - return json_payload; } static void rtp_rtcp_report_dtor(void *obj) diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index 7d078f9d0..b92d048bc 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -135,9 +135,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message); static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message); -static struct ast_json *ast_channel_entered_bridge_to_json(struct stasis_message *msg); -static struct ast_json *ast_channel_left_bridge_to_json(struct stasis_message *msg); -static struct ast_json *ast_bridge_merge_message_to_json(struct stasis_message *msg); +static struct ast_json *ast_channel_entered_bridge_to_json( + struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize); +static struct ast_json *ast_channel_left_bridge_to_json( + struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize); +static struct ast_json *ast_bridge_merge_message_to_json( + struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize); static struct stasis_cp_all *bridge_cache_all; @@ -316,17 +322,25 @@ static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_b return msg; } -static struct ast_json *ast_bridge_merge_message_to_json(struct stasis_message *msg) +static struct ast_json *ast_bridge_merge_message_to_json( + struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize) { - struct ast_bridge_merge_message *merge; + struct ast_bridge_merge_message *merge = stasis_message_data(msg); + RAII_VAR(struct ast_json *, json_bridge_to, + ast_bridge_snapshot_to_json(merge->to, sanitize), ast_json_unref); + RAII_VAR(struct ast_json *, json_bridge_from, + ast_bridge_snapshot_to_json(merge->from, sanitize), ast_json_unref); - merge = stasis_message_data(msg); + if (!json_bridge_to || !json_bridge_from) { + return NULL; + } - return ast_json_pack("{s: s, s: o, s: o, s: o}", + return ast_json_pack("{s: s, s: o, s: O, s: O}", "type", "BridgeMerged", "timestamp", ast_json_timeval(*stasis_message_timestamp(msg), NULL), - "bridge", ast_bridge_snapshot_to_json(merge->to), - "bridge_from", ast_bridge_snapshot_to_json(merge->from)); + "bridge", json_bridge_to, + "bridge_from", json_bridge_from); } void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from) @@ -443,45 +457,63 @@ static struct ast_json *simple_bridge_channel_event( const char *type, struct ast_bridge_snapshot *bridge_snapshot, struct ast_channel_snapshot *channel_snapshot, - const struct timeval *tv) + const struct timeval *tv, + const struct stasis_message_sanitizer *sanitize) { - return ast_json_pack("{s: s, s: o, s: o, s: o}", + RAII_VAR(struct ast_json *, json_bridge, + ast_bridge_snapshot_to_json(bridge_snapshot, sanitize), ast_json_unref); + RAII_VAR(struct ast_json *, json_channel, + ast_channel_snapshot_to_json(channel_snapshot, sanitize), ast_json_unref); + + if (!json_bridge || !json_channel) { + return NULL; + } + + return ast_json_pack("{s: s, s: o, s: O, s: O}", "type", type, "timestamp", ast_json_timeval(*tv, NULL), - "bridge", ast_bridge_snapshot_to_json(bridge_snapshot), - "channel", ast_channel_snapshot_to_json(channel_snapshot)); + "bridge", json_bridge, + "channel", json_channel); } -struct ast_json *ast_channel_entered_bridge_to_json(struct stasis_message *msg) +struct ast_json *ast_channel_entered_bridge_to_json( + struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize) { struct ast_bridge_blob *obj = stasis_message_data(msg); return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge, - obj->channel, stasis_message_timestamp(msg)); + obj->channel, stasis_message_timestamp(msg), sanitize); } -struct ast_json *ast_channel_left_bridge_to_json(struct stasis_message *msg) +struct ast_json *ast_channel_left_bridge_to_json( + struct stasis_message *msg, + const struct stasis_message_sanitizer *sanitize) { struct ast_bridge_blob *obj = stasis_message_data(msg); return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge, - obj->channel, stasis_message_timestamp(msg)); + obj->channel, stasis_message_timestamp(msg), sanitize); } -typedef struct ast_json *(*json_item_serializer_cb)(void *obj); - -static struct ast_json *container_to_json_array(struct ao2_container *items, json_item_serializer_cb item_cb) +static struct ast_json *container_to_json_array(struct ao2_container *items, + const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, json_items, ast_json_array_create(), ast_json_unref); - void *item; + char *item; struct ao2_iterator it; if (!json_items) { return NULL; } - it = ao2_iterator_init(items, 0); - while ((item = ao2_iterator_next(&it))) { - if (ast_json_array_append(json_items, item_cb(item))) { + for (it = ao2_iterator_init(items, 0); + (item = ao2_iterator_next(&it)); ao2_cleanup(item)) { + if (sanitize && sanitize->channel_id && sanitize->channel_id(item)) { + continue; + } + + if (ast_json_array_append(json_items, ast_json_string_create(item))) { + ao2_cleanup(item); ao2_iterator_destroy(&it); return NULL; } @@ -500,7 +532,9 @@ static const char *capability2str(uint32_t capabilities) } } -struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot) +struct ast_json *ast_bridge_snapshot_to_json( + const struct ast_bridge_snapshot *snapshot, + const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, json_bridge, NULL, ast_json_unref); struct ast_json *json_channels; @@ -509,8 +543,7 @@ struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *s return NULL; } - json_channels = container_to_json_array(snapshot->channels, - (json_item_serializer_cb)ast_json_string_create); + json_channels = container_to_json_array(snapshot->channels, sanitize); if (!json_channels) { return NULL; } diff --git a/main/stasis_channels.c b/main/stasis_channels.c index f178df35b..38aac982e 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -755,11 +755,15 @@ void ast_publish_channel_state(struct ast_channel *chan) stasis_publish(ast_channel_topic(chan), message); } -struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot) +struct ast_json *ast_channel_snapshot_to_json( + const struct ast_channel_snapshot *snapshot, + const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref); - if (snapshot == NULL) { + if (snapshot == NULL + || (sanitize && sanitize->channel_snapshot + && sanitize->channel_snapshot(snapshot))) { return NULL; } @@ -817,8 +821,10 @@ int ast_channel_snapshot_caller_id_equal( strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0; } -static struct ast_json *channel_blob_to_json(struct stasis_message *message, - const char *type) +static struct ast_json *channel_blob_to_json( + struct stasis_message *message, + const char *type, + const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, out, NULL, ast_json_unref); struct ast_channel_blob *channel_blob = stasis_message_data(message); @@ -844,8 +850,13 @@ static struct ast_json *channel_blob_to_json(struct stasis_message *message, /* For global channel messages, the snapshot is optional */ if (snapshot) { - res |= ast_json_object_set(out, "channel", - ast_channel_snapshot_to_json(snapshot)); + struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize); + + if (!json_channel) { + return NULL; + } + + res |= ast_json_object_set(out, "channel", json_channel); } if (res != 0) { @@ -855,7 +866,9 @@ static struct ast_json *channel_blob_to_json(struct stasis_message *message, return ast_json_ref(out); } -static struct ast_json *dtmf_end_to_json(struct stasis_message *message) +static struct ast_json *dtmf_end_to_json( + struct stasis_message *message, + const struct stasis_message_sanitizer *sanitize) { struct ast_channel_blob *channel_blob = stasis_message_data(message); struct ast_json *blob = channel_blob->blob; @@ -863,43 +876,59 @@ static struct ast_json *dtmf_end_to_json(struct stasis_message *message) const char *direction = ast_json_string_get(ast_json_object_get(blob, "direction")); const struct timeval *tv = stasis_message_timestamp(message); + struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize); /* Only present received DTMF end events as JSON */ if (strcasecmp("Received", direction) != 0) { return NULL; } + if (!json_channel) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}", "type", "ChannelDtmfReceived", "timestamp", ast_json_timeval(*tv, NULL), "digit", ast_json_object_get(blob, "digit"), "duration_ms", ast_json_object_get(blob, "duration_ms"), - "channel", ast_channel_snapshot_to_json(snapshot)); + "channel", json_channel); } -static struct ast_json *user_event_to_json(struct stasis_message *message) +static struct ast_json *user_event_to_json( + struct stasis_message *message, + const struct stasis_message_sanitizer *sanitize) { struct ast_channel_blob *channel_blob = stasis_message_data(message); struct ast_json *blob = channel_blob->blob; struct ast_channel_snapshot *snapshot = channel_blob->snapshot; const struct timeval *tv = stasis_message_timestamp(message); + struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize); + + if (!json_channel) { + return NULL; + } return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}", "type", "ChannelUserevent", "timestamp", ast_json_timeval(*tv, NULL), "eventname", ast_json_object_get(blob, "eventname"), "userevent", blob, - "channel", ast_channel_snapshot_to_json(snapshot)); + "channel", json_channel); } -static struct ast_json *varset_to_json(struct stasis_message *message) +static struct ast_json *varset_to_json( + struct stasis_message *message, + const struct stasis_message_sanitizer *sanitize) { - return channel_blob_to_json(message, "ChannelVarset"); + return channel_blob_to_json(message, "ChannelVarset", sanitize); } -static struct ast_json *hangup_request_to_json(struct stasis_message *message) +static struct ast_json *hangup_request_to_json( + struct stasis_message *message, + const struct stasis_message_sanitizer *sanitize) { - return channel_blob_to_json(message, "ChannelHangupRequest"); + return channel_blob_to_json(message, "ChannelHangupRequest", sanitize); } /*! diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 096770a3d..81c4f15a3 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -237,7 +237,8 @@ static const char *endpoint_snapshot_get_id(struct stasis_message *message) struct ast_json *ast_endpoint_snapshot_to_json( - const struct ast_endpoint_snapshot *snapshot) + const struct ast_endpoint_snapshot *snapshot, + const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json *channel_array; @@ -264,7 +265,14 @@ struct ast_json *ast_endpoint_snapshot_to_json( channel_array = ast_json_object_get(json, "channel_ids"); ast_assert(channel_array != NULL); for (i = 0; i < snapshot->num_channels; ++i) { - int res = ast_json_array_append(channel_array, + int res; + + if (sanitize && sanitize->channel_id + && sanitize->channel_id(snapshot->channel_ids[i])) { + continue; + } + + res = ast_json_array_append(channel_array, ast_json_string_create(snapshot->channel_ids[i])); if (res != 0) { return NULL; diff --git a/main/stasis_message.c b/main/stasis_message.c index b25d1f25a..240845aff 100644 --- a/main/stasis_message.c +++ b/main/stasis_message.c @@ -161,7 +161,9 @@ struct ast_manager_event_blob *stasis_message_to_ami(struct stasis_message *msg) return INVOKE_VIRTUAL(to_ami, msg); } -struct ast_json *stasis_message_to_json(struct stasis_message *msg) +struct ast_json *stasis_message_to_json( + struct stasis_message *msg, + struct stasis_message_sanitizer *sanitize) { - return INVOKE_VIRTUAL(to_json, msg); + return INVOKE_VIRTUAL(to_json, msg, sanitize); } diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 7c4fed29b..e09bea6b5 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -605,7 +605,7 @@ void ast_ari_bridges_get(struct ast_variable *headers, } ast_ari_response_ok(response, - ast_bridge_snapshot_to_json(snapshot)); + ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer())); } void ast_ari_bridges_destroy(struct ast_variable *headers, @@ -656,7 +656,9 @@ void ast_ari_bridges_list(struct ast_variable *headers, while ((obj = ao2_iterator_next(&i))) { RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup); struct ast_bridge_snapshot *snapshot = stasis_message_data(msg); - if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) { + struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + + if (!json_bridge || ast_json_array_append(json, json_bridge)) { ast_ari_response_alloc_failed(response); return; } @@ -689,5 +691,5 @@ void ast_ari_bridges_create(struct ast_variable *headers, } ast_ari_response_ok(response, - ast_bridge_snapshot_to_json(snapshot)); + ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer())); } diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index dc0058fa5..75d56d924 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -593,7 +593,7 @@ void ast_ari_channels_get(struct ast_variable *headers, ast_assert(snapshot != NULL); ast_ari_response_ok(response, - ast_channel_snapshot_to_json(snapshot)); + ast_channel_snapshot_to_json(snapshot, NULL)); } void ast_ari_channels_hangup(struct ast_variable *headers, @@ -639,6 +639,7 @@ void ast_ari_channels_list(struct ast_variable *headers, RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ao2_iterator i; void *obj; + struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer(); cache = ast_channel_cache(); if (!cache) { @@ -661,14 +662,23 @@ void ast_ari_channels_list(struct ast_variable *headers, return; } - i = ao2_iterator_init(snapshots, 0); - while ((obj = ao2_iterator_next(&i))) { + for (i = ao2_iterator_init(snapshots, 0); + (obj = ao2_iterator_next(&i)); ao2_cleanup(obj)) { RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup); struct ast_channel_snapshot *snapshot = stasis_message_data(msg); - int r = ast_json_array_append( - json, ast_channel_snapshot_to_json(snapshot)); + int r; + + if (sanitize && sanitize->channel_snapshot + && sanitize->channel_snapshot(snapshot)) { + continue; + } + + r = ast_json_array_append( + json, ast_channel_snapshot_to_json(snapshot, NULL)); if (r != 0) { ast_ari_response_alloc_failed(response); + ao2_cleanup(obj); + ao2_iterator_destroy(&i); return; } } @@ -769,7 +779,7 @@ void ast_ari_channels_originate(struct ast_variable *headers, stasis_app_subscribe(args->app, uris, 1, NULL); } - ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot)); + ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL)); ast_channel_unref(chan); } diff --git a/res/ari/resource_endpoints.c b/res/ari/resource_endpoints.c index 14f9e0576..c37f4968e 100644 --- a/res/ari/resource_endpoints.c +++ b/res/ari/resource_endpoints.c @@ -31,6 +31,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/stasis.h" +#include "asterisk/stasis_app.h" #include "asterisk/stasis_endpoints.h" #include "asterisk/channel.h" @@ -69,8 +70,15 @@ void ast_ari_endpoints_list(struct ast_variable *headers, while ((obj = ao2_iterator_next(&i))) { RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup); struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg); - int r = ast_json_array_append( - json, ast_endpoint_snapshot_to_json(snapshot)); + struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + int r; + + if (!json_endpoint) { + return; + } + + r = ast_json_array_append( + json, json_endpoint); if (r != 0) { ast_ari_response_alloc_failed(response); return; @@ -121,14 +129,20 @@ void ast_ari_endpoints_list_by_tech(struct ast_variable *headers, while ((obj = ao2_iterator_next(&i))) { RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup); struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg); + struct ast_json *json_endpoint; int r; if (strcasecmp(args->tech, snapshot->tech) != 0) { continue; } + json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + if (!json_endpoint) { + continue; + } + r = ast_json_array_append( - json, ast_endpoint_snapshot_to_json(snapshot)); + json, json_endpoint); if (r != 0) { ast_ari_response_alloc_failed(response); return; @@ -151,7 +165,7 @@ void ast_ari_endpoints_get(struct ast_variable *headers, return; } - json = ast_endpoint_snapshot_to_json(snapshot); + json = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); if (!json) { ast_ari_response_alloc_failed(response); return; diff --git a/res/res_stasis.c b/res/res_stasis.c index e5fe1f691..e21941210 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -627,6 +627,7 @@ static int send_start_msg(struct app *app, struct ast_channel *chan, struct ast_json *json_args; int i; + struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer(); ast_assert(chan != NULL); @@ -636,11 +637,16 @@ static int send_start_msg(struct app *app, struct ast_channel *chan, return -1; } + if (sanitize && sanitize->channel_snapshot + && sanitize->channel_snapshot(snapshot)) { + return 0; + } + msg = ast_json_pack("{s: s, s: o, s: [], s: o}", "type", "StasisStart", "timestamp", ast_json_timeval(ast_tvnow(), NULL), "args", - "channel", ast_channel_snapshot_to_json(snapshot)); + "channel", ast_channel_snapshot_to_json(snapshot, NULL)); if (!msg) { return -1; } @@ -665,6 +671,7 @@ static int send_end_msg(struct app *app, struct ast_channel *chan) { RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref); RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); + struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer(); ast_assert(chan != NULL); @@ -674,10 +681,15 @@ static int send_end_msg(struct app *app, struct ast_channel *chan) return -1; } + if (sanitize && sanitize->channel_snapshot + && sanitize->channel_snapshot(snapshot)) { + return 0; + } + msg = ast_json_pack("{s: s, s: o, s: o}", "type", "StasisEnd", "timestamp", ast_json_timeval(ast_tvnow(), NULL), - "channel", ast_channel_snapshot_to_json(snapshot)); + "channel", ast_channel_snapshot_to_json(snapshot, NULL)); if (!msg) { return -1; } @@ -1153,6 +1165,34 @@ static int unload_module(void) return 0; } +/* \brief Sanitization callback for channel snapshots */ +static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot) +{ + if (!snapshot || !(snapshot->tech_properties & AST_CHAN_TP_INTERNAL)) { + return 0; + } + return 1; +} + +/* \brief Sanitization callback for channel unique IDs */ +static int channel_id_sanitizer(const char *id) +{ + RAII_VAR(struct ast_channel_snapshot *, snapshot, ast_channel_snapshot_get_latest(id), ao2_cleanup); + + return channel_snapshot_sanitizer(snapshot); +} + +/* \brief Sanitization callbacks for communication to Stasis applications */ +struct stasis_message_sanitizer app_sanitizer = { + .channel_id = channel_id_sanitizer, + .channel_snapshot = channel_snapshot_sanitizer, +}; + +struct stasis_message_sanitizer *stasis_app_get_sanitizer(void) +{ + return &app_sanitizer; +} + static int load_module(void) { apps_registry = ao2_container_alloc(APPS_NUM_BUCKETS, app_hash, app_compare); diff --git a/res/stasis/app.c b/res/stasis/app.c index 99af6ee57..433d3adb5 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -276,7 +276,7 @@ static void sub_default_handler(void *data, struct stasis_subscription *sub, } /* By default, send any message that has a JSON representation */ - json = stasis_message_to_json(message); + json = stasis_message_to_json(message, stasis_app_get_sanitizer()); if (!json) { return; } @@ -295,10 +295,16 @@ static struct ast_json *simple_channel_event( struct ast_channel_snapshot *snapshot, const struct timeval *tv) { + struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + + if (!json_channel) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: o}", "type", type, "timestamp", ast_json_timeval(*tv, NULL), - "channel", ast_channel_snapshot_to_json(snapshot)); + "channel", json_channel); } static struct ast_json *channel_created_event( @@ -312,12 +318,18 @@ static struct ast_json *channel_destroyed_event( struct ast_channel_snapshot *snapshot, const struct timeval *tv) { + struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + + if (!json_channel) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}", "type", "ChannelDestroyed", "timestamp", ast_json_timeval(*tv, NULL), "cause", snapshot->hangupcause, "cause_txt", ast_cause2str(snapshot->hangupcause), - "channel", ast_channel_snapshot_to_json(snapshot)); + "channel", json_channel); } static struct ast_json *channel_state_change_event( @@ -353,6 +365,7 @@ static struct ast_json *channel_dialplan( const struct timeval *tv) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json *json_channel; /* No Newexten event on cache clear or first event */ if (!old_snapshot || !new_snapshot) { @@ -368,12 +381,17 @@ static struct ast_json *channel_dialplan( return NULL; } + json_channel = ast_channel_snapshot_to_json(new_snapshot, stasis_app_get_sanitizer()); + if (!json_channel) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: s, s: s, s: o}", "type", "ChannelDialplan", "timestamp", ast_json_timeval(*tv, NULL), "dialplan_app", new_snapshot->appl, "dialplan_app_data", new_snapshot->data, - "channel", ast_channel_snapshot_to_json(new_snapshot)); + "channel", json_channel); } static struct ast_json *channel_callerid( @@ -382,6 +400,7 @@ static struct ast_json *channel_callerid( const struct timeval *tv) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json *json_channel; /* No NewCallerid event on cache clear or first event */ if (!old_snapshot || !new_snapshot) { @@ -392,13 +411,18 @@ static struct ast_json *channel_callerid( return NULL; } + json_channel = ast_channel_snapshot_to_json(new_snapshot, stasis_app_get_sanitizer()); + if (!json_channel) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}", "type", "ChannelCallerId", "timestamp", ast_json_timeval(*tv, NULL), "caller_presentation", new_snapshot->caller_pres, "caller_presentation_txt", ast_describe_caller_presentation( new_snapshot->caller_pres), - "channel", ast_channel_snapshot_to_json(new_snapshot)); + "channel", json_channel); } static channel_snapshot_monitor channel_monitors[] = { @@ -448,10 +472,16 @@ static struct ast_json *simple_endpoint_event( struct ast_endpoint_snapshot *snapshot, const struct timeval *tv) { + struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + + if (!json_endpoint) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: o}", "type", type, "timestamp", ast_json_timeval(*tv, NULL), - "endpoint", ast_endpoint_snapshot_to_json(snapshot)); + "endpoint", json_endpoint); } static void sub_endpoint_update_handler(void *data, @@ -489,10 +519,15 @@ static struct ast_json *simple_bridge_event( struct ast_bridge_snapshot *snapshot, const struct timeval *tv) { + struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + if (!json_bridge) { + return NULL; + } + return ast_json_pack("{s: s, s: o, s: o}", "type", type, "timestamp", ast_json_timeval(*tv, NULL), - "bridge", ast_bridge_snapshot_to_json(snapshot)); + "bridge", json_bridge); } static void sub_bridge_update_handler(void *data, @@ -521,7 +556,7 @@ static void sub_bridge_update_handler(void *data, if (!new_snapshot) { json = simple_bridge_event("BridgeDestroyed", old_snapshot, tv); } else if (!old_snapshot) { - json = simple_bridge_event("BridgeCreated", old_snapshot, tv); + json = simple_bridge_event("BridgeCreated", new_snapshot, tv); } if (!json) { |