2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
19 * The Initial Developer of the Original Code is
20 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
26 * Anthony Minessale II <anthm@freeswitch.org>
27 * Michael Jerris <mike@jerris.com>
28 * Paul D. Tinsley <pdt at jackhammer.org>
29 * William King <william.king@quentustech.com>
30 * Raymond Chandler <intralanman@freeswitch.org>
32 * switch_event.c -- Event System
37 #include "private/switch_core_pvt.h"
38 #include <switch_event.h>
43 //#define SWITCH_EVENT_RECYCLE
44 #define DISPATCH_QUEUE_LEN 10000
45 //#define DEBUG_DISPATCH_QUEUES
47 /*! \brief A node to store binded events */
48 struct switch_event_node
{
49 /*! the id of the node */
51 /*! the event id enumeration to bind to */
52 switch_event_types_t event_id
;
53 /*! the event subclass to bind to for custom events */
55 /*! a callback function to execute when the event is triggered */
56 switch_event_callback_t callback
;
59 struct switch_event_node
*next
;
62 /*! \brief A registered custom event subclass */
63 struct switch_event_subclass
{
64 /*! the owner of the subclass */
66 /*! the subclass name */
68 /*! the subclass was reserved by a listener so it's ok for a module to reserve it still */
74 switch_event_channel_id_t ID
;
75 switch_thread_rwlock_t
*rwlock
;
77 switch_hash_t
*perm_hash
;
78 switch_hash_t
*lahash
;
79 switch_mutex_t
*lamutex
;
80 } event_channel_manager
;
82 #define MAX_DISPATCH_VAL 64
83 static unsigned int MAX_DISPATCH
= MAX_DISPATCH_VAL
;
84 static unsigned int SOFT_MAX_DISPATCH
= 0;
85 static char guess_ip_v4
[80] = "";
86 static char guess_ip_v6
[80] = "";
87 static switch_event_node_t
*EVENT_NODES
[SWITCH_EVENT_ALL
+ 1] = { NULL
};
88 static switch_thread_rwlock_t
*RWLOCK
= NULL
;
89 static switch_mutex_t
*BLOCK
= NULL
;
90 static switch_mutex_t
*POOL_LOCK
= NULL
;
91 static switch_memory_pool_t
*RUNTIME_POOL
= NULL
;
92 static switch_memory_pool_t
*THRUNTIME_POOL
= NULL
;
93 static switch_thread_t
*EVENT_DISPATCH_QUEUE_THREADS
[MAX_DISPATCH_VAL
] = { 0 };
94 static uint8_t EVENT_DISPATCH_QUEUE_RUNNING
[MAX_DISPATCH_VAL
] = { 0 };
95 static switch_queue_t
*EVENT_DISPATCH_QUEUE
= NULL
;
96 static switch_queue_t
*EVENT_CHANNEL_DISPATCH_QUEUE
= NULL
;
97 static switch_mutex_t
*EVENT_QUEUE_MUTEX
= NULL
;
98 static switch_mutex_t
*CUSTOM_HASH_MUTEX
= NULL
;
99 static switch_hash_t
*CUSTOM_HASH
= NULL
;
100 static int THREAD_COUNT
= 0;
101 static int DISPATCH_THREAD_COUNT
= 0;
102 static int EVENT_CHANNEL_DISPATCH_THREAD_COUNT
= 0;
103 static int EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 0;
104 static int SYSTEM_RUNNING
= 0;
105 static uint64_t EVENT_SEQUENCE_NR
= 0;
106 #ifdef SWITCH_EVENT_RECYCLE
107 static switch_queue_t
*EVENT_RECYCLE_QUEUE
= NULL
;
108 static switch_queue_t
*EVENT_HEADER_RECYCLE_QUEUE
= NULL
;
111 static void unsub_all_switch_event_channel(void);
113 static char *my_dup(const char *s
)
115 size_t len
= strlen(s
) + 1;
116 void *new = malloc(len
);
119 return (char *) memcpy(new, s
, len
);
123 #define ALLOC(size) malloc(size)
126 #define DUP(str) my_dup(str)
129 #define FREE(ptr) switch_safe_free(ptr)
132 static void free_header(switch_event_header_t
**header
);
134 /* make sure this is synced with the switch_event_types_t enum in switch_types.h
135 also never put any new ones before EVENT_ALL
137 static char *EVENT_NAMES
[] = {
146 "CHANNEL_HANGUP_COMPLETE",
148 "CHANNEL_EXECUTE_COMPLETE",
154 "CHANNEL_PROGRESS_MEDIA",
158 "CHANNEL_APPLICATION",
197 "PHONE_FEATURE_SUBSCRIBE",
205 "CLIENT_DISCONNECTED",
206 "SERVER_DISCONNECTED",
222 "CONFERENCE_DATA_QUERY",
229 "SHUTDOWN_REQUESTED",
233 static int switch_events_match(switch_event_t
*event
, switch_event_node_t
*node
)
237 if (node
->event_id
== SWITCH_EVENT_ALL
) {
240 if (!node
->subclass_name
) {
245 if (match
|| event
->event_id
== node
->event_id
) {
247 if (event
->subclass_name
&& node
->subclass_name
) {
248 if (!strncasecmp(node
->subclass_name
, "file:", 5)) {
250 if ((file_header
= switch_event_get_header(event
, "file")) != 0) {
251 match
= !strcmp(node
->subclass_name
+ 5, file_header
) ? 1 : 0;
253 } else if (!strncasecmp(node
->subclass_name
, "func:", 5)) {
255 if ((func_header
= switch_event_get_header(event
, "function")) != 0) {
256 match
= !strcmp(node
->subclass_name
+ 5, func_header
) ? 1 : 0;
258 } else if (event
->subclass_name
&& node
->subclass_name
) {
259 match
= !strcmp(event
->subclass_name
, node
->subclass_name
) ? 1 : 0;
261 } else if ((event
->subclass_name
&& !node
->subclass_name
) || (!event
->subclass_name
&& !node
->subclass_name
)) {
272 static void *SWITCH_THREAD_FUNC
switch_event_deliver_thread(switch_thread_t
*thread
, void *obj
)
274 switch_event_t
*event
= (switch_event_t
*) obj
;
276 switch_event_deliver(&event
);
281 static void switch_event_deliver_thread_pool(switch_event_t
**event
)
283 switch_thread_data_t
*td
;
285 td
= malloc(sizeof(*td
));
289 td
->func
= switch_event_deliver_thread
;
295 switch_thread_pool_launch_thread(&td
);
299 static void *SWITCH_THREAD_FUNC
switch_event_dispatch_thread(switch_thread_t
*thread
, void *obj
)
301 switch_queue_t
*queue
= (switch_queue_t
*) obj
;
304 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
306 DISPATCH_THREAD_COUNT
++;
308 for (my_id
= 0; my_id
< MAX_DISPATCH_VAL
; my_id
++) {
309 if (EVENT_DISPATCH_QUEUE_THREADS
[my_id
] == thread
) {
314 if ( my_id
>= MAX_DISPATCH_VAL
) {
315 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
319 EVENT_DISPATCH_QUEUE_RUNNING
[my_id
] = 1;
320 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
325 switch_event_t
*event
= NULL
;
327 if (!SYSTEM_RUNNING
) {
331 if (switch_queue_pop(queue
, &pop
) != SWITCH_STATUS_SUCCESS
) {
339 event
= (switch_event_t
*) pop
;
340 switch_event_deliver(&event
);
345 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
346 EVENT_DISPATCH_QUEUE_RUNNING
[my_id
] = 0;
348 DISPATCH_THREAD_COUNT
--;
349 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
351 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Dispatch Thread %d Ended.\n", my_id
);
356 static int PENDING
= 0;
358 static switch_status_t
switch_event_queue_dispatch_event(switch_event_t
**eventp
)
361 switch_event_t
*event
= *eventp
;
363 if (!SYSTEM_RUNNING
) {
364 return SWITCH_STATUS_FALSE
;
370 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
372 if (!PENDING
&& switch_queue_size(EVENT_DISPATCH_QUEUE
) > (unsigned int)(DISPATCH_QUEUE_LEN
* DISPATCH_THREAD_COUNT
)) {
373 if (SOFT_MAX_DISPATCH
+ 1 < MAX_DISPATCH
) {
379 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
382 if (SOFT_MAX_DISPATCH
+ 1 < MAX_DISPATCH
) {
383 switch_event_launch_dispatch_threads(SOFT_MAX_DISPATCH
+ 1);
386 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
388 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
392 switch_queue_push(EVENT_DISPATCH_QUEUE
, event
);
397 return SWITCH_STATUS_SUCCESS
;
400 SWITCH_DECLARE(void) switch_event_deliver(switch_event_t
**event
)
402 switch_event_types_t e
;
403 switch_event_node_t
*node
;
405 if (SYSTEM_RUNNING
) {
406 switch_thread_rwlock_rdlock(RWLOCK
);
407 for (e
= (*event
)->event_id
;; e
= SWITCH_EVENT_ALL
) {
408 for (node
= EVENT_NODES
[e
]; node
; node
= node
->next
) {
409 if (switch_events_match(*event
, node
)) {
410 (*event
)->bind_user_data
= node
->user_data
;
411 node
->callback(*event
);
415 if (e
== SWITCH_EVENT_ALL
) {
419 switch_thread_rwlock_unlock(RWLOCK
);
422 switch_event_destroy(event
);
425 SWITCH_DECLARE(switch_status_t
) switch_event_running(void)
427 return SYSTEM_RUNNING
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
430 SWITCH_DECLARE(const char *) switch_event_name(switch_event_types_t event
)
432 switch_assert(BLOCK
!= NULL
);
433 switch_assert(RUNTIME_POOL
!= NULL
);
435 return EVENT_NAMES
[event
];
438 SWITCH_DECLARE(switch_status_t
) switch_name_event(const char *name
, switch_event_types_t
*type
)
440 switch_event_types_t x
;
441 switch_assert(BLOCK
!= NULL
);
442 switch_assert(RUNTIME_POOL
!= NULL
);
444 for (x
= 0; x
<= SWITCH_EVENT_ALL
; x
++) {
445 if ((strlen(name
) > 13 && !strcasecmp(name
+ 13, EVENT_NAMES
[x
])) || !strcasecmp(name
, EVENT_NAMES
[x
])) {
447 return SWITCH_STATUS_SUCCESS
;
451 return SWITCH_STATUS_FALSE
;
454 SWITCH_DECLARE(switch_status_t
) switch_event_free_subclass_detailed(const char *owner
, const char *subclass_name
)
456 switch_event_subclass_t
*subclass
;
457 switch_status_t status
= SWITCH_STATUS_FALSE
;
459 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
461 switch_assert(RUNTIME_POOL
!= NULL
);
462 switch_assert(CUSTOM_HASH
!= NULL
);
464 if ((subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
465 if (!strcmp(owner
, subclass
->owner
)) {
466 switch_thread_rwlock_wrlock(RWLOCK
);
467 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Subclass reservation deleted for %s:%s\n", owner
, subclass_name
);
468 switch_core_hash_delete(CUSTOM_HASH
, subclass_name
);
469 FREE(subclass
->owner
);
470 FREE(subclass
->name
);
472 status
= SWITCH_STATUS_SUCCESS
;
473 switch_thread_rwlock_unlock(RWLOCK
);
475 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Subclass reservation %s inuse by listeners, detaching..\n", subclass_name
);
480 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
485 SWITCH_DECLARE(switch_status_t
) switch_event_reserve_subclass_detailed(const char *owner
, const char *subclass_name
)
487 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
488 switch_event_subclass_t
*subclass
;
490 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
492 switch_assert(RUNTIME_POOL
!= NULL
);
493 switch_assert(CUSTOM_HASH
!= NULL
);
495 if ((subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
496 /* a listener reserved it for us, now we can lock it so nobody else can have it */
497 if (subclass
->bind
) {
499 switch_goto_status(SWITCH_STATUS_SUCCESS
, end
);
501 switch_goto_status(SWITCH_STATUS_INUSE
, end
);
504 switch_zmalloc(subclass
, sizeof(*subclass
));
506 subclass
->owner
= DUP(owner
);
507 subclass
->name
= DUP(subclass_name
);
509 status
= switch_core_hash_insert(CUSTOM_HASH
, subclass
->name
, subclass
);
511 if (status
!= SWITCH_STATUS_SUCCESS
) {
512 free(subclass
->owner
);
513 free(subclass
->name
);
519 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
524 SWITCH_DECLARE(void) switch_core_memory_reclaim_events(void)
526 #ifdef SWITCH_EVENT_RECYCLE
530 size
= switch_queue_size(EVENT_RECYCLE_QUEUE
);
532 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Returning %d recycled event(s) %d bytes\n", size
, (int) sizeof(switch_event_t
) * size
);
533 size
= switch_queue_size(EVENT_HEADER_RECYCLE_QUEUE
);
534 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Returning %d recycled event header(s) %d bytes\n",
535 size
, (int) sizeof(switch_event_header_t
) * size
);
537 while (switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
540 while (switch_queue_trypop(EVENT_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
549 SWITCH_DECLARE(switch_status_t
) switch_event_shutdown(void)
553 switch_hash_index_t
*hi
;
557 if (switch_core_test_flag(SCF_MINIMAL
)) {
558 return SWITCH_STATUS_SUCCESS
;
561 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
563 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
565 unsub_all_switch_event_channel();
567 if (EVENT_CHANNEL_DISPATCH_QUEUE
) {
568 switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE
, NULL
);
569 switch_queue_interrupt_all(EVENT_CHANNEL_DISPATCH_QUEUE
);
572 if (runtime
.events_use_dispatch
) {
573 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Stopping dispatch queues\n");
575 for(x
= 0; x
< (uint32_t)DISPATCH_THREAD_COUNT
; x
++) {
576 switch_queue_trypush(EVENT_DISPATCH_QUEUE
, NULL
);
580 switch_queue_interrupt_all(EVENT_DISPATCH_QUEUE
);
582 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Stopping dispatch threads\n");
584 for(x
= 0; x
< (uint32_t)MAX_DISPATCH
; x
++) {
585 if (EVENT_DISPATCH_QUEUE_THREADS
[x
]) {
587 switch_thread_join(&st
, EVENT_DISPATCH_QUEUE_THREADS
[x
]);
593 while (x
< 100 && THREAD_COUNT
) {
594 switch_yield(100000);
595 if (THREAD_COUNT
== last
) {
601 if (runtime
.events_use_dispatch
) {
603 switch_event_t
*event
= NULL
;
605 while (switch_queue_trypop(EVENT_DISPATCH_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
606 event
= (switch_event_t
*) pop
;
607 switch_event_destroy(&event
);
611 for (hi
= switch_core_hash_first(CUSTOM_HASH
); hi
; hi
= switch_core_hash_next(&hi
)) {
612 switch_event_subclass_t
*subclass
;
613 switch_core_hash_this(hi
, &var
, NULL
, &val
);
614 if ((subclass
= (switch_event_subclass_t
*) val
)) {
615 FREE(subclass
->name
);
616 FREE(subclass
->owner
);
621 switch_core_hash_destroy(&event_channel_manager
.lahash
);
622 switch_core_hash_destroy(&event_channel_manager
.hash
);
623 switch_core_hash_destroy(&event_channel_manager
.perm_hash
);
625 switch_core_hash_destroy(&CUSTOM_HASH
);
626 switch_core_memory_reclaim_events();
628 return SWITCH_STATUS_SUCCESS
;
631 static void check_dispatch(void)
633 if (!EVENT_DISPATCH_QUEUE
) {
634 switch_mutex_lock(BLOCK
);
636 if (!EVENT_DISPATCH_QUEUE
) {
637 switch_queue_create(&EVENT_DISPATCH_QUEUE
, DISPATCH_QUEUE_LEN
* MAX_DISPATCH
, THRUNTIME_POOL
);
638 switch_event_launch_dispatch_threads(1);
640 while (!THREAD_COUNT
) {
644 switch_mutex_unlock(BLOCK
);
650 SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max
)
652 switch_threadattr_t
*thd_attr
;
655 uint32_t sanity
= 200;
657 switch_memory_pool_t
*pool
= RUNTIME_POOL
;
661 if (max
> MAX_DISPATCH
) {
665 if (max
< SOFT_MAX_DISPATCH
) {
669 for (index
= SOFT_MAX_DISPATCH
; index
< max
&& index
< MAX_DISPATCH
; index
++) {
670 if (EVENT_DISPATCH_QUEUE_THREADS
[index
]) {
674 switch_threadattr_create(&thd_attr
, pool
);
675 switch_threadattr_stacksize_set(thd_attr
, SWITCH_THREAD_STACKSIZE
);
676 switch_threadattr_priority_set(thd_attr
, SWITCH_PRI_REALTIME
);
677 switch_thread_create(&EVENT_DISPATCH_QUEUE_THREADS
[index
], thd_attr
, switch_event_dispatch_thread
, EVENT_DISPATCH_QUEUE
, pool
);
678 while(--sanity
&& !EVENT_DISPATCH_QUEUE_RUNNING
[index
]) switch_yield(10000);
681 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Create event dispatch thread %d\n", index
);
683 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Create additional event dispatch thread %d\n", index
);
688 SOFT_MAX_DISPATCH
= index
;
691 SWITCH_DECLARE(switch_status_t
) switch_event_init(switch_memory_pool_t
*pool
)
694 /* don't need any more dispatch threads than we have CPU's*/
695 MAX_DISPATCH
= (switch_core_cpu_count() / 2) + 1;
696 if (MAX_DISPATCH
< 2) {
700 switch_assert(pool
!= NULL
);
701 THRUNTIME_POOL
= RUNTIME_POOL
= pool
;
702 switch_thread_rwlock_create(&RWLOCK
, RUNTIME_POOL
);
703 switch_mutex_init(&BLOCK
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
704 switch_mutex_init(&POOL_LOCK
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
705 switch_mutex_init(&EVENT_QUEUE_MUTEX
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
706 switch_mutex_init(&CUSTOM_HASH_MUTEX
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
707 switch_core_hash_init(&CUSTOM_HASH
);
709 if (switch_core_test_flag(SCF_MINIMAL
)) {
710 return SWITCH_STATUS_SUCCESS
;
713 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_INFO
, "Activate Eventing Engine.\n");
715 switch_core_hash_init(&event_channel_manager
.lahash
);
716 switch_mutex_init(&event_channel_manager
.lamutex
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
718 switch_thread_rwlock_create(&event_channel_manager
.rwlock
, RUNTIME_POOL
);
719 switch_core_hash_init(&event_channel_manager
.hash
);
720 switch_core_hash_init(&event_channel_manager
.perm_hash
);
721 event_channel_manager
.ID
= 1;
723 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
725 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
727 //switch_threadattr_create(&thd_attr, pool);
728 switch_find_local_ip(guess_ip_v4
, sizeof(guess_ip_v4
), NULL
, AF_INET
);
729 switch_find_local_ip(guess_ip_v6
, sizeof(guess_ip_v6
), NULL
, AF_INET6
);
732 #ifdef SWITCH_EVENT_RECYCLE
733 switch_queue_create(&EVENT_RECYCLE_QUEUE
, 250000, THRUNTIME_POOL
);
734 switch_queue_create(&EVENT_HEADER_RECYCLE_QUEUE
, 250000, THRUNTIME_POOL
);
739 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
741 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
743 return SWITCH_STATUS_SUCCESS
;
746 SWITCH_DECLARE(switch_status_t
) switch_event_create_subclass_detailed(const char *file
, const char *func
, int line
,
747 switch_event_t
**event
, switch_event_types_t event_id
, const char *subclass_name
)
749 #ifdef SWITCH_EVENT_RECYCLE
755 if ((event_id
!= SWITCH_EVENT_CLONE
&& event_id
!= SWITCH_EVENT_CUSTOM
) && subclass_name
) {
756 return SWITCH_STATUS_GENERR
;
758 #ifdef SWITCH_EVENT_RECYCLE
759 if (EVENT_RECYCLE_QUEUE
&& switch_queue_trypop(EVENT_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
760 *event
= (switch_event_t
*) pop
;
763 *event
= ALLOC(sizeof(switch_event_t
));
764 switch_assert(*event
);
765 #ifdef SWITCH_EVENT_RECYCLE
769 memset(*event
, 0, sizeof(switch_event_t
));
771 if (event_id
== SWITCH_EVENT_REQUEST_PARAMS
|| event_id
== SWITCH_EVENT_CHANNEL_DATA
|| event_id
== SWITCH_EVENT_MESSAGE
) {
772 (*event
)->flags
|= EF_UNIQ_HEADERS
;
775 if (event_id
!= SWITCH_EVENT_CLONE
) {
776 (*event
)->event_id
= event_id
;
777 switch_event_prep_for_delivery_detailed(file
, func
, line
, *event
);
781 (*event
)->subclass_name
= DUP(subclass_name
);
782 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "Event-Subclass", subclass_name
);
785 return SWITCH_STATUS_SUCCESS
;
788 SWITCH_DECLARE(switch_status_t
) switch_event_set_priority(switch_event_t
*event
, switch_priority_t priority
)
790 event
->priority
= priority
;
791 switch_event_add_header_string(event
, SWITCH_STACK_TOP
, "priority", switch_priority_name(priority
));
792 return SWITCH_STATUS_SUCCESS
;
795 SWITCH_DECLARE(switch_status_t
) switch_event_rename_header(switch_event_t
*event
, const char *header_name
, const char *new_header_name
)
797 switch_event_header_t
*hp
;
798 switch_ssize_t hlen
= -1;
799 unsigned long hash
= 0;
802 switch_assert(event
);
805 return SWITCH_STATUS_FALSE
;
808 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
810 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
811 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(hp
->name
, header_name
)) {
813 hp
->name
= DUP(new_header_name
);
815 hp
->hash
= switch_ci_hashfunc_default(hp
->name
, &hlen
);
820 return x
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
824 SWITCH_DECLARE(switch_event_header_t
*) switch_event_get_header_ptr(switch_event_t
*event
, const char *header_name
)
826 switch_event_header_t
*hp
;
827 switch_ssize_t hlen
= -1;
828 unsigned long hash
= 0;
830 switch_assert(event
);
835 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
837 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
838 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(hp
->name
, header_name
)) {
845 SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t
*event
, const char *header_name
, int idx
)
847 switch_event_header_t
*hp
;
849 if ((hp
= switch_event_get_header_ptr(event
, header_name
))) {
852 return hp
->array
[idx
];
859 } else if (!strcmp(header_name
, "_body")) {
866 SWITCH_DECLARE(char *) switch_event_get_body(switch_event_t
*event
)
868 return (event
? event
->body
: NULL
);
871 SWITCH_DECLARE(switch_status_t
) switch_event_del_header_val(switch_event_t
*event
, const char *header_name
, const char *val
)
873 switch_event_header_t
*hp
, *lp
= NULL
, *tp
;
874 switch_status_t status
= SWITCH_STATUS_FALSE
;
876 switch_ssize_t hlen
= -1;
877 unsigned long hash
= 0;
880 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
886 switch_assert(x
< 1000000);
888 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(header_name
, hp
->name
) && (zstr(val
) || !strcmp(hp
->value
, val
))) {
892 event
->headers
= hp
->next
;
894 if (hp
== event
->last_header
|| !hp
->next
) {
895 event
->last_header
= lp
;
898 status
= SWITCH_STATUS_SUCCESS
;
907 static switch_event_header_t
*new_header(const char *header_name
)
909 switch_event_header_t
*header
;
911 #ifdef SWITCH_EVENT_RECYCLE
913 if (EVENT_HEADER_RECYCLE_QUEUE
&& switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
) {
914 header
= (switch_event_header_t
*) pop
;
917 header
= ALLOC(sizeof(*header
));
918 switch_assert(header
);
919 #ifdef SWITCH_EVENT_RECYCLE
923 memset(header
, 0, sizeof(*header
));
924 header
->name
= DUP(header_name
);
930 static void free_header(switch_event_header_t
**header
)
935 if ((*header
)->idx
) {
936 if (!(*header
)->array
) {
937 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "INDEX WITH NO ARRAY ?? [%s][%s]\n", (*header
)->name
, (*header
)->value
);
941 for (i
= 0; i
< (*header
)->idx
; i
++) {
942 FREE((*header
)->array
[i
]);
944 FREE((*header
)->array
);
948 FREE((*header
)->name
);
949 FREE((*header
)->value
);
951 #ifdef SWITCH_EVENT_RECYCLE
952 if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE
, *header
) != SWITCH_STATUS_SUCCESS
) {
961 SWITCH_DECLARE(int) switch_event_add_array(switch_event_t
*event
, const char *var
, const char *val
)
970 if (strlen(val
) < 8) {
978 while((p
= strstr(p
, "|:"))) {
983 data
= strdup(val
+ 7);
985 len
= (sizeof(char *) * max
) + 1;
989 switch_assert(array
);
990 memset(array
, 0, len
);
992 switch_separate_string_string(data
, "|:", array
, max
);
994 for(i
= 0; i
< max
; i
++) {
995 switch_event_add_header_string(event
, SWITCH_STACK_PUSH
, var
, array
[i
]);
1004 static switch_status_t
switch_event_base_add_header(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, char *data
)
1006 switch_event_header_t
*header
= NULL
;
1007 switch_ssize_t hlen
= -1;
1008 int exists
= 0, fly
= 0;
1011 char *real_header_name
= NULL
;
1014 if (!strcmp(header_name
, "_body")) {
1015 switch_event_set_body(event
, data
);
1018 if ((index_ptr
= strchr(header_name
, '['))) {
1020 index
= atoi(index_ptr
);
1021 real_header_name
= DUP(header_name
);
1022 if ((index_ptr
= strchr(real_header_name
, '['))) {
1023 *index_ptr
++ = '\0';
1025 header_name
= real_header_name
;
1028 if (index_ptr
|| (stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1029 switch_event_header_t
*tmp_header
= NULL
;
1031 if (!(header
= switch_event_get_header_ptr(event
, header_name
)) && index_ptr
) {
1033 tmp_header
= header
= new_header(header_name
);
1035 if (switch_test_flag(event
, EF_UNIQ_HEADERS
)) {
1036 switch_event_del_header(event
, header_name
);
1042 if (header
|| (header
= switch_event_get_header_ptr(event
, header_name
))) {
1045 if (index
> -1 && index
<= 4000) {
1046 if (index
< header
->idx
) {
1047 FREE(header
->array
[index
]);
1048 header
->array
[index
] = DUP(data
);
1053 m
= realloc(header
->array
, sizeof(char *) * (index
+ 1));
1056 for (i
= header
->idx
; i
< index
; i
++) {
1059 m
[index
] = DUP(data
);
1060 header
->idx
= index
+ 1;
1068 } else if (tmp_header
) {
1069 free_header(&tmp_header
);
1075 if ((stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1077 stack
&= ~(SWITCH_STACK_TOP
| SWITCH_STACK_BOTTOM
);
1089 switch_event_del_header(event
, header_name
);
1094 if (switch_test_flag(event
, EF_UNIQ_HEADERS
)) {
1095 switch_event_del_header(event
, header_name
);
1098 if (!strncmp(data
, "ARRAY::", 7)) {
1099 switch_event_add_array(event
, header_name
, data
);
1105 header
= new_header(header_name
);
1108 if ((stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1110 switch_size_t len
= 0;
1114 if (header
->value
&& !header
->idx
) {
1115 m
= malloc(sizeof(char *));
1117 m
[0] = header
->value
;
1118 header
->value
= NULL
;
1124 i
= header
->idx
+ 1;
1125 m
= realloc(header
->array
, sizeof(char *) * i
);
1128 if ((stack
& SWITCH_STACK_PUSH
)) {
1129 m
[header
->idx
] = data
;
1130 } else if ((stack
& SWITCH_STACK_UNSHIFT
)) {
1131 for (j
= header
->idx
; j
> 0; j
--) {
1142 for(j
= 0; j
< header
->idx
; j
++) {
1144 if (!header
->array
[j
]) {
1147 len
+= strlen(header
->array
[j
]);
1152 hv
= realloc(header
->value
, len
);
1156 if (header
->idx
> 1) {
1157 switch_snprintf(header
->value
, len
, "ARRAY::");
1159 *header
->value
= '\0';
1162 hv
+= strlen(header
->value
);
1163 for(j
= 0; j
< header
->idx
; j
++) {
1165 memcpy(hv
, "|:", 2);
1168 if (!header
->array
[j
]) {
1171 memcpy(hv
, header
->array
[j
], strlen(header
->array
[j
]));
1172 hv
+= strlen(header
->array
[j
]);
1178 switch_safe_free(header
->value
);
1179 header
->value
= data
;
1183 header
->hash
= switch_ci_hashfunc_default(header
->name
, &hlen
);
1185 if ((stack
& SWITCH_STACK_TOP
)) {
1186 header
->next
= event
->headers
;
1187 event
->headers
= header
;
1188 if (!event
->last_header
) {
1189 event
->last_header
= header
;
1192 if (event
->last_header
) {
1193 event
->last_header
->next
= header
;
1195 event
->headers
= header
;
1196 header
->next
= NULL
;
1198 event
->last_header
= header
;
1204 switch_safe_free(real_header_name
);
1206 return SWITCH_STATUS_SUCCESS
;
1209 SWITCH_DECLARE(switch_status_t
) switch_event_add_header(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, const char *fmt
, ...)
1216 ret
= switch_vasprintf(&data
, fmt
, ap
);
1220 return SWITCH_STATUS_MEMERR
;
1223 return switch_event_base_add_header(event
, stack
, header_name
, data
);
1226 SWITCH_DECLARE(switch_status_t
) switch_event_set_subclass_name(switch_event_t
*event
, const char *subclass_name
)
1228 if (!event
|| !subclass_name
)
1229 return SWITCH_STATUS_GENERR
;
1231 switch_safe_free(event
->subclass_name
);
1232 event
->subclass_name
= DUP(subclass_name
);
1233 switch_event_del_header(event
, "Event-Subclass");
1234 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Subclass", event
->subclass_name
);
1235 return SWITCH_STATUS_SUCCESS
;
1238 SWITCH_DECLARE(switch_status_t
) switch_event_add_header_string(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, const char *data
)
1241 return switch_event_base_add_header(event
, stack
, header_name
, (stack
& SWITCH_STACK_NODUP
) ? (char *)data
: DUP(data
));
1243 return SWITCH_STATUS_GENERR
;
1246 SWITCH_DECLARE(switch_status_t
) switch_event_set_body(switch_event_t
*event
, const char *body
)
1248 switch_safe_free(event
->body
);
1251 event
->body
= DUP(body
);
1254 return SWITCH_STATUS_SUCCESS
;
1257 SWITCH_DECLARE(switch_status_t
) switch_event_add_body(switch_event_t
*event
, const char *fmt
, ...)
1265 ret
= switch_vasprintf(&data
, fmt
, ap
);
1269 return SWITCH_STATUS_GENERR
;
1271 switch_safe_free(event
->body
);
1273 return SWITCH_STATUS_SUCCESS
;
1276 return SWITCH_STATUS_GENERR
;
1280 SWITCH_DECLARE(void) switch_event_destroy(switch_event_t
**event
)
1282 switch_event_t
*ep
= *event
;
1283 switch_event_header_t
*hp
, *this;
1286 for (hp
= ep
->headers
; hp
;) {
1292 FREE(ep
->subclass_name
);
1293 #ifdef SWITCH_EVENT_RECYCLE
1294 if (switch_queue_trypush(EVENT_RECYCLE_QUEUE
, ep
) != SWITCH_STATUS_SUCCESS
) {
1306 SWITCH_DECLARE(void) switch_event_merge(switch_event_t
*event
, switch_event_t
*tomerge
)
1308 switch_event_header_t
*hp
;
1310 switch_assert(tomerge
&& event
);
1312 for (hp
= tomerge
->headers
; hp
; hp
= hp
->next
) {
1316 for(i
= 0; i
< hp
->idx
; i
++) {
1317 switch_event_add_header_string(event
, SWITCH_STACK_PUSH
, hp
->name
, hp
->array
[i
]);
1320 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, hp
->name
, hp
->value
);
1325 SWITCH_DECLARE(switch_status_t
) switch_event_dup(switch_event_t
**event
, switch_event_t
*todup
)
1327 switch_event_header_t
*hp
;
1329 if (switch_event_create_subclass(event
, SWITCH_EVENT_CLONE
, todup
->subclass_name
) != SWITCH_STATUS_SUCCESS
) {
1330 return SWITCH_STATUS_GENERR
;
1333 (*event
)->event_id
= todup
->event_id
;
1334 (*event
)->event_user_data
= todup
->event_user_data
;
1335 (*event
)->bind_user_data
= todup
->bind_user_data
;
1336 (*event
)->flags
= todup
->flags
;
1337 for (hp
= todup
->headers
; hp
; hp
= hp
->next
) {
1338 if (todup
->subclass_name
&& !strcmp(hp
->name
, "Event-Subclass")) {
1344 for (i
= 0; i
< hp
->idx
; i
++) {
1345 switch_event_add_header_string(*event
, SWITCH_STACK_PUSH
, hp
->name
, hp
->array
[i
]);
1348 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, hp
->name
, hp
->value
);
1353 (*event
)->body
= DUP(todup
->body
);
1356 (*event
)->key
= todup
->key
;
1358 return SWITCH_STATUS_SUCCESS
;
1362 SWITCH_DECLARE(switch_status_t
) switch_event_dup_reply(switch_event_t
**event
, switch_event_t
*todup
)
1364 switch_event_header_t
*hp
;
1365 char hname
[1024] = "";
1368 if (switch_event_create_subclass(event
, SWITCH_EVENT_CLONE
, todup
->subclass_name
) != SWITCH_STATUS_SUCCESS
) {
1369 return SWITCH_STATUS_GENERR
;
1372 (*event
)->event_id
= todup
->event_id
;
1373 (*event
)->event_user_data
= todup
->event_user_data
;
1374 (*event
)->bind_user_data
= todup
->bind_user_data
;
1375 (*event
)->flags
= todup
->flags
;
1377 for (hp
= todup
->headers
; hp
; hp
= hp
->next
) {
1378 char *name
= hp
->name
, *value
= hp
->value
;
1380 if (todup
->subclass_name
&& !strcmp(hp
->name
, "Event-Subclass")) {
1384 if (!strncasecmp(hp
->name
, "from_", 5)) {
1386 switch_snprintf(hname
, sizeof(hname
), "to_%s", p
);
1388 } else if (!strncasecmp(hp
->name
, "to_", 3)) {
1390 switch_snprintf(hname
, sizeof(hname
), "from_%s", p
);
1392 } else if (!strcasecmp(name
, "to")) {
1394 } else if (!strcasecmp(name
, "from")) {
1400 for (i
= 0; i
< hp
->idx
; i
++) {
1401 switch_event_add_header_string(*event
, SWITCH_STACK_PUSH
, name
, hp
->array
[i
]);
1404 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, name
, value
);
1408 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "replying", "true");
1411 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "orig_body", todup
->body
);
1414 (*event
)->key
= todup
->key
;
1416 return SWITCH_STATUS_SUCCESS
;
1419 #define SWITCH_SERIALIZED_EVENT_MAP "S(iiisss)A(S(ss))"
1421 SWITCH_DECLARE(switch_status_t
) switch_event_binary_deserialize(switch_event_t
**eventp
, void **data
, switch_size_t len
, switch_bool_t destroy
)
1424 switch_event_t
*event
;
1426 switch_serial_event_t e
;
1427 switch_serial_event_header_t sh
;
1430 switch_event_create(&event
, SWITCH_EVENT_CLONE
);
1431 switch_assert(event
);
1433 tn
= tpl_map(SWITCH_SERIALIZED_EVENT_MAP
, &e
, &sh
);
1436 how
|= TPL_EXCESS_OK
;
1439 tpl_load(tn
, how
, data
, len
);
1443 event
->event_id
= e
.event_id
;
1444 event
->priority
= e
.priority
;
1445 event
->flags
= e
.flags
;
1447 event
->owner
= e
.owner
;
1448 event
->subclass_name
= e
.subclass_name
;
1449 event
->body
= e
.body
;
1452 while (tpl_unpack(tn
, 1)) {
1453 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, sh
.name
, sh
.value
);
1466 return SWITCH_STATUS_SUCCESS
;
1468 return SWITCH_STATUS_FALSE
;
1473 SWITCH_DECLARE(switch_status_t
) switch_event_binary_serialize(switch_event_t
*event
, void **data
, switch_size_t
*len
)
1477 switch_serial_event_t e
;
1478 switch_serial_event_header_t sh
;
1479 switch_event_header_t
*eh
;
1482 e
.event_id
= event
->event_id
;
1483 e
.priority
= event
->priority
;
1484 e
.flags
= event
->flags
;
1486 e
.owner
= event
->owner
;
1487 e
.subclass_name
= event
->subclass_name
;
1488 e
.body
= event
->body
;
1490 tn
= tpl_map(SWITCH_SERIALIZED_EVENT_MAP
, &e
, &sh
);
1494 for (eh
= event
->headers
; eh
; eh
= eh
->next
) {
1495 if (eh
->idx
) continue; // no arrays yet
1498 sh
.value
= eh
->value
;
1504 how
|= TPL_PREALLOCD
;
1507 tpl_dump(tn
, how
, data
, len
);
1511 return SWITCH_STATUS_SUCCESS
;
1513 return SWITCH_STATUS_FALSE
;
1518 SWITCH_DECLARE(switch_status_t
) switch_event_serialize(switch_event_t
*event
, char **str
, switch_bool_t encode
)
1520 switch_size_t len
= 0;
1521 switch_event_header_t
*hp
;
1522 switch_size_t llen
= 0, dlen
= 0, blocksize
= 512, encode_len
= 1536, new_len
= 0;
1524 char *encode_buf
= NULL
; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */
1528 dlen
= blocksize
* 2;
1530 if (!(buf
= malloc(dlen
))) {
1534 /* go ahead and give ourselves some space to work with, should save a few reallocs */
1535 if (!(encode_buf
= malloc(encode_len
))) {
1539 /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "hit serialized!.\n"); */
1540 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1542 * grab enough memory to store 3x the string (url encode takes one char and turns it into %XX)
1543 * so we could end up with a string that is 3 times the originals length, unlikely but rather
1544 * be safe than destroy the string, also add one for the null. And try to be smart about using
1545 * the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU
1552 for(i
= 0; i
< hp
->idx
; i
++) {
1553 new_len
+= (strlen(hp
->array
[i
]) * 3) + 1;
1556 new_len
= (strlen(hp
->value
) * 3) + 1;
1559 if (encode_len
< new_len
) {
1562 /* keep track of the size of our allocation */
1563 encode_len
= new_len
;
1565 if (!(tmp
= realloc(encode_buf
, encode_len
))) {
1572 /* handle any bad things in the string like newlines : etc that screw up the serialized format */
1576 switch_url_encode(hp
->value
, encode_buf
, encode_len
);
1578 switch_snprintf(encode_buf
, encode_len
, "[%s]", hp
->value
);
1582 llen
= strlen(hp
->name
) + strlen(encode_buf
) + 8;
1584 if ((len
+ llen
) > dlen
) {
1586 dlen
+= (blocksize
+ (len
+ llen
));
1587 if (!(m
= realloc(buf
, dlen
))) {
1593 switch_snprintf(buf
+ len
, dlen
- len
, "%s: %s\n", hp
->name
, *encode_buf
== '\0' ? "_undef_" : encode_buf
);
1597 /* we are done with the memory we used for encoding, give it back */
1598 switch_safe_free(encode_buf
);
1601 int blen
= (int) strlen(event
->body
);
1610 if ((len
+ llen
) > dlen
) {
1612 dlen
+= (blocksize
+ (len
+ llen
));
1613 if (!(m
= realloc(buf
, dlen
))) {
1620 switch_snprintf(buf
+ len
, dlen
- len
, "Content-Length: %d\n\n%s", blen
, event
->body
);
1622 switch_snprintf(buf
+ len
, dlen
- len
, "\n");
1625 switch_snprintf(buf
+ len
, dlen
- len
, "\n");
1630 return SWITCH_STATUS_SUCCESS
;
1633 SWITCH_DECLARE(switch_status_t
) switch_event_create_array_pair(switch_event_t
**event
, char **names
, char **vals
, int len
)
1638 switch_event_create(event
, SWITCH_EVENT_CLONE
);
1640 for (r
= 0; r
< len
; r
++) {
1641 val
= switch_str_nil(vals
[r
]);
1648 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, name
, val
);
1651 return SWITCH_STATUS_SUCCESS
;
1655 SWITCH_DECLARE(switch_status_t
) switch_event_create_brackets(char *data
, char a
, char b
, char c
, switch_event_t
**event
, char **new_data
, switch_bool_t dup
)
1657 char *vdata
, *vdatap
= NULL
;
1658 char *end
, *check_a
, *check_b
;
1659 switch_event_t
*e
= *event
;
1660 char *var_array
[1024] = { 0 };
1662 char *next
= NULL
, *vnext
= NULL
;
1665 vdatap
= strdup(data
);
1671 end
= switch_find_end_paren(vdata
, a
, b
);
1675 while (check_a
&& (check_b
= switch_strchr_strict(check_a
, a
, " "))) {
1676 if ((check_b
= switch_find_end_paren(check_b
, a
, b
))) {
1681 if (check_a
) end
= check_a
;
1691 return SWITCH_STATUS_FALSE
;
1695 switch_event_create_plain(&e
, SWITCH_EVENT_CHANNEL_DATA
);
1696 e
->flags
|= EF_UNIQ_HEADERS
;
1706 if ((pnext
= switch_strchr_strict(next
, a
, " "))) {
1710 vnext
= switch_find_end_paren(next
, a
, b
);
1716 if (*vdata
== '^' && *(vdata
+ 1) == '^') {
1722 if ((var_count
= switch_separate_string(vdata
, c
, var_array
, (sizeof(var_array
) / sizeof(var_array
[0]))))) {
1724 for (x
= 0; x
< var_count
; x
++) {
1725 char *inner_var_array
[2] = { 0 };
1726 int inner_var_count
;
1728 if ((inner_var_count
= switch_separate_string(var_array
[x
], '=',
1729 inner_var_array
, (sizeof(inner_var_array
) / sizeof(inner_var_array
[0])))) == 2) {
1730 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "Parsing variable [%s]=[%s]\n", inner_var_array
[0], inner_var_array
[1]);
1731 switch_event_add_header_string(e
, SWITCH_STACK_BOTTOM
, inner_var_array
[0], inner_var_array
[1]);
1748 *new_data
= strdup(end
);
1754 return SWITCH_STATUS_SUCCESS
;
1760 SWITCH_DECLARE(switch_status_t
) switch_event_create_json(switch_event_t
**event
, const char *json
)
1762 switch_event_t
*new_event
;
1766 if (!(cj
= cJSON_Parse(json
))) {
1767 return SWITCH_STATUS_FALSE
;
1770 if (switch_event_create(&new_event
, SWITCH_EVENT_CLONE
) != SWITCH_STATUS_SUCCESS
) {
1772 return SWITCH_STATUS_FALSE
;
1775 for (cjp
= cj
->child
; cjp
; cjp
= cjp
->next
) {
1776 char *name
= cjp
->string
;
1777 char *value
= cjp
->valuestring
;
1779 if (name
&& value
) {
1780 if (!strcasecmp(name
, "_body")) {
1781 switch_event_add_body(new_event
, value
, SWITCH_VA_NONE
);
1783 if (!strcasecmp(name
, "event-name")) {
1784 switch_event_del_header(new_event
, "event-name");
1785 switch_name_event(value
, &new_event
->event_id
);
1788 switch_event_add_header_string(new_event
, SWITCH_STACK_BOTTOM
, name
, value
);
1792 if (cjp
->type
== cJSON_Array
) {
1793 int i
, x
= cJSON_GetArraySize(cjp
);
1795 for (i
= 0; i
< x
; i
++) {
1796 cJSON
*item
= cJSON_GetArrayItem(cjp
, i
);
1798 if (item
&& item
->type
== cJSON_String
&& item
->valuestring
) {
1799 switch_event_add_header_string(new_event
, SWITCH_STACK_PUSH
, name
, item
->valuestring
);
1808 return SWITCH_STATUS_SUCCESS
;
1811 SWITCH_DECLARE(switch_status_t
) switch_event_serialize_json_obj(switch_event_t
*event
, cJSON
**json
)
1813 switch_event_header_t
*hp
;
1816 cj
= cJSON_CreateObject();
1818 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1820 cJSON
*a
= cJSON_CreateArray();
1823 for(i
= 0; i
< hp
->idx
; i
++) {
1824 cJSON_AddItemToArray(a
, cJSON_CreateString(hp
->array
[i
]));
1827 cJSON_AddItemToObject(cj
, hp
->name
, a
);
1830 cJSON_AddItemToObject(cj
, hp
->name
, cJSON_CreateString(hp
->value
));
1835 int blen
= (int) strlen(event
->body
);
1838 switch_snprintf(tmp
, sizeof(tmp
), "%d", blen
);
1840 cJSON_AddItemToObject(cj
, "Content-Length", cJSON_CreateString(tmp
));
1841 cJSON_AddItemToObject(cj
, "_body", cJSON_CreateString(event
->body
));
1846 return SWITCH_STATUS_SUCCESS
;
1849 SWITCH_DECLARE(switch_status_t
) switch_event_serialize_json(switch_event_t
*event
, char **str
)
1855 if (switch_event_serialize_json_obj(event
, &cj
) == SWITCH_STATUS_SUCCESS
) {
1856 *str
= cJSON_PrintUnformatted(cj
);
1859 return SWITCH_STATUS_SUCCESS
;
1862 return SWITCH_STATUS_FALSE
;
1865 static switch_xml_t
add_xml_header(switch_xml_t xml
, char *name
, char *value
, int offset
)
1867 switch_xml_t header
= switch_xml_add_child_d(xml
, name
, offset
);
1870 switch_size_t encode_len
= (strlen(value
) * 3) + 1;
1871 char *encode_buf
= malloc(encode_len
);
1873 switch_assert(encode_buf
);
1875 memset(encode_buf
, 0, encode_len
);
1876 switch_url_encode((char *) value
, encode_buf
, encode_len
);
1877 switch_xml_set_txt_d(header
, encode_buf
);
1884 SWITCH_DECLARE(switch_xml_t
) switch_event_xmlize(switch_event_t
*event
, const char *fmt
,...)
1886 switch_event_header_t
*hp
;
1887 char *data
= NULL
, *body
= NULL
;
1889 switch_xml_t xml
= NULL
;
1892 switch_xml_t xheaders
= NULL
;
1894 if (!(xml
= switch_xml_new("event"))) {
1900 #ifdef HAVE_VASPRINTF
1901 ret
= vasprintf(&data
, fmt
, ap
);
1903 data
= (char *) malloc(2048);
1908 ret
= vsnprintf(data
, 2048, fmt
, ap
);
1912 #ifndef HAVE_VASPRINTF
1919 if ((xheaders
= switch_xml_add_child_d(xml
, "headers", off
++))) {
1921 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1925 for (i
= 0; i
< hp
->idx
; i
++) {
1926 add_xml_header(xheaders
, hp
->name
, hp
->array
[i
], hoff
++);
1929 add_xml_header(xheaders
, hp
->name
, hp
->value
, hoff
++);
1936 } else if (event
->body
) {
1941 int blen
= (int) strlen(body
);
1943 switch_snprintf(blena
, sizeof(blena
), "%d", blen
);
1945 switch_xml_t xbody
= NULL
;
1947 add_xml_header(xml
, "Content-Length", blena
, off
++);
1948 if ((xbody
= switch_xml_add_child_d(xml
, "body", off
++))) {
1949 switch_xml_set_txt_d(xbody
, body
);
1961 SWITCH_DECLARE(void) switch_event_prep_for_delivery_detailed(const char *file
, const char *func
, int line
, switch_event_t
*event
)
1963 switch_time_exp_t tm
;
1965 switch_size_t retsize
;
1966 switch_time_t ts
= switch_micro_time_now();
1969 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
1970 seq
= ++EVENT_SEQUENCE_NR
;
1971 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
1974 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Name", switch_event_name(event
->event_id
));
1975 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Core-UUID", switch_core_get_uuid());
1976 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-Hostname", switch_core_get_hostname());
1977 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-Switchname", switch_core_get_switchname());
1978 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-IPv4", guess_ip_v4
);
1979 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-IPv6", guess_ip_v6
);
1981 switch_time_exp_lt(&tm
, ts
);
1982 switch_strftime_nocheck(date
, &retsize
, sizeof(date
), "%Y-%m-%d %T", &tm
);
1983 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Date-Local", date
);
1984 switch_rfc822_date(date
, ts
);
1985 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Date-GMT", date
);
1986 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Date-Timestamp", "%" SWITCH_UINT64_T_FMT
, (uint64_t) ts
);
1987 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-File", switch_cut_path(file
));
1988 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-Function", func
);
1989 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-Line-Number", "%d", line
);
1990 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Sequence", "%" SWITCH_UINT64_T_FMT
, seq
);
1995 SWITCH_DECLARE(switch_status_t
) switch_event_fire_detailed(const char *file
, const char *func
, int line
, switch_event_t
**event
, void *user_data
)
1998 switch_assert(BLOCK
!= NULL
);
1999 switch_assert(RUNTIME_POOL
!= NULL
);
2000 switch_assert(EVENT_QUEUE_MUTEX
!= NULL
);
2001 switch_assert(RUNTIME_POOL
!= NULL
);
2003 if (SYSTEM_RUNNING
<= 0) {
2004 /* sorry we're closed */
2005 switch_event_destroy(event
);
2006 return SWITCH_STATUS_SUCCESS
;
2010 (*event
)->event_user_data
= user_data
;
2015 if (runtime
.events_use_dispatch
) {
2018 if (switch_event_queue_dispatch_event(event
) != SWITCH_STATUS_SUCCESS
) {
2019 switch_event_destroy(event
);
2020 return SWITCH_STATUS_FALSE
;
2023 switch_event_deliver_thread_pool(event
);
2026 return SWITCH_STATUS_SUCCESS
;
2029 SWITCH_DECLARE(switch_status_t
) switch_event_get_custom_events(switch_console_callback_match_t
**matches
)
2031 switch_hash_index_t
*hi
= NULL
;
2036 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
2038 for (hi
= switch_core_hash_first(CUSTOM_HASH
); hi
; hi
= switch_core_hash_next(&hi
)) {
2039 switch_core_hash_this(hi
, &var
, NULL
, &val
);
2040 switch_console_push_match(matches
, (const char *) var
);
2044 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
2046 return x
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
2049 SWITCH_DECLARE(switch_status_t
) switch_event_bind_removable(const char *id
, switch_event_types_t event
, const char *subclass_name
,
2050 switch_event_callback_t callback
, void *user_data
, switch_event_node_t
**node
)
2052 switch_event_node_t
*event_node
;
2053 switch_event_subclass_t
*subclass
= NULL
;
2055 switch_assert(BLOCK
!= NULL
);
2056 switch_assert(RUNTIME_POOL
!= NULL
);
2062 if (subclass_name
) {
2063 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
2065 if (!(subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
2066 switch_event_reserve_subclass_detailed(id
, subclass_name
);
2067 subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
);
2071 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
2074 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Could not reserve subclass. '%s'\n", subclass_name
);
2075 return SWITCH_STATUS_FALSE
;
2079 if (event
<= SWITCH_EVENT_ALL
) {
2080 switch_zmalloc(event_node
, sizeof(*event_node
));
2081 switch_thread_rwlock_wrlock(RWLOCK
);
2082 switch_mutex_lock(BLOCK
);
2083 /* <LOCKED> ----------------------------------------------- */
2084 event_node
->id
= DUP(id
);
2085 event_node
->event_id
= event
;
2086 if (subclass_name
) {
2087 event_node
->subclass_name
= DUP(subclass_name
);
2089 event_node
->callback
= callback
;
2090 event_node
->user_data
= user_data
;
2092 if (EVENT_NODES
[event
]) {
2093 event_node
->next
= EVENT_NODES
[event
];
2096 EVENT_NODES
[event
] = event_node
;
2097 switch_mutex_unlock(BLOCK
);
2098 switch_thread_rwlock_unlock(RWLOCK
);
2099 /* </LOCKED> ----------------------------------------------- */
2105 return SWITCH_STATUS_SUCCESS
;
2108 return SWITCH_STATUS_MEMERR
;
2112 SWITCH_DECLARE(switch_status_t
) switch_event_bind(const char *id
, switch_event_types_t event
, const char *subclass_name
,
2113 switch_event_callback_t callback
, void *user_data
)
2115 return switch_event_bind_removable(id
, event
, subclass_name
, callback
, user_data
, NULL
);
2119 SWITCH_DECLARE(switch_status_t
) switch_event_unbind_callback(switch_event_callback_t callback
)
2121 switch_event_node_t
*n
, *np
, *lnp
= NULL
;
2122 switch_status_t status
= SWITCH_STATUS_FALSE
;
2125 switch_thread_rwlock_wrlock(RWLOCK
);
2126 switch_mutex_lock(BLOCK
);
2127 /* <LOCKED> ----------------------------------------------- */
2128 for (id
= 0; id
<= SWITCH_EVENT_ALL
; id
++) {
2131 for (np
= EVENT_NODES
[id
]; np
;) {
2134 if (n
->callback
== callback
) {
2136 lnp
->next
= n
->next
;
2138 EVENT_NODES
[n
->event_id
] = n
->next
;
2141 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG
, "Event Binding deleted for %s:%s\n", n
->id
, switch_event_name(n
->event_id
));
2142 FREE(n
->subclass_name
);
2145 status
= SWITCH_STATUS_SUCCESS
;
2151 switch_mutex_unlock(BLOCK
);
2152 switch_thread_rwlock_unlock(RWLOCK
);
2153 /* </LOCKED> ----------------------------------------------- */
2160 SWITCH_DECLARE(switch_status_t
) switch_event_unbind(switch_event_node_t
**node
)
2162 switch_event_node_t
*n
, *np
, *lnp
= NULL
;
2163 switch_status_t status
= SWITCH_STATUS_FALSE
;
2171 switch_thread_rwlock_wrlock(RWLOCK
);
2172 switch_mutex_lock(BLOCK
);
2173 /* <LOCKED> ----------------------------------------------- */
2174 for (np
= EVENT_NODES
[n
->event_id
]; np
; np
= np
->next
) {
2177 lnp
->next
= n
->next
;
2179 EVENT_NODES
[n
->event_id
] = n
->next
;
2181 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG
, "Event Binding deleted for %s:%s\n", n
->id
, switch_event_name(n
->event_id
));
2182 FREE(n
->subclass_name
);
2186 status
= SWITCH_STATUS_SUCCESS
;
2191 switch_mutex_unlock(BLOCK
);
2192 switch_thread_rwlock_unlock(RWLOCK
);
2193 /* </LOCKED> ----------------------------------------------- */
2198 SWITCH_DECLARE(switch_status_t
) switch_event_create_pres_in_detailed(char *file
, char *func
, int line
,
2199 const char *proto
, const char *login
,
2200 const char *from
, const char *from_domain
,
2201 const char *status
, const char *event_type
,
2202 const char *alt_event_type
, int event_count
,
2203 const char *unique_id
, const char *channel_state
,
2204 const char *answer_state
, const char *call_direction
)
2206 switch_event_t
*pres_event
;
2208 if (switch_event_create_subclass(&pres_event
, SWITCH_EVENT_PRESENCE_IN
, SWITCH_EVENT_SUBCLASS_ANY
) == SWITCH_STATUS_SUCCESS
) {
2209 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "proto", proto
);
2210 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "login", login
);
2211 switch_event_add_header(pres_event
, SWITCH_STACK_TOP
, "from", "%s@%s", from
, from_domain
);
2212 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "status", status
);
2213 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "event_type", event_type
);
2214 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "alt_event_type", alt_event_type
);
2215 switch_event_add_header(pres_event
, SWITCH_STACK_TOP
, "event_count", "%d", event_count
);
2216 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "unique-id", alt_event_type
);
2217 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "channel-state", channel_state
);
2218 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "answer-state", answer_state
);
2219 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "presence-call-direction", call_direction
);
2220 switch_event_fire_detailed(file
, func
, line
, &pres_event
, NULL
);
2221 return SWITCH_STATUS_SUCCESS
;
2223 return SWITCH_STATUS_MEMERR
;
2226 #define resize(l) {\
2228 olen += (len + l + block);\
2230 if ((dp = realloc(data, olen))) {\
2233 memset(c, 0, olen - cpos);\
2236 SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list, uint32_t recur)
2239 char *data
, *indup
, *endof_indup
;
2240 size_t sp
= 0, len
= 0, olen
= 0, vtype
= 0, br
= 0, cpos
, block
= 128;
2241 const char *sub_val
= NULL
;
2242 char *cloned_sub_val
= NULL
, *expanded_sub_val
= NULL
;
2243 char *func_val
= NULL
;
2245 char *gvar
= NULL
, *sb
= NULL
;
2255 nv
= switch_string_var_check_const(in
) || switch_string_has_escaped_data(in
);
2262 olen
= strlen(in
) + 1;
2264 switch_assert(indup
);
2265 endof_indup
= end_of_p(indup
) + 1;
2267 if ((data
= malloc(olen
))) {
2268 memset(data
, 0, olen
);
2270 for (p
= indup
; p
&& p
< endof_indup
&& *p
; p
++) {
2275 if (*(p
+ 1) == '$') {
2278 if (*(p
+ 1) == '$') {
2281 } else if (*(p
+ 1) == '\'') {
2284 } else if (*(p
+ 1) == '\\') {
2285 if (len
+ 1 >= olen
) {
2295 if (*p
== '$' && !nv
) {
2296 if (*(p
+ 1) == '$') {
2302 if (*(p
+ 1) == '{') {
2303 vtype
= global
? 3 : 1;
2313 if (len
+ 1 >= olen
) {
2324 char *s
= p
, *e
, *vname
, *vval
= NULL
;
2329 if ((vtype
== 1 || vtype
== 3) && *s
== '{') {
2337 if (br
== 1 && *e
== '}') {
2344 if (e
!= s
&& *e
== '{') {
2346 } else if (br
> 1 && *e
== '}') {
2353 p
= e
> endof_indup
? endof_indup
: e
;
2356 for(sb
= vname
; sb
&& *sb
; sb
++) {
2360 } else if (*sb
== '(') {
2379 } else if (br
> 1 && *e
== ')') {
2381 } else if (br
== 1 && *e
== ')') {
2391 if (vtype
== 1 || vtype
== 3) {
2392 char *expanded
= NULL
;
2398 if ((expanded
= switch_event_expand_headers_check(event
, (char *) vname
, var_list
, api_list
, recur
+1)) == vname
) {
2403 if ((ptr
= strchr(vname
, ':'))) {
2406 if ((ptr
= strchr(ptr
, ':'))) {
2408 ooffset
= atoi(ptr
);
2412 if ((ptr
= strchr(vname
, '[')) && strchr(ptr
, ']')) {
2417 if (vtype
== 3 || !(sub_val
= switch_event_get_header_idx(event
, vname
, idx
))) {
2418 switch_safe_free(gvar
);
2419 if ((gvar
= switch_core_get_variable_dup(vname
))) {
2423 if (var_list
&& !switch_event_check_permission_list(var_list
, vname
)) {
2424 sub_val
= "<Variable Expansion Permission Denied>";
2428 if ((expanded_sub_val
= switch_event_expand_headers_check(event
, sub_val
, var_list
, api_list
, recur
+1)) == sub_val
) {
2429 expanded_sub_val
= NULL
;
2431 sub_val
= expanded_sub_val
;
2436 if (offset
|| ooffset
) {
2437 cloned_sub_val
= strdup(sub_val
);
2438 switch_assert(cloned_sub_val
);
2439 sub_val
= cloned_sub_val
;
2444 } else if ((size_t) abs(offset
) <= strlen(sub_val
)) {
2445 sub_val
= cloned_sub_val
+ (strlen(cloned_sub_val
) + offset
);
2448 if (ooffset
> 0 && (size_t) ooffset
< strlen(sub_val
)) {
2449 if ((ptr
= (char *) sub_val
+ ooffset
)) {
2455 switch_safe_free(expanded
);
2457 switch_stream_handle_t stream
= { 0 };
2458 char *expanded
= NULL
;
2459 char *expanded_vname
= NULL
;
2461 if ((expanded_vname
= switch_event_expand_headers_check(event
, (char *) vname
, var_list
, api_list
, recur
+1)) == vname
) {
2462 expanded_vname
= NULL
;
2464 vname
= expanded_vname
;
2467 if ((expanded
= switch_event_expand_headers_check(event
, vval
, var_list
, api_list
, recur
+1)) == vval
) {
2473 if (!switch_core_test_flag(SCF_API_EXPANSION
) || (api_list
&& !switch_event_check_permission_list(api_list
, vname
))) {
2475 sub_val
= "<API execute Permission Denied>";
2477 SWITCH_STANDARD_STREAM(stream
);
2478 if (switch_api_execute(vname
, vval
, NULL
, &stream
) == SWITCH_STATUS_SUCCESS
) {
2479 func_val
= stream
.data
;
2486 switch_safe_free(expanded
);
2487 switch_safe_free(expanded_vname
);
2489 if ((nlen
= sub_val
? strlen(sub_val
) : 0)) {
2490 if (len
+ nlen
>= olen
) {
2499 switch_safe_free(func_val
);
2500 switch_safe_free(cloned_sub_val
);
2501 switch_safe_free(expanded_sub_val
);
2508 if (len
+ 1 >= olen
) {
2520 if (len
+ 1 >= olen
) {
2530 switch_safe_free(gvar
);
2535 SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t
*event
, const char *prefix
, switch_hash_t
*vars_map
)
2537 switch_stream_handle_t stream
= { 0 };
2538 switch_size_t encode_len
= 1024, new_len
= 0;
2539 char *encode_buf
= NULL
;
2540 const char *prof
[12] = { 0 }, *prof_names
[12] = {
2543 switch_event_header_t
*hi
;
2547 SWITCH_STANDARD_STREAM(stream
);
2550 stream
.write_function(&stream
, "%s&", prefix
);
2553 encode_buf
= malloc(encode_len
);
2554 switch_assert(encode_buf
);
2558 for (x
= 0; prof
[x
]; x
++) {
2559 if (zstr(prof
[x
])) {
2562 new_len
= (strlen(prof
[x
]) * 3) + 1;
2563 if (encode_len
< new_len
) {
2566 encode_len
= new_len
;
2568 if (!(tmp
= realloc(encode_buf
, encode_len
))) {
2574 switch_url_encode(prof
[x
], encode_buf
, encode_len
);
2575 stream
.write_function(&stream
, "%s=%s&", prof_names
[x
], encode_buf
);
2579 if ((hi
= event
->headers
)) {
2581 for (; hi
; hi
= hi
->next
) {
2582 char *var
= hi
->name
;
2583 char *val
= hi
->value
;
2585 if (vars_map
!= NULL
) {
2586 if ((data
= switch_core_hash_find(vars_map
, var
)) == NULL
|| strcasecmp(((char *) data
), "enabled"))
2591 new_len
= (strlen((char *) val
) * 3) + 1;
2592 if (encode_len
< new_len
) {
2595 encode_len
= new_len
;
2597 tmp
= realloc(encode_buf
, encode_len
);
2602 switch_url_encode((char *) val
, encode_buf
, encode_len
);
2603 stream
.write_function(&stream
, "%s=%s&", (char *) var
, encode_buf
);
2609 e
= (char *) stream
.data
+ (strlen((char *) stream
.data
) - 1);
2611 if (e
&& *e
== '&') {
2615 switch_safe_free(encode_buf
);
2620 SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t
*list
, const char *name
)
2624 int default_allow
= 0;
2630 default_allow
= switch_test_flag(list
, EF_DEFAULT_ALLOW
);
2632 if (!list
->headers
) {
2633 return default_allow
;
2636 if ((v
= switch_event_get_header(list
, name
))) {
2649 SWITCH_DECLARE(void) switch_json_add_presence_data_cols(switch_event_t
*event
, cJSON
*json
, const char *prefix
)
2653 if (!prefix
) prefix
= "";
2655 if ((data
= switch_event_get_header(event
, "presence_data_cols"))) {
2656 char *cols
[128] = { 0 };
2657 char header_name
[128] = "";
2658 int col_count
= 0, i
= 0;
2659 char *data_copy
= NULL
;
2661 data_copy
= strdup(data
);
2663 col_count
= switch_split(data_copy
, ':', cols
);
2665 for (i
= 0; i
< col_count
; i
++) {
2666 const char *val
= NULL
;
2667 switch_snprintf(header_name
, sizeof(header_name
), "%s%s", prefix
, cols
[i
]);
2669 val
= switch_event_get_header(event
, cols
[i
]);
2670 json_add_child_string(json
, header_name
, val
);
2673 switch_safe_free(data_copy
);
2679 SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t
*channel
, switch_event_t
*event
, const char *prefix
)
2683 if (!prefix
) prefix
= "";
2685 if ((data
= switch_channel_get_variable(channel
, "presence_data_cols"))) {
2686 char *cols
[128] = { 0 };
2687 char header_name
[128] = "";
2688 int col_count
= 0, i
= 0;
2689 char *data_copy
= NULL
;
2691 data_copy
= strdup(data
);
2693 col_count
= switch_split(data_copy
, ':', cols
);
2695 for (i
= 0; i
< col_count
; i
++) {
2696 const char *val
= NULL
;
2697 switch_snprintf(header_name
, sizeof(header_name
), "%s%s", prefix
, cols
[i
]);
2699 val
= switch_channel_get_variable(channel
, cols
[i
]);
2700 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, header_name
, val
);
2703 switch_safe_free(data_copy
);
2708 struct switch_event_channel_sub_node_head_s
;
2709 typedef struct switch_event_channel_sub_node_s
{
2710 switch_event_channel_func_t func
;
2712 switch_event_channel_id_t id
;
2713 struct switch_event_channel_sub_node_head_s
*head
;
2714 struct switch_event_channel_sub_node_s
*next
;
2715 } switch_event_channel_sub_node_t
;
2717 typedef struct switch_event_channel_sub_node_head_s
{
2718 switch_event_channel_sub_node_t
*node
;
2719 switch_event_channel_sub_node_t
*tail
;
2720 char *event_channel
;
2721 } switch_event_channel_sub_node_head_t
;
2723 static uint32_t switch_event_channel_unsub_head(switch_event_channel_func_t func
, switch_event_channel_sub_node_head_t
*head
, void *user_data
)
2727 switch_event_channel_sub_node_t
*thisnp
= NULL
, *np
, *last
= NULL
;
2729 np
= head
->tail
= head
->node
;
2736 if (!(func
) || (thisnp
->func
== func
&& (thisnp
->user_data
== user_data
|| user_data
== NULL
))) {
2746 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "UNSUBBING %p [%s]\n", (void *)(intptr_t)thisnp
->func
, thisnp
->head
->event_channel
);
2749 thisnp
->func
= NULL
;
2760 static void unsub_all_switch_event_channel(void)
2762 switch_hash_index_t
*hi
= NULL
;
2765 switch_event_channel_sub_node_head_t
*head
;
2767 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2769 while ((hi
= switch_core_hash_first_iter( event_channel_manager
.perm_hash
, hi
))) {
2770 switch_event_t
*vals
= NULL
;
2771 switch_core_hash_this(hi
, &var
, NULL
, &val
);
2772 vals
= (switch_event_t
*) val
;
2773 switch_core_hash_delete(event_channel_manager
.perm_hash
, var
);
2774 switch_event_destroy(&vals
);
2777 while ((hi
= switch_core_hash_first_iter( event_channel_manager
.hash
, hi
))) {
2778 switch_core_hash_this(hi
, NULL
, NULL
, &val
);
2779 head
= (switch_event_channel_sub_node_head_t
*) val
;
2780 switch_event_channel_unsub_head(NULL
, head
, NULL
);
2781 switch_core_hash_delete(event_channel_manager
.hash
, head
->event_channel
);
2782 free(head
->event_channel
);
2786 switch_safe_free(hi
);
2787 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2790 static uint32_t switch_event_channel_unsub_channel(switch_event_channel_func_t func
, const char *event_channel
, void *user_data
)
2792 switch_event_channel_sub_node_head_t
*head
;
2795 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2797 if (!event_channel
) {
2798 switch_hash_index_t
*hi
;
2801 for (hi
= switch_core_hash_first(event_channel_manager
.hash
); hi
; hi
= switch_core_hash_next(&hi
)) {
2802 switch_core_hash_this(hi
, NULL
, NULL
, &val
);
2805 head
= (switch_event_channel_sub_node_head_t
*) val
;
2806 x
+= switch_event_channel_unsub_head(func
, head
, user_data
);
2811 if ((head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2812 x
+= switch_event_channel_unsub_head(func
, head
, user_data
);
2816 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2821 static switch_status_t
switch_event_channel_sub_channel(const char *event_channel
, switch_event_channel_func_t func
, switch_event_channel_id_t id
, void *user_data
)
2824 switch_event_channel_sub_node_t
*node
, *np
;
2825 switch_event_channel_sub_node_head_t
*head
;
2826 switch_status_t status
= SWITCH_STATUS_FALSE
;
2828 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2830 if (!(head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2831 switch_zmalloc(head
, sizeof(*head
));
2832 head
->event_channel
= strdup(event_channel
);
2833 switch_core_hash_insert(event_channel_manager
.hash
, event_channel
, head
);
2835 switch_zmalloc(node
, sizeof(*node
));
2837 node
->user_data
= user_data
;
2843 status
= SWITCH_STATUS_SUCCESS
;
2847 for (np
= head
->node
; np
; np
= np
->next
) {
2848 if (np
->func
== func
&& np
->user_data
== user_data
) {
2855 switch_zmalloc(node
, sizeof(*node
));
2858 node
->user_data
= user_data
;
2867 head
->tail
->next
= node
;
2868 head
->tail
= head
->tail
->next
;
2870 status
= SWITCH_STATUS_SUCCESS
;
2874 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2880 char *event_channel
;
2883 switch_event_channel_id_t id
;
2884 } event_channel_data_t
;
2888 static uint32_t _switch_event_channel_broadcast(const char *event_channel
, const char *broadcast_channel
,
2889 cJSON
*json
, const char *key
, switch_event_channel_id_t id
)
2891 switch_event_channel_sub_node_t
*np
;
2892 switch_event_channel_sub_node_head_t
*head
;
2895 switch_thread_rwlock_rdlock(event_channel_manager
.rwlock
);
2896 if ((head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2897 for (np
= head
->node
; np
; np
= np
->next
) {
2902 np
->func(broadcast_channel
, json
, key
, id
, np
->user_data
);
2906 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2911 static void destroy_ecd(event_channel_data_t
**ecdP
)
2913 event_channel_data_t
*ecd
= *ecdP
;
2916 switch_safe_free(ecd
->event_channel
);
2917 switch_safe_free(ecd
->key
);
2919 cJSON_Delete(ecd
->json
);
2926 #ifndef SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS
2927 #define SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS 10
2930 static void ecd_deliver(event_channel_data_t
**ecdP
)
2932 event_channel_data_t
*ecd
= *ecdP
;
2938 t
= _switch_event_channel_broadcast(ecd
->event_channel
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2940 key
= strdup(ecd
->event_channel
);
2941 if (switch_core_test_flag(SCF_EVENT_CHANNEL_ENABLE_HIERARCHY_DELIVERY
)) {
2942 const char *sep
= switch_core_get_event_channel_key_separator();
2943 char *x_argv
[SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS
] = { 0 };
2944 int x_argc
= switch_separate_string_string(key
, (char*) sep
, x_argv
, SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS
);
2947 for(i
=x_argc
- 1; i
> 0; i
--) {
2949 memset(buf
, 0, 1024);
2950 sprintf(buf
, "%s", x_argv
[0]);
2951 for(z
=1; z
< i
; z
++) {
2953 strcat(buf
, x_argv
[z
]);
2955 r
= _switch_event_channel_broadcast(buf
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2957 if (r
&& switch_core_test_flag(SCF_EVENT_CHANNEL_HIERARCHY_DELIVERY_ONCE
)) {
2963 if ((p
= strchr(key
, '.'))) {
2965 t
+= _switch_event_channel_broadcast(key
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2968 switch_safe_free(key
);
2970 t
+= _switch_event_channel_broadcast(SWITCH_EVENT_CHANNEL_GLOBAL
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2973 if (switch_core_test_flag(SCF_EVENT_CHANNEL_LOG_UNDELIVERABLE_JSON
)) {
2974 char *json
= cJSON_Print(ecd
->json
);
2975 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "no subscribers for %s , %s => %s\n", ecd
->event_channel
, ecd
->key
, json
);
2976 switch_safe_free(json
);
2978 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "no subscribers for %s , %s\n", ecd
->event_channel
, ecd
->key
);
2981 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "delivered to %u subscribers for %s\n", t
, ecd
->event_channel
);
2987 static void *SWITCH_THREAD_FUNC
switch_event_channel_deliver_thread(switch_thread_t
*thread
, void *obj
)
2989 switch_queue_t
*queue
= (switch_queue_t
*) obj
;
2991 event_channel_data_t
*ecd
= NULL
;
2993 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
2995 EVENT_CHANNEL_DISPATCH_THREAD_COUNT
++;
2996 EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 0;
2997 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
2999 while(SYSTEM_RUNNING
) {
3001 if (switch_queue_pop(queue
, &pop
) != SWITCH_STATUS_SUCCESS
) {
3009 ecd
= (event_channel_data_t
*) pop
;
3014 while (switch_queue_trypop(queue
, &pop
) == SWITCH_STATUS_SUCCESS
) {
3015 ecd
= (event_channel_data_t
*) pop
;
3019 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
3021 EVENT_CHANNEL_DISPATCH_THREAD_COUNT
--;
3022 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
3024 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Event Channel Dispatch Thread Ended.\n");
3028 SWITCH_DECLARE(switch_status_t
) switch_event_channel_broadcast(const char *event_channel
, cJSON
**json
, const char *key
, switch_event_channel_id_t id
)
3030 event_channel_data_t
*ecd
= NULL
;
3031 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3034 if (!SYSTEM_RUNNING
) {
3035 cJSON_Delete(*json
);
3037 return SWITCH_STATUS_FALSE
;
3040 switch_zmalloc(ecd
, sizeof(*ecd
));
3042 ecd
->event_channel
= strdup(event_channel
);
3044 ecd
->key
= strdup(key
);
3049 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
3050 if (!EVENT_CHANNEL_DISPATCH_THREAD_COUNT
&& !EVENT_CHANNEL_DISPATCH_THREAD_STARTING
&& SYSTEM_RUNNING
) {
3051 EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 1;
3054 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
3057 switch_thread_data_t
*td
;
3059 if (!EVENT_CHANNEL_DISPATCH_QUEUE
) {
3060 switch_queue_create(&EVENT_CHANNEL_DISPATCH_QUEUE
, DISPATCH_QUEUE_LEN
* MAX_DISPATCH
, THRUNTIME_POOL
);
3063 td
= malloc(sizeof(*td
));
3067 td
->func
= switch_event_channel_deliver_thread
;
3068 td
->obj
= EVENT_CHANNEL_DISPATCH_QUEUE
;
3071 switch_thread_pool_launch_thread(&td
);
3074 if ((status
= switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE
, ecd
)) != SWITCH_STATUS_SUCCESS
) {
3075 cJSON_Delete(ecd
->json
);
3078 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Event Channel Queue failure for channel %s, status = %d\n", event_channel
, status
);
3086 SWITCH_DECLARE(switch_status_t
) switch_event_channel_deliver(const char *event_channel
, cJSON
**json
, const char *key
, switch_event_channel_id_t id
)
3088 event_channel_data_t
*ecd
= NULL
;
3089 switch_zmalloc(ecd
, sizeof(*ecd
));
3091 ecd
->event_channel
= strdup(event_channel
);
3093 ecd
->key
= strdup(key
);
3100 return SWITCH_STATUS_SUCCESS
;
3103 SWITCH_DECLARE(uint32_t) switch_event_channel_unbind(const char *event_channel
, switch_event_channel_func_t func
, void *user_data
)
3105 return switch_event_channel_unsub_channel(func
, event_channel
, user_data
);
3108 SWITCH_DECLARE(switch_status_t
) switch_event_channel_bind(const char *event_channel
, switch_event_channel_func_t func
, switch_event_channel_id_t
*id
, void *user_data
)
3110 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3115 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3116 *id
= event_channel_manager
.ID
++;
3117 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3120 status
= switch_event_channel_sub_channel(event_channel
, func
, *id
, user_data
);
3125 SWITCH_DECLARE(switch_bool_t
) switch_event_channel_permission_verify(const char *cookie
, const char *event_channel
)
3127 switch_event_t
*vals
;
3128 switch_bool_t r
= SWITCH_FALSE
;
3130 switch_thread_rwlock_rdlock(event_channel_manager
.rwlock
);
3131 if ((vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3132 r
= switch_true(switch_event_get_header(vals
, event_channel
));
3134 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3139 SWITCH_DECLARE(void) switch_event_channel_permission_modify(const char *cookie
, const char *event_channel
, switch_bool_t set
)
3141 switch_event_t
*vals
;
3143 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3144 if (!(vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3147 switch_event_create_plain(&vals
, SWITCH_EVENT_CHANNEL_DATA
);
3148 switch_core_hash_insert(event_channel_manager
.perm_hash
, cookie
, vals
);
3152 switch_event_add_header_string(vals
, SWITCH_STACK_BOTTOM
, event_channel
, "true");
3154 switch_event_del_header(vals
, event_channel
);
3160 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3163 SWITCH_DECLARE(void) switch_event_channel_permission_clear(const char *cookie
)
3165 switch_event_t
*vals
;
3167 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3168 if ((vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3169 switch_core_hash_delete(event_channel_manager
.perm_hash
, cookie
);
3170 switch_event_destroy(&vals
);
3172 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3176 typedef struct alias_node_s
{
3177 char *event_channel
;
3180 struct alias_node_s
*next
;
3183 typedef struct la_node_s
{
3186 struct la_node_s
*next
;
3190 struct switch_live_array_s
{
3191 char *event_channel
;
3196 switch_memory_pool_t
*pool
;
3197 switch_hash_t
*hash
;
3198 switch_mutex_t
*mutex
;
3201 switch_bool_t visible
;
3203 switch_event_channel_id_t channel_id
;
3204 switch_live_array_command_handler_t command_handler
;
3206 alias_node_t
*aliases
;
3210 static switch_status_t
la_broadcast(switch_live_array_t
*la
, cJSON
**json
)
3215 switch_mutex_lock(la
->mutex
);
3216 for (np
= la
->aliases
; np
; np
= np
->next
) {
3217 cJSON
*dup
= cJSON_Duplicate(*json
, 1);
3218 cJSON
*data
= cJSON_GetObjectItem(dup
, "data");
3220 cJSON_ReplaceItemInObject(dup
, "eventChannel", cJSON_CreateString(np
->event_channel
));
3221 cJSON_ReplaceItemInObject(data
, "name", cJSON_CreateString(np
->name
));
3223 switch_event_channel_broadcast(np
->event_channel
, &dup
, __FILE__
, la
->channel_id
);
3225 switch_mutex_unlock(la
->mutex
);
3228 return switch_event_channel_broadcast(la
->event_channel
, json
, __FILE__
, la
->channel_id
);
3233 SWITCH_DECLARE(switch_status_t
) switch_live_array_visible(switch_live_array_t
*la
, switch_bool_t visible
, switch_bool_t force
)
3235 switch_status_t status
= SWITCH_STATUS_FALSE
;
3237 switch_mutex_lock(la
->mutex
);
3238 if (la
->visible
!= visible
|| force
) {
3241 msg
= cJSON_CreateObject();
3242 data
= json_add_child_obj(msg
, "data", NULL
);
3244 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3245 cJSON_AddItemToObject(data
, "action", cJSON_CreateString(visible
? "hide" : "show"));
3246 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3248 la_broadcast(la
, &msg
);
3250 la
->visible
= visible
;
3252 switch_mutex_unlock(la
->mutex
);
3257 SWITCH_DECLARE(switch_status_t
) switch_live_array_clear(switch_live_array_t
*la
)
3259 la_node_t
*cur
, *np
;
3262 switch_mutex_lock(la
->mutex
);
3265 msg
= cJSON_CreateObject();
3266 data
= json_add_child_obj(msg
, "data", NULL
);
3268 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3269 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("clear"));
3270 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3271 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3272 cJSON_AddItemToObject(data
, "data", cJSON_CreateObject());
3274 la_broadcast(la
, &msg
);
3279 cJSON_Delete(cur
->obj
);
3284 la
->head
= la
->tail
= NULL
;
3286 switch_mutex_unlock(la
->mutex
);
3288 return SWITCH_STATUS_SUCCESS
;
3291 SWITCH_DECLARE(switch_status_t
) switch_live_array_bootstrap(switch_live_array_t
*la
, const char *sessid
, switch_event_channel_id_t channel_id
)
3296 switch_mutex_lock(la
->mutex
);
3299 msg
= cJSON_CreateObject();
3300 data
= json_add_child_obj(msg
, "data", NULL
);
3302 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3303 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("clear"));
3304 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3305 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3306 cJSON_AddItemToObject(data
, "data", cJSON_CreateObject());
3308 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3310 for (np
= la
->head
; np
; np
= np
->next
) {
3311 msg
= cJSON_CreateObject();
3312 data
= json_add_child_obj(msg
, "data", NULL
);
3314 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3315 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("add"));
3316 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3317 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(np
->name
));
3318 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3319 cJSON_AddItemToObject(data
, "data", cJSON_Duplicate(np
->obj
, 1));
3321 cJSON_AddItemToObject(msg
, "sessid", cJSON_CreateString(sessid
));
3323 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3328 msg
= cJSON_CreateObject();
3329 data
= json_add_child_obj(msg
, "data", NULL
);
3331 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3332 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("bootObj"));
3333 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3334 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3337 cJSON_AddItemToObject(msg
, "sessid", cJSON_CreateString(sessid
));
3340 data
= json_add_child_array(data
, "data");
3342 for (np
= la
->head
; np
; np
= np
->next
) {
3343 cJSON
*row
= cJSON_CreateArray();
3344 cJSON_AddItemToArray(row
, cJSON_CreateString(np
->name
));
3345 cJSON_AddItemToArray(row
, cJSON_Duplicate(np
->obj
, 1));
3346 cJSON_AddItemToArray(data
, row
);
3349 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3355 switch_live_array_visible(la
, SWITCH_FALSE
, SWITCH_TRUE
);
3358 switch_mutex_unlock(la
->mutex
);
3360 return SWITCH_STATUS_SUCCESS
;
3363 SWITCH_DECLARE(switch_status_t
) switch_live_array_destroy(switch_live_array_t
**live_arrayP
)
3365 switch_live_array_t
*la
= *live_arrayP
;
3366 switch_memory_pool_t
*pool
;
3370 *live_arrayP
= NULL
;
3372 switch_mutex_lock(la
->mutex
);
3376 if (la
->refs
) done
= 1;
3377 switch_mutex_unlock(la
->mutex
);
3380 return SWITCH_STATUS_SUCCESS
;
3385 switch_live_array_clear(la
);
3387 switch_core_hash_destroy(&la
->hash
);
3389 switch_mutex_lock(event_channel_manager
.lamutex
);
3390 switch_core_hash_delete(event_channel_manager
.lahash
, la
->key
);
3391 for (np
= la
->aliases
; np
; np
= np
->next
) {
3392 switch_core_hash_delete(event_channel_manager
.lahash
, np
->key
);
3394 switch_mutex_unlock(event_channel_manager
.lamutex
);
3396 switch_core_destroy_memory_pool(&pool
);
3398 return SWITCH_STATUS_SUCCESS
;
3401 SWITCH_DECLARE(switch_bool_t
) switch_live_array_isnew(switch_live_array_t
*la
)
3406 SWITCH_DECLARE(switch_bool_t
) switch_live_array_clear_alias(switch_live_array_t
*la
, const char *event_channel
, const char *name
)
3408 alias_node_t
*np
, *last
= NULL
, *del
= NULL
;
3409 switch_bool_t r
= SWITCH_FALSE
;
3411 switch_mutex_lock(la
->mutex
);
3412 for (np
= la
->aliases
; np
; np
= np
->next
) {
3413 if (!strcmp(np
->event_channel
, event_channel
) && !strcmp(np
->name
, name
)) {
3418 last
->next
= np
->next
;
3420 la
->aliases
= np
->next
;
3426 switch_mutex_unlock(la
->mutex
);
3429 switch_mutex_lock(event_channel_manager
.lamutex
);
3430 switch_core_hash_delete(event_channel_manager
.lahash
, del
->key
);
3431 switch_mutex_unlock(event_channel_manager
.lamutex
);
3438 SWITCH_DECLARE(switch_bool_t
) switch_live_array_add_alias(switch_live_array_t
*la
, const char *event_channel
, const char *name
)
3440 alias_node_t
*node
= 0, *np
;
3441 switch_bool_t exist
= SWITCH_FALSE
;
3443 switch_mutex_lock(la
->mutex
);
3444 for (np
= la
->aliases
; np
&& np
->next
; np
= np
->next
) {
3445 if (!strcmp(np
->event_channel
, event_channel
) && !strcmp(np
->name
, name
)) {
3446 exist
= SWITCH_TRUE
;
3452 node
= switch_core_alloc(la
->pool
, sizeof(*node
));
3453 node
->event_channel
= switch_core_strdup(la
->pool
, event_channel
);
3454 node
->name
= switch_core_strdup(la
->pool
, name
);
3455 node
->key
= switch_core_sprintf(la
->pool
, "%s.%s", event_channel
, name
);
3464 switch_mutex_unlock(la
->mutex
);
3467 switch_mutex_lock(event_channel_manager
.lamutex
);
3468 switch_core_hash_insert(event_channel_manager
.lahash
, node
->key
, la
);
3469 switch_mutex_unlock(event_channel_manager
.lamutex
);
3476 SWITCH_DECLARE(switch_status_t
) switch_live_array_create(const char *event_channel
, const char *name
,
3477 switch_event_channel_id_t channel_id
, switch_live_array_t
**live_arrayP
)
3479 switch_live_array_t
*la
= NULL
;
3480 switch_memory_pool_t
*pool
;
3483 switch_core_new_memory_pool(&pool
);
3484 key
= switch_core_sprintf(pool
, "%s.%s", event_channel
, name
);
3486 switch_mutex_lock(event_channel_manager
.lamutex
);
3487 la
= switch_core_hash_find(event_channel_manager
.lahash
, key
);
3488 switch_mutex_unlock(event_channel_manager
.lamutex
);
3491 la
->new = SWITCH_FALSE
;
3493 la
= switch_core_alloc(pool
, sizeof(*la
));
3496 la
->visible
= SWITCH_TRUE
;
3497 la
->event_channel
= switch_core_strdup(la
->pool
, event_channel
);
3498 la
->name
= switch_core_strdup(la
->pool
, name
);
3500 la
->new = SWITCH_TRUE
;
3501 la
->channel_id
= channel_id
;
3502 switch_core_hash_init(&la
->hash
);
3503 switch_mutex_init(&la
->mutex
, SWITCH_MUTEX_NESTED
, la
->pool
);
3505 switch_mutex_lock(event_channel_manager
.lamutex
);
3506 switch_core_hash_insert(event_channel_manager
.lahash
, la
->key
, la
);
3507 switch_mutex_unlock(event_channel_manager
.lamutex
);
3510 switch_mutex_lock(la
->mutex
);
3512 switch_mutex_unlock(la
->mutex
);
3516 return SWITCH_STATUS_SUCCESS
;
3519 SWITCH_DECLARE(cJSON
*) switch_live_array_get(switch_live_array_t
*la
, const char *name
)
3524 switch_mutex_lock(la
->mutex
);
3525 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3526 dup
= cJSON_Duplicate(node
->obj
, 1);
3528 switch_mutex_unlock(la
->mutex
);
3533 SWITCH_DECLARE(cJSON
*) switch_live_array_get_idx(switch_live_array_t
*la
, int idx
)
3538 switch_mutex_lock(la
->mutex
);
3539 for (node
= la
->head
; node
; node
= node
->next
) {
3540 if (node
->pos
== idx
) {
3541 dup
= cJSON_Duplicate(node
->obj
, 1);
3545 switch_mutex_unlock(la
->mutex
);
3550 SWITCH_DECLARE(void) switch_live_array_lock(switch_live_array_t
*la
)
3552 switch_mutex_lock(la
->mutex
);
3555 SWITCH_DECLARE(void) switch_live_array_unlock(switch_live_array_t
*la
)
3557 switch_mutex_unlock(la
->mutex
);
3560 SWITCH_DECLARE(switch_status_t
) switch_live_array_del(switch_live_array_t
*la
, const char *name
)
3562 switch_status_t status
= SWITCH_STATUS_FALSE
;
3563 la_node_t
*node
, *cur
, *np
, *last
= NULL
;
3564 cJSON
*msg
, *data
= NULL
;
3566 switch_mutex_lock(la
->mutex
);
3567 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3576 last
->next
= cur
->next
;
3578 la
->head
= cur
->next
;
3580 switch_core_hash_delete(la
->hash
, name
);
3582 msg
= cJSON_CreateObject();
3583 data
= json_add_child_obj(msg
, "data", NULL
);
3585 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3586 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3587 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("del"));
3588 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(cur
->name
));
3589 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3590 cJSON_AddItemToObject(data
, "data", cur
->obj
);
3593 la_broadcast(la
, &msg
);
3597 cur
->pos
= la
->pos
++;
3603 switch_mutex_unlock(la
->mutex
);
3608 SWITCH_DECLARE(switch_status_t
) switch_live_array_add(switch_live_array_t
*la
, const char *name
, int index
, cJSON
**obj
, switch_bool_t duplicate
)
3611 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3612 const char *action
= "add";
3613 cJSON
*msg
= NULL
, *data
= NULL
;
3614 const char *visibility
= NULL
;
3616 switch_mutex_lock(la
->mutex
);
3618 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3624 cJSON_Delete(node
->obj
);
3629 switch_zmalloc(node
, sizeof(*node
));
3631 node
->name
= strdup(name
);
3632 switch_core_hash_insert(la
->hash
, name
, node
);
3634 if (index
> -1 && index
< la
->pos
&& la
->head
) {
3635 la_node_t
*np
, *last
= NULL
;
3638 for(np
= la
->head
; np
; np
= np
->next
) {
3642 node
->next
= last
->next
;
3646 node
->next
= la
->head
;
3661 node
->pos
= la
->pos
++;
3667 la
->tail
->next
= node
;
3675 node
->obj
= cJSON_Duplicate(*obj
, 1);
3680 msg
= cJSON_CreateObject();
3681 data
= json_add_child_obj(msg
, "data", NULL
);
3682 if ((visibility
= cJSON_GetObjectCstr(node
->obj
, "contentVisibility"))) {
3683 cJSON_AddItemToObject(msg
, "contentVisibility", cJSON_CreateString(visibility
));
3685 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3686 cJSON_AddItemToObject(data
, "action", cJSON_CreateString(action
));
3689 cJSON_AddItemToObject(data
, "arrIndex", cJSON_CreateNumber(index
));
3692 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3693 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(node
->name
));
3694 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3695 cJSON_AddItemToObject(data
, "data", cJSON_Duplicate(node
->obj
, 1));
3697 la_broadcast(la
, &msg
);
3699 switch_mutex_unlock(la
->mutex
);
3704 SWITCH_DECLARE(void) switch_live_array_set_user_data(switch_live_array_t
*la
, void *user_data
)
3707 la
->user_data
= user_data
;
3710 SWITCH_DECLARE(void) switch_live_array_set_command_handler(switch_live_array_t
*la
, switch_live_array_command_handler_t command_handler
)
3713 la
->command_handler
= command_handler
;
3717 SWITCH_DECLARE(void) switch_live_array_parse_json(cJSON
*json
, switch_event_channel_id_t channel_id
)
3719 const char *context
= NULL
, *name
= NULL
;
3720 switch_live_array_t
*la
= NULL
;
3723 if ((jla
= cJSON_GetObjectItem(json
, "data")) && (jla
= cJSON_GetObjectItem(jla
, "liveArray"))) {
3725 if ((context
= cJSON_GetObjectCstr(jla
, "context")) && (name
= cJSON_GetObjectCstr(jla
, "name"))) {
3726 const char *command
= cJSON_GetObjectCstr(jla
, "command");
3727 const char *sessid
= cJSON_GetObjectCstr(json
, "sessid");
3730 if (switch_live_array_create(context
, name
, channel_id
, &la
) == SWITCH_STATUS_SUCCESS
) {
3732 if (!strcasecmp(command
, "bootstrap")) {
3733 switch_live_array_bootstrap(la
, sessid
, channel_id
);
3735 if (la
->command_handler
) {
3736 la
->command_handler(la
, command
, sessid
, jla
, la
->user_data
);
3739 switch_live_array_destroy(&la
);
3750 * indent-tabs-mode:t
3755 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: