diff options
author | Joshua Colp <jcolp@digium.com> | 2016-04-26 04:57:07 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2016-04-26 04:57:07 -0500 |
commit | 9d8f59aaf286c2177cdc051e25a50b05bfeacb44 (patch) | |
tree | 220f4b2bc83c663798cc5a01dfc080de24ef1987 /main | |
parent | 4efc6b43155452b2f9cb5f96c7aea4cdfc1a84d1 (diff) | |
parent | ebf0724a8355e060764f1f6a4b92abb071eb9af6 (diff) |
Merge changes from topic 'system_stress_patches' into 13
* changes:
test_message.c: Wait longer in case dialplan also processes the test message.
Manager: Short circuit AMI message processing.
manager.c: Eliminate most RAII_VAR usage.
manager_channels.c: Fix allocation failure crash.
Diffstat (limited to 'main')
-rw-r--r-- | main/manager.c | 202 | ||||
-rw-r--r-- | main/manager_channels.c | 24 | ||||
-rw-r--r-- | main/stasis_message.c | 35 |
3 files changed, 194 insertions, 67 deletions
diff --git a/main/manager.c b/main/manager.c index 7c2155015..ba261e8e9 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1541,6 +1541,17 @@ static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook); /*! \brief A container of event documentation nodes */ static AO2_GLOBAL_OBJ_STATIC(event_docs); +static int __attribute__((format(printf, 9, 0))) __manager_event_sessions( + struct ao2_container *sessions, + int category, + const char *event, + int chancount, + struct ast_channel **chans, + const char *file, + int line, + const char *func, + const char *fmt, + ...); static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters); static int match_filter(struct mansession *s, char *eventdata); @@ -1679,37 +1690,75 @@ struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_excl return res; } +#define manager_event_sessions(sessions, category, event, contents , ...) \ + __manager_event_sessions(sessions, category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__) + +#define any_manager_listeners(sessions) \ + ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks)) + static void manager_default_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup); + struct ao2_container *sessions; + struct ast_manager_event_blob *ev; - ev = stasis_message_to_ami(message); + if (!stasis_message_can_be_ami(message)) { + /* Not an AMI message; disregard */ + return; + } + + sessions = ao2_global_obj_ref(mgr_sessions); + if (!any_manager_listeners(sessions)) { + /* Nobody is listening */ + ao2_cleanup(sessions); + return; + } - if (ev == NULL) { - /* Not and AMI message; disregard */ + ev = stasis_message_to_ami(message); + if (!ev) { + /* Conversion failure */ + ao2_cleanup(sessions); return; } - manager_event(ev->event_flags, ev->manager_event, "%s", - ev->extra_fields); + manager_event_sessions(sessions, ev->event_flags, ev->manager_event, + "%s", ev->extra_fields); + ao2_ref(ev, -1); + ao2_cleanup(sessions); } static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - struct ast_json_payload *payload = stasis_message_data(message); - int class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type")); - const char *type = ast_json_string_get(ast_json_object_get(payload->json, "type")); - struct ast_json *event = ast_json_object_get(payload->json, "event"); - RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free); + struct ast_json_payload *payload; + int class_type; + const char *type; + struct ast_json *event; + struct ast_str *event_buffer; + struct ao2_container *sessions; + + sessions = ao2_global_obj_ref(mgr_sessions); + if (!any_manager_listeners(sessions)) { + /* Nobody is listening */ + ao2_cleanup(sessions); + return; + } + + payload = stasis_message_data(message); + class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type")); + type = ast_json_string_get(ast_json_object_get(payload->json, "type")); + event = ast_json_object_get(payload->json, "event"); event_buffer = ast_manager_str_from_json_object(event, NULL); if (!event_buffer) { ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type); + ao2_cleanup(sessions); return; } - manager_event(class_type, type, "%s", ast_str_buffer(event_buffer)); + manager_event_sessions(sessions, class_type, type, + "%s", ast_str_buffer(event_buffer)); + ast_free(event_buffer); + ao2_cleanup(sessions); } void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj) @@ -4698,7 +4747,7 @@ static int action_blind_transfer(struct mansession *s, const struct message *m) const char *name = astman_get_header(m, "Channel"); const char *exten = astman_get_header(m, "Exten"); const char *context = astman_get_header(m, "Context"); - RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup); + struct ast_channel *chan; if (ast_strlen_zero(name)) { astman_send_error(s, m, "No channel specified"); @@ -4735,6 +4784,7 @@ static int action_blind_transfer(struct mansession *s, const struct message *m) break; } + ast_channel_unref(chan); return 0; } @@ -5907,7 +5957,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m const char *actionid = astman_get_header(m, "ActionID"); char idText[256]; int numchans = 0; - RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup); + struct ao2_container *channels; struct ao2_iterator it_chans; struct stasis_message *msg; @@ -5917,7 +5967,8 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m idText[0] = '\0'; } - if (!(channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) { + channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()); + if (!channels) { astman_send_error(s, m, "Could not get cached channels"); return 0; } @@ -5969,6 +6020,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m astman_send_list_complete_start(s, m, "CoreShowChannelsComplete", numchans); astman_send_list_complete_end(s); + ao2_ref(channels, -1); return 0; } @@ -6597,11 +6649,10 @@ static int append_event(const char *str, int category) static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan) { - RAII_VAR(struct varshead *, vars, NULL, ao2_cleanup); + struct varshead *vars; struct ast_var_t *var; vars = ast_channel_get_manager_vars(chan); - if (!vars) { return; } @@ -6609,62 +6660,67 @@ static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan) AST_LIST_TRAVERSE(vars, var, entries) { ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value); } + ao2_ref(vars, -1); } /* XXX see if can be moved inside the function */ AST_THREADSTORAGE(manager_event_buf); #define MANAGER_EVENT_BUF_INITSIZE 256 -int __ast_manager_event_multichan(int category, const char *event, int chancount, - struct ast_channel **chans, const char *file, int line, const char *func, - const char *fmt, ...) +static int __attribute__((format(printf, 9, 0))) __manager_event_sessions_va( + struct ao2_container *sessions, + int category, + const char *event, + int chancount, + struct ast_channel **chans, + const char *file, + int line, + const char *func, + const char *fmt, + va_list ap) { - RAII_VAR(struct ao2_container *, sessions, ao2_global_obj_ref(mgr_sessions), ao2_cleanup); - struct mansession_session *session; - struct manager_custom_hook *hook; struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING); const char *cat_str; - va_list ap; struct timeval now; struct ast_str *buf; int i; - if (!(sessions && ao2_container_count(sessions)) && AST_RWLIST_EMPTY(&manager_hooks)) { - return 0; - } - - if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) { + buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE); + if (!buf) { return -1; } cat_str = authority_to_str(category, &auth); ast_str_set(&buf, 0, - "Event: %s\r\nPrivilege: %s\r\n", - event, cat_str); + "Event: %s\r\n" + "Privilege: %s\r\n", + event, cat_str); if (timestampevents) { now = ast_tvnow(); ast_str_append(&buf, 0, - "Timestamp: %ld.%06lu\r\n", - (long)now.tv_sec, (unsigned long) now.tv_usec); + "Timestamp: %ld.%06lu\r\n", + (long)now.tv_sec, (unsigned long) now.tv_usec); } if (manager_debug) { static int seq; + ast_str_append(&buf, 0, - "SequenceNumber: %d\r\n", - ast_atomic_fetchadd_int(&seq, 1)); + "SequenceNumber: %d\r\n", + ast_atomic_fetchadd_int(&seq, 1)); ast_str_append(&buf, 0, - "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func); + "File: %s\r\n" + "Line: %d\r\n" + "Func: %s\r\n", + file, line, func); } if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_str_append(&buf, 0, - "SystemName: %s\r\n", - ast_config_AST_SYSTEM_NAME); + "SystemName: %s\r\n", + ast_config_AST_SYSTEM_NAME); } - va_start(ap, fmt); ast_str_append_va(&buf, 0, fmt, ap); - va_end(ap); for (i = 0; i < chancount; i++) { append_channel_vars(&buf, chans[i]); } @@ -6675,9 +6731,11 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount /* Wake up any sleeping sessions */ if (sessions) { - struct ao2_iterator i; - i = ao2_iterator_init(sessions, 0); - while ((session = ao2_iterator_next(&i))) { + struct ao2_iterator iter; + struct mansession_session *session; + + iter = ao2_iterator_init(sessions, 0); + while ((session = ao2_iterator_next(&iter))) { ao2_lock(session); if (session->waiting_thread != AST_PTHREADT_NULL) { pthread_kill(session->waiting_thread, SIGURG); @@ -6692,10 +6750,12 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount ao2_unlock(session); unref_mansession(session); } - ao2_iterator_destroy(&i); + ao2_iterator_destroy(&iter); } if (category != EVENT_FLAG_SHUTDOWN && !AST_RWLIST_EMPTY(&manager_hooks)) { + struct manager_custom_hook *hook; + AST_RWLIST_RDLOCK(&manager_hooks); AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) { hook->helper(category, event, ast_str_buffer(buf)); @@ -6706,6 +6766,50 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount return 0; } +static int __attribute__((format(printf, 9, 0))) __manager_event_sessions( + struct ao2_container *sessions, + int category, + const char *event, + int chancount, + struct ast_channel **chans, + const char *file, + int line, + const char *func, + const char *fmt, + ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = __manager_event_sessions_va(sessions, category, event, chancount, chans, + file, line, func, fmt, ap); + va_end(ap); + return res; +} + +int __ast_manager_event_multichan(int category, const char *event, int chancount, + struct ast_channel **chans, const char *file, int line, const char *func, + const char *fmt, ...) +{ + struct ao2_container *sessions = ao2_global_obj_ref(mgr_sessions); + va_list ap; + int res; + + if (!any_manager_listeners(sessions)) { + /* Nobody is listening */ + ao2_cleanup(sessions); + return 0; + } + + va_start(ap, fmt); + res = __manager_event_sessions_va(sessions, category, event, chancount, chans, + file, line, func, fmt, ap); + va_end(ap); + ao2_cleanup(sessions); + return res; +} + /*! \brief * support functions to register/unregister AMI action handlers, */ @@ -9184,6 +9288,7 @@ int ast_str_append_event_header(struct ast_str **fields_string, static void manager_event_blob_dtor(void *obj) { struct ast_manager_event_blob *ev = obj; + ast_string_field_free_memory(ev); } @@ -9195,18 +9300,19 @@ ast_manager_event_blob_create( const char *extra_fields_fmt, ...) { - RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup); + struct ast_manager_event_blob *ev; va_list argp; ast_assert(extra_fields_fmt != NULL); ast_assert(manager_event != NULL); - ev = ao2_alloc(sizeof(*ev), manager_event_blob_dtor); + ev = ao2_alloc_options(sizeof(*ev), manager_event_blob_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!ev) { return NULL; } if (ast_string_field_init(ev, 20)) { + ao2_ref(ev, -1); return NULL; } @@ -9214,10 +9320,8 @@ ast_manager_event_blob_create( ev->event_flags = event_flags; va_start(argp, extra_fields_fmt); - ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, - argp); + ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, argp); va_end(argp); - ao2_ref(ev, +1); return ev; } diff --git a/main/manager_channels.c b/main/manager_channels.c index adef639e8..ef71c65b1 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -697,28 +697,33 @@ static void channel_hangup_request_cb(void *data, struct stasis_message *message) { struct ast_channel_blob *obj = stasis_message_data(message); - RAII_VAR(struct ast_str *, extra, NULL, ast_free); - RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); + struct ast_str *extra; + struct ast_str *channel_event_string; struct ast_json *cause; int is_soft; char *manager_event = "HangupRequest"; + if (!obj->snapshot) { + /* No snapshot? Likely an earlier allocation failure creating it. */ + return; + } + extra = ast_str_create(20); if (!extra) { return; } channel_event_string = ast_manager_build_channel_state_string(obj->snapshot); - if (!channel_event_string) { + ast_free(extra); return; } cause = ast_json_object_get(obj->blob, "cause"); if (cause) { ast_str_append(&extra, 0, - "Cause: %jd\r\n", - ast_json_integer_get(cause)); + "Cause: %jd\r\n", + ast_json_integer_get(cause)); } is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft")); @@ -727,9 +732,12 @@ static void channel_hangup_request_cb(void *data, } manager_event(EVENT_FLAG_CALL, manager_event, - "%s%s", - ast_str_buffer(channel_event_string), - ast_str_buffer(extra)); + "%s%s", + ast_str_buffer(channel_event_string), + ast_str_buffer(extra)); + + ast_free(channel_event_string); + ast_free(extra); } static void channel_chanspy_stop_cb(void *data, struct stasis_subscription *sub, diff --git a/main/stasis_message.c b/main/stasis_message.c index c797cdfa0..99721ef3c 100644 --- a/main/stasis_message.c +++ b/main/stasis_message.c @@ -170,17 +170,17 @@ const struct timeval *stasis_message_timestamp(const struct stasis_message *msg) return &msg->timestamp; } -#define INVOKE_VIRTUAL(fn, ...) \ - ({ \ - if (msg == NULL) { \ - return NULL; \ - } \ - ast_assert(msg->type != NULL); \ +#define INVOKE_VIRTUAL(fn, ...) \ + ({ \ + if (!msg) { \ + return NULL; \ + } \ + ast_assert(msg->type != NULL); \ ast_assert(msg->type->vtable != NULL); \ - if (msg->type->vtable->fn == NULL) { \ - return NULL; \ - } \ - msg->type->vtable->fn(__VA_ARGS__); \ + if (!msg->type->vtable->fn) { \ + return NULL; \ + } \ + msg->type->vtable->fn(__VA_ARGS__); \ }) struct ast_manager_event_blob *stasis_message_to_ami(struct stasis_message *msg) @@ -199,3 +199,18 @@ struct ast_event *stasis_message_to_event(struct stasis_message *msg) { return INVOKE_VIRTUAL(to_event, msg); } + +#define HAS_VIRTUAL(fn, msg) \ + ({ \ + if (!msg) { \ + return 0; \ + } \ + ast_assert(msg->type != NULL); \ + ast_assert(msg->type->vtable != NULL); \ + !!msg->type->vtable->fn; \ + }) + +int stasis_message_can_be_ami(struct stasis_message *msg) +{ + return HAS_VIRTUAL(to_ami, msg); +} |