Bug Summary

File:src/mod/applications/mod_hash/mod_hash.c
Location:line 891, column 9
Description:Potential leak of memory pointed to by 'item'

Annotated Source Code

1/*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4 *
5 * Version: MPL 1.1
6 *
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/
11 *
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
15 * License.
16 *
17 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18 *
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.
23 *
24 * Contributor(s):
25 *
26 * Anthony Minessale II <anthm@freeswitch.org>
27 * Ken Rice <krice at suspicious dot org
28 * Mathieu Rene <mathieu.rene@gmail.com>
29 * Bret McDanel <trixter AT 0xdecafbad.com>
30 * Rupa Schomaker <rupa@rupa.com>
31 *
32 * mod_hash.c -- Hash api, hash backend for limit
33 *
34 */
35
36#include <switch.h>
37#include "esl.h"
38
39#define LIMIT_HASH_CLEANUP_INTERVAL900 900
40
41SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)switch_status_t mod_hash_load (switch_loadable_module_interface_t
**module_interface, switch_memory_pool_t *pool)
;
42SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)switch_status_t mod_hash_shutdown (void);
43SWITCH_MODULE_DEFINITION(mod_hash, mod_hash_load, mod_hash_shutdown, NULL)static const char modname[] = "mod_hash" ; __attribute__((visibility
("default"))) switch_loadable_module_function_table_t mod_hash_module_interface
= { 5, mod_hash_load, mod_hash_shutdown, ((void*)0), SMODF_NONE
}
;
44
45/* CORE STUFF */
46static struct {
47 switch_memory_pool_t *pool;
48 switch_thread_rwlock_t *limit_hash_rwlock;
49 switch_hash_t *limit_hash;
50 switch_thread_rwlock_t *db_hash_rwlock;
51 switch_hash_t *db_hash;
52 switch_thread_rwlock_t *remote_hash_rwlock;
53 switch_hash_t *remote_hash;
54} globals;
55
56typedef struct {
57 uint32_t total_usage; /* < Total */
58 uint32_t rate_usage; /* < Current rate usage */
59 time_t last_check; /* < Last rate check */
60 uint32_t interval; /* < Interval used on last rate check */
61 switch_time_t last_update; /* < Last updated timestamp (rate or total) */
62} limit_hash_item_t;
63
64struct callback {
65 char *buf;
66 size_t len;
67 int matches;
68};
69
70typedef struct callback callback_t;
71
72/* HASH STUFF */
73typedef struct {
74 switch_hash_t *hash;
75} limit_hash_private_t;
76
77typedef enum {
78 REMOTE_OFF = 0, /* < Thread not running */
79 REMOTE_DOWN, /* <C annot connect to remote instance */
80 REMOTE_UP /* < All good */
81} limit_remote_state_t;
82
83static inline const char *state_str(limit_remote_state_t state) {
84 switch (state) {
85 case REMOTE_OFF:
86 return "Off";
87 case REMOTE_DOWN:
88 return "Down";
89 case REMOTE_UP:
90 return "Up";
91 }
92 return "";
93}
94
95typedef struct {
96 const char *name;
97 const char *host;
98 const char *username;
99 const char *password;
100 int port;
101
102 int interval;
103
104 esl_handle_t handle;
105
106 switch_hash_t *index;
107 switch_thread_rwlock_t *rwlock;
108 switch_memory_pool_t *pool;
109
110 switch_bool_t running;
111 switch_thread_t *thread;
112
113 limit_remote_state_t state;
114} limit_remote_t;
115
116static limit_hash_item_t get_remote_usage(const char *key);
117void limit_remote_destroy(limit_remote_t **r);
118static void do_config(switch_bool_t reload);
119
120
121/* \brief Enforces limit_hash restrictions
122 * \param session current session
123 * \param realm limit realm
124 * \param id limit id
125 * \param max maximum count
126 * \param interval interval for rate limiting
127 * \return SWITCH_TRUE if the access is allowed, SWITCH_FALSE if it isnt
128 */
129SWITCH_LIMIT_INCR(limit_incr_hash)static switch_status_t limit_incr_hash (switch_core_session_t
*session, const char *realm, const char *resource, const int
max, const int interval)
130{
131 switch_channel_t *channel = switch_core_session_get_channel(session);
132 char *hashkey = NULL((void*)0);
133 switch_status_t status = SWITCH_STATUS_SUCCESS;
134 limit_hash_item_t *item = NULL((void*)0);
135 time_t now = switch_epoch_time_now(NULL((void*)0));
136 limit_hash_private_t *pvt = NULL((void*)0);
137 uint8_t increment = 1;
138 limit_hash_item_t remote_usage;
139
140 hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
141
142 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
143 /* Check if that realm+resource has ever been checked */
144 if (!(item = (limit_hash_item_t *) switch_core_hash_find(globals.limit_hash, hashkey))) {
145 /* No, create an empty structure and add it, then continue like as if it existed */
146 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 146, (const char*)(session)
, SWITCH_LOG_DEBUG10, "Creating new limit structure: key: %s\n", hashkey);
147 item = (limit_hash_item_t *) malloc(sizeof(limit_hash_item_t));
148 switch_assert(item)((item) ? (void) (0) : __assert_fail ("item", "mod_hash.c", 148
, __PRETTY_FUNCTION__))
;
149 memset(item, 0, sizeof(limit_hash_item_t));
150 switch_core_hash_insert(globals.limit_hash, hashkey, item)switch_core_hash_insert_destructor(globals.limit_hash, hashkey
, item, ((void*)0))
;
151 }
152
153 if (!(pvt = switch_channel_get_private(channel, "limit_hash"))) {
154 pvt = (limit_hash_private_t *) switch_core_session_alloc(session, sizeof(limit_hash_private_t))switch_core_perform_session_alloc(session, sizeof(limit_hash_private_t
), "mod_hash.c", (const char *)__func__, 154)
;
155 memset(pvt, 0, sizeof(limit_hash_private_t));
156 switch_channel_set_private(channel, "limit_hash", pvt);
157 }
158 if (!(pvt->hash)) {
159 switch_core_hash_init(&pvt->hash)switch_core_hash_init_case(&pvt->hash, SWITCH_TRUE);
160 }
161 increment = !switch_core_hash_find(pvt->hash, hashkey);
162 remote_usage = get_remote_usage(hashkey);
163
164 if (interval > 0) {
165 item->interval = interval;
166 if (item->last_check <= (now - interval)) {
167 item->rate_usage = 1;
168 item->last_check = now;
169 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 169, (const char*)(session)
, SWITCH_LOG_DEBUG10, "Usage for %s reset to 1\n",
170 hashkey);
171 } else {
172 /* Always increment rate when its checked as it doesnt depend on the channel */
173 item->rate_usage++;
174
175 if ((max >= 0) && (item->rate_usage > (uint32_t) max)) {
176 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 176, (const char*)(session)
, SWITCH_LOG_INFO, "Usage for %s exceeds maximum rate of %d/%ds, now at %d\n",
177 hashkey, max, interval, item->rate_usage);
178 status = SWITCH_STATUS_GENERR;
179 goto end;
180 }
181 }
182 } else if ((max >= 0) && (item->total_usage + increment + remote_usage.total_usage > (uint32_t) max)) {
183 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 183, (const char*)(session)
, SWITCH_LOG_INFO, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage);
184 status = SWITCH_STATUS_GENERR;
185 goto end;
186 }
187
188 if (increment) {
189 item->total_usage++;
190
191 switch_core_hash_insert(pvt->hash, hashkey, item)switch_core_hash_insert_destructor(pvt->hash, hashkey, item
, ((void*)0))
;
192
193 if (max == -1) {
194 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 194, (const char*)(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d\n", hashkey, item->total_usage + remote_usage.total_usage);
195 } else if (interval == 0) {
196 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 196, (const char*)(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d/%d\n", hashkey, item->total_usage + remote_usage.total_usage, max);
197 } else {
198 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 198, (const char*)(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d/%d for the last %d seconds\n", hashkey,
199 item->rate_usage, max, interval);
200 }
201
202 switch_limit_fire_event("hash", realm, resource, item->total_usage, item->rate_usage, max, max >= 0 ? (uint32_t) max : 0);
203 }
204
205 /* Save current usage & rate into channel variables so it can be used later in the dialplan, or added to CDR records */
206 {
207 const char *susage = switch_core_session_sprintf(session, "%d", item->total_usage);
208 const char *srate = switch_core_session_sprintf(session, "%d", item->rate_usage);
209
210 switch_channel_set_variable(channel, "limit_usage", susage)switch_channel_set_variable_var_check(channel, "limit_usage",
susage, SWITCH_TRUE)
;
211 switch_channel_set_variable(channel, switch_core_session_sprintf(session, "limit_usage_%s", hashkey), susage)switch_channel_set_variable_var_check(channel, switch_core_session_sprintf
(session, "limit_usage_%s", hashkey), susage, SWITCH_TRUE)
;
212
213 switch_channel_set_variable(channel, "limit_rate", srate)switch_channel_set_variable_var_check(channel, "limit_rate", srate
, SWITCH_TRUE)
;
214 switch_channel_set_variable(channel, switch_core_session_sprintf(session, "limit_rate_%s", hashkey), srate)switch_channel_set_variable_var_check(channel, switch_core_session_sprintf
(session, "limit_rate_%s", hashkey), srate, SWITCH_TRUE)
;
215 }
216
217 end:
218 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
219 return status;
220}
221
222/* !\brief Determines whether a given entry is ready to be removed. */
223SWITCH_HASH_DELETE_FUNC(limit_hash_cleanup_delete_callback)static switch_bool_t limit_hash_cleanup_delete_callback (const
void *key, const void *val, void *pData)
{
224 limit_hash_item_t *item = (limit_hash_item_t *) val;
225 time_t now = switch_epoch_time_now(NULL((void*)0));
226
227 /* reset to 0 if window has passed so we can clean it up */
228 if (item->rate_usage > 0 && (item->last_check <= (now - item->interval))) {
229 item->rate_usage = 0;
230 }
231
232 if (item->total_usage == 0 && item->rate_usage == 0) {
233 /* Noone is using this item anymore */
234 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 234
, ((void*)0)
, SWITCH_LOG_DEBUG, "Freeing limit item: %s\n", (const char *) key);
235
236 free(item);
237 return SWITCH_TRUE;
238 }
239
240 return SWITCH_FALSE;
241}
242
243SWITCH_HASH_DELETE_FUNC(limit_hash_remote_cleanup_callback)static switch_bool_t limit_hash_remote_cleanup_callback (const
void *key, const void *val, void *pData)
244{
245 limit_hash_item_t *item = (limit_hash_item_t *) val;
246 switch_time_t now = (switch_time_t)(intptr_t)pData;
247
248 if (item->last_update != now) {
249 free(item);
250 return SWITCH_TRUE;
251 }
252
253 return SWITCH_FALSE;
254}
255
256/* !\brief Periodically checks for unused limit entries and frees them */
257SWITCH_STANDARD_SCHED_FUNC(limit_hash_cleanup_callback)static void limit_hash_cleanup_callback (switch_scheduler_task_t
*task)
258{
259 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
260 if (globals.limit_hash) {
261 switch_core_hash_delete_multi(globals.limit_hash, limit_hash_cleanup_delete_callback, NULL((void*)0));
262 }
263 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
264
265 if (globals.limit_hash) {
266 task->runtime = switch_epoch_time_now(NULL((void*)0)) + LIMIT_HASH_CLEANUP_INTERVAL900;
267 }
268}
269
270/* !\brief Releases usage of a limit_hash-controlled resource */
271SWITCH_LIMIT_RELEASE(limit_release_hash)static switch_status_t limit_release_hash (switch_core_session_t
*session, const char *realm, const char *resource)
272{
273 switch_channel_t *channel = switch_core_session_get_channel(session);
274 limit_hash_private_t *pvt = switch_channel_get_private(channel, "limit_hash");
275 limit_hash_item_t *item = NULL((void*)0);
276
277 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
278
279 if (!pvt || !pvt->hash) {
280 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
281 return SWITCH_STATUS_SUCCESS;
282 }
283
284 /* clear for uuid */
285 if (realm == NULL((void*)0) && resource == NULL((void*)0)) {
286 switch_hash_index_t *hi = NULL((void*)0);
287 /* Loop through the channel's hashtable which contains mapping to all the limit_hash_item_t referenced by that channel */
288 while ((hi = switch_core_hash_first_iter(pvt->hash, hi))) {
289 void *val = NULL((void*)0);
290 const void *key;
291 switch_ssize_t keylen;
292 limit_hash_item_t *item = NULL((void*)0);
293
294 switch_core_hash_this(hi, &key, &keylen, &val);
295
296 item = (limit_hash_item_t *) val;
297 item->total_usage--;
298 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 298, (const char*)(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d\n", (const char *) key, item->total_usage);
299
300 if (item->total_usage == 0 && item->rate_usage == 0) {
301 /* Noone is using this item anymore */
302 switch_core_hash_delete(globals.limit_hash, (const char *) key);
303 free(item);
304 }
305
306 switch_core_hash_delete(pvt->hash, (const char *) key);
307 }
308 switch_core_hash_destroy(&pvt->hash);
309 } else {
310 char *hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
311
312 if ((item = (limit_hash_item_t *) switch_core_hash_find(pvt->hash, hashkey))) {
313 item->total_usage--;
314 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 314, (const char*)(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d\n", (const char *) hashkey, item->total_usage);
315
316 switch_core_hash_delete(pvt->hash, hashkey);
317
318 if (item->total_usage == 0 && item->rate_usage == 0) {
319 /* Noone is using this item anymore */
320 switch_core_hash_delete(globals.limit_hash, (const char *) hashkey);
321 free(item);
322 }
323 }
324 }
325
326 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
327
328 return SWITCH_STATUS_SUCCESS;
329}
330
331SWITCH_LIMIT_USAGE(limit_usage_hash)static int limit_usage_hash (const char *realm, const char *resource
, uint32_t *rcount)
332{
333 char *hash_key = NULL((void*)0);
334 limit_hash_item_t *item = NULL((void*)0);
335 int count = 0;
336 limit_hash_item_t remote_usage;
337
338 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
339
340 hash_key = switch_mprintf("%s_%s", realm, resource);
341 remote_usage = get_remote_usage(hash_key);
342
343 count = remote_usage.total_usage;
344 *rcount = remote_usage.rate_usage;
345
346 if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
347 count += item->total_usage;
348 *rcount += item->rate_usage;
349 }
350
351 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
352 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
353
354 return count;
355}
356
357SWITCH_LIMIT_RESET(limit_reset_hash)static switch_status_t limit_reset_hash (void)
358{
359 return SWITCH_STATUS_GENERR;
360}
361
362SWITCH_LIMIT_INTERVAL_RESET(limit_interval_reset_hash)static switch_status_t limit_interval_reset_hash (const char *
realm, const char *resource)
363{
364 char *hash_key = NULL((void*)0);
365 limit_hash_item_t *item = NULL((void*)0);
366
367 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
368
369 hash_key = switch_mprintf("%s_%s", realm, resource);
370 if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
371 item->rate_usage = 0;
372 item->last_check = switch_epoch_time_now(NULL((void*)0));
373 }
374
375 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
376 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
377 return SWITCH_STATUS_SUCCESS;
378}
379
380SWITCH_LIMIT_STATUS(limit_status_hash)static char * limit_status_hash (void)
381{
382 /*
383 switch_hash_index_t *hi = NULL;
384 int count = 0;
385 char *ret = NULL;
386
387 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
388
389 for (hi = switch_core_hash_first(globals.limit_hash); hi; switch_core_hash_next(hi)) {
390 count++;
391 }
392
393 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
394
395 ret = switch_mprintf("There are %d elements being tracked.", count);
396 return ret;
397 */
398 return strdup("-ERR not supported yet (locking problems).")(__extension__ (__builtin_constant_p ("-ERR not supported yet (locking problems)."
) && ((size_t)(const void *)(("-ERR not supported yet (locking problems)."
) + 1) - (size_t)(const void *)("-ERR not supported yet (locking problems)."
) == 1) ? (((const char *) ("-ERR not supported yet (locking problems)."
))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) : ({
size_t __len = strlen ("-ERR not supported yet (locking problems)."
) + 1; char *__retval = (char *) malloc (__len); if (__retval
!= ((void*)0)) __retval = (char *) memcpy (__retval, "-ERR not supported yet (locking problems)."
, __len); __retval; })) : __strdup ("-ERR not supported yet (locking problems)."
)))
;
399}
400
401/* APP/API STUFF */
402
403/* CORE HASH STUFF */
404
405#define HASH_USAGE"[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>" "[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>"
406#define HASH_DESC"save data" "save data"
407
408SWITCH_STANDARD_APP(hash_function)static void hash_function (switch_core_session_t *session, const
char *data)
409{
410 int argc = 0;
411 char *argv[4] = { 0 };
412 char *mydata = NULL((void*)0);
413 char *hash_key = NULL((void*)0);
414 char *value = NULL((void*)0);
415
416 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
417
418 if (!zstr(data)_zstr(data)) {
419 mydata = strdup(data)(__extension__ (__builtin_constant_p (data) && ((size_t
)(const void *)((data) + 1) - (size_t)(const void *)(data) ==
1) ? (((const char *) (data))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (data) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, data, __len)
; __retval; })) : __strdup (data)))
;
420 switch_assert(mydata)((mydata) ? (void) (0) : __assert_fail ("mydata", "mod_hash.c"
, 420, __PRETTY_FUNCTION__))
;
421 argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
422 }
423
424 if (argc < 3 || !argv[0]) {
425 goto usage;
426 }
427
428 hash_key = switch_mprintf("%s_%s", argv[1], argv[2]);
429
430 if (!strcasecmp(argv[0], "insert")) {
431 if (argc < 4) {
432 goto usage;
433 }
434 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
435 free(value);
436 switch_core_hash_delete(globals.db_hash, hash_key);
437 }
438 value = strdup(argv[3])(__extension__ (__builtin_constant_p (argv[3]) && ((size_t
)(const void *)((argv[3]) + 1) - (size_t)(const void *)(argv[
3]) == 1) ? (((const char *) (argv[3]))[0] == '\0' ? (char *)
calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (
argv[3]) + 1; char *__retval = (char *) malloc (__len); if (__retval
!= ((void*)0)) __retval = (char *) memcpy (__retval, argv[3]
, __len); __retval; })) : __strdup (argv[3])))
;
439 switch_assert(value)((value) ? (void) (0) : __assert_fail ("value", "mod_hash.c",
439, __PRETTY_FUNCTION__))
;
440 switch_core_hash_insert(globals.db_hash, hash_key, value)switch_core_hash_insert_destructor(globals.db_hash, hash_key,
value, ((void*)0))
;
441 } else if (!strcasecmp(argv[0], "insert_ifempty")) {
442 if (argc < 4) {
443 goto usage;
444 }
445 if (!(value = switch_core_hash_find(globals.db_hash, hash_key))) {
446 value = strdup(argv[3])(__extension__ (__builtin_constant_p (argv[3]) && ((size_t
)(const void *)((argv[3]) + 1) - (size_t)(const void *)(argv[
3]) == 1) ? (((const char *) (argv[3]))[0] == '\0' ? (char *)
calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (
argv[3]) + 1; char *__retval = (char *) malloc (__len); if (__retval
!= ((void*)0)) __retval = (char *) memcpy (__retval, argv[3]
, __len); __retval; })) : __strdup (argv[3])))
;
447 switch_assert(value)((value) ? (void) (0) : __assert_fail ("value", "mod_hash.c",
447, __PRETTY_FUNCTION__))
;
448 switch_core_hash_insert(globals.db_hash, hash_key, value)switch_core_hash_insert_destructor(globals.db_hash, hash_key,
value, ((void*)0))
;
449 }
450
451 } else if (!strcasecmp(argv[0], "delete")) {
452 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
453 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
454 switch_core_hash_delete(globals.db_hash, hash_key);
455 }
456 } else if (!strcasecmp(argv[0], "delete_ifmatch")) {
457 if (argc < 4) {
458 goto usage;
459 }
460 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
461 if(!strcmp(argv[3], value)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(argv[3]) && __builtin_constant_p (value) &&
(__s1_len = __builtin_strlen (argv[3]), __s2_len = __builtin_strlen
(value), (!((size_t)(const void *)((argv[3]) + 1) - (size_t)
(const void *)(argv[3]) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((value) + 1) - (size_t)(const void
*)(value) == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv
[3], value) : (__builtin_constant_p (argv[3]) && ((size_t
)(const void *)((argv[3]) + 1) - (size_t)(const void *)(argv[
3]) == 1) && (__s1_len = __builtin_strlen (argv[3]), __s1_len
< 4) ? (__builtin_constant_p (value) && ((size_t)
(const void *)((value) + 1) - (size_t)(const void *)(value) ==
1) ? __builtin_strcmp (argv[3], value) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(value); int __result = (((const unsigned char *) (const char
*) (argv[3]))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
argv[3]))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
argv[3]))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (argv
[3]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(value) && ((size_t)(const void *)((value) + 1) - (size_t
)(const void *)(value) == 1) && (__s2_len = __builtin_strlen
(value), __s2_len < 4) ? (__builtin_constant_p (argv[3]) &&
((size_t)(const void *)((argv[3]) + 1) - (size_t)(const void
*)(argv[3]) == 1) ? __builtin_strcmp (argv[3], value) : (- (
__extension__ ({ const unsigned char *__s2 = (const unsigned char
*) (const char *) (argv[3]); int __result = (((const unsigned
char *) (const char *) (value))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (value))[1] - __s2[1]); if (__s2_len > 1
&& __result == 0) { __result = (((const unsigned char
*) (const char *) (value))[2] - __s2[2]); if (__s2_len > 2
&& __result == 0) __result = (((const unsigned char *
) (const char *) (value))[3] - __s2[3]); } } __result; })))) :
__builtin_strcmp (argv[3], value)))); })
) {
462 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
463 switch_core_hash_delete(globals.db_hash, hash_key);
464 }
465 }
466 } else {
467 goto usage;
468 }
469
470 goto done;
471
472 usage:
473 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 473, (const char*)(session)
, SWITCH_LOG_WARNING, "USAGE: hash %s\n", HASH_USAGE"[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>");
474
475 done:
476 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
477 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
478 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
479}
480
481#define HASH_API_USAGE"insert|insert_ifempty|select|delete|delete_ifmatch/realm/key[/value]" "insert|insert_ifempty|select|delete|delete_ifmatch/realm/key[/value]"
482SWITCH_STANDARD_API(hash_api_function)static switch_status_t hash_api_function ( const char *cmd, switch_core_session_t
*session, switch_stream_handle_t *stream)
483{
484 int argc = 0;
485 char *argv[4] = { 0 };
486 char *mydata = NULL((void*)0);
487 char *value = NULL((void*)0);
488 char *hash_key = NULL((void*)0);
489
490 if (!zstr(cmd)_zstr(cmd)) {
491 mydata = strdup(cmd)(__extension__ (__builtin_constant_p (cmd) && ((size_t
)(const void *)((cmd) + 1) - (size_t)(const void *)(cmd) == 1
) ? (((const char *) (cmd))[0] == '\0' ? (char *) calloc ((size_t
) 1, (size_t) 1) : ({ size_t __len = strlen (cmd) + 1; char *
__retval = (char *) malloc (__len); if (__retval != ((void*)0
)) __retval = (char *) memcpy (__retval, cmd, __len); __retval
; })) : __strdup (cmd)))
;
492 switch_assert(mydata)((mydata) ? (void) (0) : __assert_fail ("mydata", "mod_hash.c"
, 492, __PRETTY_FUNCTION__))
;
493 argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
494 }
495
496 if (argc < 3 || !argv[0]) {
497 goto usage;
498 }
499
500 hash_key = switch_mprintf("%s_%s", argv[1], argv[2]);
501
502 if (!strcasecmp(argv[0], "insert")) {
503 if (argc < 4) {
504 goto usage;
505 }
506 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
507 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
508 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
509 switch_core_hash_delete(globals.db_hash, hash_key);
510 }
511 value = strdup(argv[3])(__extension__ (__builtin_constant_p (argv[3]) && ((size_t
)(const void *)((argv[3]) + 1) - (size_t)(const void *)(argv[
3]) == 1) ? (((const char *) (argv[3]))[0] == '\0' ? (char *)
calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (
argv[3]) + 1; char *__retval = (char *) malloc (__len); if (__retval
!= ((void*)0)) __retval = (char *) memcpy (__retval, argv[3]
, __len); __retval; })) : __strdup (argv[3])))
;
512 switch_assert(value)((value) ? (void) (0) : __assert_fail ("value", "mod_hash.c",
512, __PRETTY_FUNCTION__))
;
513 switch_core_hash_insert(globals.db_hash, hash_key, value)switch_core_hash_insert_destructor(globals.db_hash, hash_key,
value, ((void*)0))
;
514 stream->write_function(stream, "+OK\n");
515 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
516 } else if (!strcasecmp(argv[0], "insert_ifempty")) {
517 if (argc < 4) {
518 goto usage;
519 }
520 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
521 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
522 stream->write_function(stream, "-ERR key already exists\n");
523 } else {
524 value = strdup(argv[3])(__extension__ (__builtin_constant_p (argv[3]) && ((size_t
)(const void *)((argv[3]) + 1) - (size_t)(const void *)(argv[
3]) == 1) ? (((const char *) (argv[3]))[0] == '\0' ? (char *)
calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (
argv[3]) + 1; char *__retval = (char *) malloc (__len); if (__retval
!= ((void*)0)) __retval = (char *) memcpy (__retval, argv[3]
, __len); __retval; })) : __strdup (argv[3])))
;
525 switch_assert(value)((value) ? (void) (0) : __assert_fail ("value", "mod_hash.c",
525, __PRETTY_FUNCTION__))
;
526 switch_core_hash_insert(globals.db_hash, hash_key, value)switch_core_hash_insert_destructor(globals.db_hash, hash_key,
value, ((void*)0))
;
527 stream->write_function(stream, "+OK\n");
528 }
529 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
530 } else if (!strcasecmp(argv[0], "delete")) {
531 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
532 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
533 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
534 switch_core_hash_delete(globals.db_hash, hash_key);
535 stream->write_function(stream, "+OK\n");
536 } else {
537 stream->write_function(stream, "-ERR Not found\n");
538 }
539 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
540 } else if (!strcasecmp(argv[0], "delete_ifmatch")) {
541 if (argc < 4) {
542 goto usage;
543 }
544 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
545 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
546 if(!strcmp(argv[3],value)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(argv[3]) && __builtin_constant_p (value) &&
(__s1_len = __builtin_strlen (argv[3]), __s2_len = __builtin_strlen
(value), (!((size_t)(const void *)((argv[3]) + 1) - (size_t)
(const void *)(argv[3]) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((value) + 1) - (size_t)(const void
*)(value) == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv
[3], value) : (__builtin_constant_p (argv[3]) && ((size_t
)(const void *)((argv[3]) + 1) - (size_t)(const void *)(argv[
3]) == 1) && (__s1_len = __builtin_strlen (argv[3]), __s1_len
< 4) ? (__builtin_constant_p (value) && ((size_t)
(const void *)((value) + 1) - (size_t)(const void *)(value) ==
1) ? __builtin_strcmp (argv[3], value) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(value); int __result = (((const unsigned char *) (const char
*) (argv[3]))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
argv[3]))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
argv[3]))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (argv
[3]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(value) && ((size_t)(const void *)((value) + 1) - (size_t
)(const void *)(value) == 1) && (__s2_len = __builtin_strlen
(value), __s2_len < 4) ? (__builtin_constant_p (argv[3]) &&
((size_t)(const void *)((argv[3]) + 1) - (size_t)(const void
*)(argv[3]) == 1) ? __builtin_strcmp (argv[3], value) : (- (
__extension__ ({ const unsigned char *__s2 = (const unsigned char
*) (const char *) (argv[3]); int __result = (((const unsigned
char *) (const char *) (value))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (value))[1] - __s2[1]); if (__s2_len > 1
&& __result == 0) { __result = (((const unsigned char
*) (const char *) (value))[2] - __s2[2]); if (__s2_len > 2
&& __result == 0) __result = (((const unsigned char *
) (const char *) (value))[3] - __s2[3]); } } __result; })))) :
__builtin_strcmp (argv[3], value)))); })
) {
547 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
548 switch_core_hash_delete(globals.db_hash, hash_key);
549 stream->write_function(stream, "+OK\n");
550 } else {
551 stream->write_function(stream, "-ERR Doesn't match\n");
552 }
553 } else {
554 stream->write_function(stream, "-ERR Not found\n");
555 }
556 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
557 } else if (!strcasecmp(argv[0], "select")) {
558 switch_thread_rwlock_rdlock(globals.db_hash_rwlock);
559 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
560 stream->write_function(stream, "%s", value);
561 }
562 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
563 } else {
564 goto usage;
565 }
566
567 goto done;
568
569 usage:
570 stream->write_function(stream, "-ERR Usage: hash %s\n", HASH_API_USAGE"insert|insert_ifempty|select|delete|delete_ifmatch/realm/key[/value]");
571
572 done:
573
574 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
575 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
576
577 return SWITCH_STATUS_SUCCESS;
578}
579
580#define HASH_DUMP_SYNTAX"all|limit|db [<realm>]" "all|limit|db [<realm>]"
581SWITCH_STANDARD_API(hash_dump_function)static switch_status_t hash_dump_function ( const char *cmd, switch_core_session_t
*session, switch_stream_handle_t *stream)
582{
583 int mode;
584 switch_hash_index_t *hi;
585 int argc = 0;
586 char *argv[4] = { 0 };
587 char *mydata = NULL((void*)0);
588 int realm = 0;
589 char *realmvalue = NULL((void*)0);
590
591 if (zstr(cmd)_zstr(cmd)) {
592 stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"all|limit|db [<realm>]""\n");
593 goto done;
594 }
595
596 mydata = strdup(cmd)(__extension__ (__builtin_constant_p (cmd) && ((size_t
)(const void *)((cmd) + 1) - (size_t)(const void *)(cmd) == 1
) ? (((const char *) (cmd))[0] == '\0' ? (char *) calloc ((size_t
) 1, (size_t) 1) : ({ size_t __len = strlen (cmd) + 1; char *
__retval = (char *) malloc (__len); if (__retval != ((void*)0
)) __retval = (char *) memcpy (__retval, cmd, __len); __retval
; })) : __strdup (cmd)))
;
597 switch_assert(mydata)((mydata) ? (void) (0) : __assert_fail ("mydata", "mod_hash.c"
, 597, __PRETTY_FUNCTION__))
;
598 argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
599 cmd = argv[0];
600
601 if (argc == 2) {
602 realm = 1;
603 realmvalue = switch_mprintf("%s_", argv[1]);
604 }
605
606 if (!strcmp(cmd, "all")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(cmd) && __builtin_constant_p ("all") && (__s1_len
= __builtin_strlen (cmd), __s2_len = __builtin_strlen ("all"
), (!((size_t)(const void *)((cmd) + 1) - (size_t)(const void
*)(cmd) == 1) || __s1_len >= 4) && (!((size_t)(const
void *)(("all") + 1) - (size_t)(const void *)("all") == 1) ||
__s2_len >= 4)) ? __builtin_strcmp (cmd, "all") : (__builtin_constant_p
(cmd) && ((size_t)(const void *)((cmd) + 1) - (size_t
)(const void *)(cmd) == 1) && (__s1_len = __builtin_strlen
(cmd), __s1_len < 4) ? (__builtin_constant_p ("all") &&
((size_t)(const void *)(("all") + 1) - (size_t)(const void *
)("all") == 1) ? __builtin_strcmp (cmd, "all") : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("all"); int __result = (((const unsigned char *) (const
char *) (cmd))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cmd))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cmd))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (cmd))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("all") && ((size_t)(const void *)(("all") + 1) - (size_t
)(const void *)("all") == 1) && (__s2_len = __builtin_strlen
("all"), __s2_len < 4) ? (__builtin_constant_p (cmd) &&
((size_t)(const void *)((cmd) + 1) - (size_t)(const void *)(
cmd) == 1) ? __builtin_strcmp (cmd, "all") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (cmd); int __result = (((const unsigned char *) (const
char *) ("all"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("all"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("all"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("all"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(cmd, "all")))); })
) {
607 mode = 3;
608 } else if (!strcmp(cmd, "limit")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(cmd) && __builtin_constant_p ("limit") && (
__s1_len = __builtin_strlen (cmd), __s2_len = __builtin_strlen
("limit"), (!((size_t)(const void *)((cmd) + 1) - (size_t)(const
void *)(cmd) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)(("limit") + 1) - (size_t)(const void *)("limit"
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (cmd, "limit"
) : (__builtin_constant_p (cmd) && ((size_t)(const void
*)((cmd) + 1) - (size_t)(const void *)(cmd) == 1) &&
(__s1_len = __builtin_strlen (cmd), __s1_len < 4) ? (__builtin_constant_p
("limit") && ((size_t)(const void *)(("limit") + 1) -
(size_t)(const void *)("limit") == 1) ? __builtin_strcmp (cmd
, "limit") : (__extension__ ({ const unsigned char *__s2 = (const
unsigned char *) (const char *) ("limit"); int __result = ((
(const unsigned char *) (const char *) (cmd))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (cmd))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (cmd))[2] - __s2[2]); if (__s1_len >
2 && __result == 0) __result = (((const unsigned char
*) (const char *) (cmd))[3] - __s2[3]); } } __result; }))) :
(__builtin_constant_p ("limit") && ((size_t)(const void
*)(("limit") + 1) - (size_t)(const void *)("limit") == 1) &&
(__s2_len = __builtin_strlen ("limit"), __s2_len < 4) ? (
__builtin_constant_p (cmd) && ((size_t)(const void *)
((cmd) + 1) - (size_t)(const void *)(cmd) == 1) ? __builtin_strcmp
(cmd, "limit") : (- (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (cmd); int __result
= (((const unsigned char *) (const char *) ("limit"))[0] - __s2
[0]); if (__s2_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) ("limit"))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) ("limit"))[2] - __s2
[2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) ("limit"))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (cmd, "limit")))
); })
) {
609 mode = 1;
610 } else if (!strcmp(cmd, "db")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(cmd) && __builtin_constant_p ("db") && (__s1_len
= __builtin_strlen (cmd), __s2_len = __builtin_strlen ("db")
, (!((size_t)(const void *)((cmd) + 1) - (size_t)(const void *
)(cmd) == 1) || __s1_len >= 4) && (!((size_t)(const
void *)(("db") + 1) - (size_t)(const void *)("db") == 1) || __s2_len
>= 4)) ? __builtin_strcmp (cmd, "db") : (__builtin_constant_p
(cmd) && ((size_t)(const void *)((cmd) + 1) - (size_t
)(const void *)(cmd) == 1) && (__s1_len = __builtin_strlen
(cmd), __s1_len < 4) ? (__builtin_constant_p ("db") &&
((size_t)(const void *)(("db") + 1) - (size_t)(const void *)
("db") == 1) ? __builtin_strcmp (cmd, "db") : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) ("db"); int __result = (((const unsigned char *) (const char
*) (cmd))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
cmd))[1] - __s2[1]); if (__s1_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) (cmd
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (cmd))[
3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("db"
) && ((size_t)(const void *)(("db") + 1) - (size_t)(const
void *)("db") == 1) && (__s2_len = __builtin_strlen (
"db"), __s2_len < 4) ? (__builtin_constant_p (cmd) &&
((size_t)(const void *)((cmd) + 1) - (size_t)(const void *)(
cmd) == 1) ? __builtin_strcmp (cmd, "db") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (cmd); int __result = (((const unsigned char *) (const
char *) ("db"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("db"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("db"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("db"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(cmd, "db")))); })
) {
611 mode = 2;
612 } else {
613 stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"all|limit|db [<realm>]""\n");
614 goto done;
615 }
616
617 if (mode & 1) {
618 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
619 for (hi = switch_core_hash_first(globals.limit_hash)switch_core_hash_first_iter(globals.limit_hash, ((void*)0)); hi; hi = switch_core_hash_next(&hi)) {
620 void *val = NULL((void*)0);
621 const void *key;
622 switch_ssize_t keylen;
623 limit_hash_item_t *item;
624 switch_core_hash_this(hi, &key, &keylen, &val);
625
626 item = (limit_hash_item_t *)val;
627
628 stream->write_function(stream, "L/%s/%d/%d/%d/%d\n", key, item->total_usage, item->rate_usage, item->interval, item->last_check);
629 }
630 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
631 }
632
633 if (mode & 2) {
634 switch_thread_rwlock_rdlock(globals.db_hash_rwlock);
635 for (hi = switch_core_hash_first(globals.db_hash)switch_core_hash_first_iter(globals.db_hash, ((void*)0)); hi; hi = switch_core_hash_next(&hi)) {
636 void *val = NULL((void*)0);
637 const void *key;
638 switch_ssize_t keylen;
639 switch_core_hash_this(hi, &key, &keylen, &val);
640 if (realm) {
641 if (strstr(key, realmvalue)) {
642 stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
643 }
644 } else {
645 stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
646 }
647 }
648 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
649 }
650
651 done:
652 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
653 switch_safe_free(realmvalue)if (realmvalue) {free(realmvalue);realmvalue=((void*)0);};
654
655 return SWITCH_STATUS_SUCCESS;
656}
657
658#define HASH_REMOTE_SYNTAX"list|kill [name]|rescan" "list|kill [name]|rescan"
659SWITCH_STANDARD_API(hash_remote_function)static switch_status_t hash_remote_function ( const char *cmd
, switch_core_session_t *session, switch_stream_handle_t *stream
)
660{
661 //int argc;
662 char *argv[10];
663 char *dup = NULL((void*)0);
664
665 if (zstr(cmd)_zstr(cmd)) {
666 stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"list|kill [name]|rescan""\n");
667 return SWITCH_STATUS_SUCCESS;
668 }
669
670 dup = strdup(cmd)(__extension__ (__builtin_constant_p (cmd) && ((size_t
)(const void *)((cmd) + 1) - (size_t)(const void *)(cmd) == 1
) ? (((const char *) (cmd))[0] == '\0' ? (char *) calloc ((size_t
) 1, (size_t) 1) : ({ size_t __len = strlen (cmd) + 1; char *
__retval = (char *) malloc (__len); if (__retval != ((void*)0
)) __retval = (char *) memcpy (__retval, cmd, __len); __retval
; })) : __strdup (cmd)))
;
671
672 switch_split(dup, ' ', argv)switch_separate_string(dup, ' ', argv, (sizeof(argv) / sizeof
(argv[0])))
;
673 if (argv[0] && !strcmp(argv[0], "list")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(argv[0]) && __builtin_constant_p ("list") &&
(__s1_len = __builtin_strlen (argv[0]), __s2_len = __builtin_strlen
("list"), (!((size_t)(const void *)((argv[0]) + 1) - (size_t
)(const void *)(argv[0]) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("list") + 1) - (size_t)(const void
*)("list") == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv
[0], "list") : (__builtin_constant_p (argv[0]) && ((size_t
)(const void *)((argv[0]) + 1) - (size_t)(const void *)(argv[
0]) == 1) && (__s1_len = __builtin_strlen (argv[0]), __s1_len
< 4) ? (__builtin_constant_p ("list") && ((size_t
)(const void *)(("list") + 1) - (size_t)(const void *)("list"
) == 1) ? __builtin_strcmp (argv[0], "list") : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("list"); int __result = (((const unsigned char *) (
const char *) (argv[0]))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (argv[0]))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (argv[0]))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (argv[0]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("list") && ((size_t)(const void *)(("list") + 1) - (
size_t)(const void *)("list") == 1) && (__s2_len = __builtin_strlen
("list"), __s2_len < 4) ? (__builtin_constant_p (argv[0])
&& ((size_t)(const void *)((argv[0]) + 1) - (size_t)
(const void *)(argv[0]) == 1) ? __builtin_strcmp (argv[0], "list"
) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (argv[0]); int __result = (((const unsigned
char *) (const char *) ("list"))[0] - __s2[0]); if (__s2_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("list"))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("list"))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) ("list"))[3] - __s2[3]); } } __result
; })))) : __builtin_strcmp (argv[0], "list")))); })
) {
674 switch_hash_index_t *hi;
675 stream->write_function(stream, "Remote connections:\nName\t\t\tState\n");
676
677 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
678 for (hi = switch_core_hash_first(globals.remote_hash)switch_core_hash_first_iter(globals.remote_hash, ((void*)0)); hi; hi = switch_core_hash_next(&hi)) {
679 void *val;
680 const void *key;
681 switch_ssize_t keylen;
682 limit_remote_t *item;
683 switch_core_hash_this(hi, &key, &keylen, &val);
684
685 item = (limit_remote_t *)val;
686 stream->write_function(stream, "%s\t\t\t%s\n", item->name, state_str(item->state));
687 }
688 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
689 stream->write_function(stream, "+OK\n");
690
691 } else if (argv[0] && !strcmp(argv[0], "kill")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(argv[0]) && __builtin_constant_p ("kill") &&
(__s1_len = __builtin_strlen (argv[0]), __s2_len = __builtin_strlen
("kill"), (!((size_t)(const void *)((argv[0]) + 1) - (size_t
)(const void *)(argv[0]) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("kill") + 1) - (size_t)(const void
*)("kill") == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv
[0], "kill") : (__builtin_constant_p (argv[0]) && ((size_t
)(const void *)((argv[0]) + 1) - (size_t)(const void *)(argv[
0]) == 1) && (__s1_len = __builtin_strlen (argv[0]), __s1_len
< 4) ? (__builtin_constant_p ("kill") && ((size_t
)(const void *)(("kill") + 1) - (size_t)(const void *)("kill"
) == 1) ? __builtin_strcmp (argv[0], "kill") : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("kill"); int __result = (((const unsigned char *) (
const char *) (argv[0]))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (argv[0]))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (argv[0]))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (argv[0]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("kill") && ((size_t)(const void *)(("kill") + 1) - (
size_t)(const void *)("kill") == 1) && (__s2_len = __builtin_strlen
("kill"), __s2_len < 4) ? (__builtin_constant_p (argv[0])
&& ((size_t)(const void *)((argv[0]) + 1) - (size_t)
(const void *)(argv[0]) == 1) ? __builtin_strcmp (argv[0], "kill"
) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (argv[0]); int __result = (((const unsigned
char *) (const char *) ("kill"))[0] - __s2[0]); if (__s2_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("kill"))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("kill"))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) ("kill"))[3] - __s2[3]); } } __result
; })))) : __builtin_strcmp (argv[0], "kill")))); })
) {
692 const char *name = argv[1];
693 limit_remote_t *remote;
694 if (zstr(name)_zstr(name)) {
695 stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"list|kill [name]|rescan""\n");
696 goto done;
697 }
698 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
699 remote = switch_core_hash_find(globals.remote_hash, name);
700 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
701
702 if (remote) {
703 limit_remote_destroy(&remote);
704
705 switch_thread_rwlock_wrlock(globals.remote_hash_rwlock);
706 switch_core_hash_delete(globals.remote_hash, name);
707 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
708
709 stream->write_function(stream, "+OK\n");
710 } else {
711 stream->write_function(stream, "-ERR No such remote instance %s\n", name);
712 }
713 } else if (argv[0] && !strcmp(argv[0], "rescan")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(argv[0]) && __builtin_constant_p ("rescan") &&
(__s1_len = __builtin_strlen (argv[0]), __s2_len = __builtin_strlen
("rescan"), (!((size_t)(const void *)((argv[0]) + 1) - (size_t
)(const void *)(argv[0]) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("rescan") + 1) - (size_t)(const void
*)("rescan") == 1) || __s2_len >= 4)) ? __builtin_strcmp (
argv[0], "rescan") : (__builtin_constant_p (argv[0]) &&
((size_t)(const void *)((argv[0]) + 1) - (size_t)(const void
*)(argv[0]) == 1) && (__s1_len = __builtin_strlen (argv
[0]), __s1_len < 4) ? (__builtin_constant_p ("rescan") &&
((size_t)(const void *)(("rescan") + 1) - (size_t)(const void
*)("rescan") == 1) ? __builtin_strcmp (argv[0], "rescan") : (
__extension__ ({ const unsigned char *__s2 = (const unsigned char
*) (const char *) ("rescan"); int __result = (((const unsigned
char *) (const char *) (argv[0]))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (argv[0]))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (argv[0]))[2] - __s2[2]); if (__s1_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) (argv[0]))[3] - __s2[3]); } } __result
; }))) : (__builtin_constant_p ("rescan") && ((size_t
)(const void *)(("rescan") + 1) - (size_t)(const void *)("rescan"
) == 1) && (__s2_len = __builtin_strlen ("rescan"), __s2_len
< 4) ? (__builtin_constant_p (argv[0]) && ((size_t
)(const void *)((argv[0]) + 1) - (size_t)(const void *)(argv[
0]) == 1) ? __builtin_strcmp (argv[0], "rescan") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (argv[0]); int __result = (((const unsigned char *) (
const char *) ("rescan"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("rescan"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("rescan"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("rescan"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(argv[0], "rescan")))); })
) {
714 do_config(SWITCH_TRUE);
715 stream->write_function(stream, "+OK\n");
716 } else {
717 stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"list|kill [name]|rescan""\n");
718
719 }
720
721done:
722
723 switch_safe_free(dup)if (dup) {free(dup);dup=((void*)0);};
724
725 return SWITCH_STATUS_SUCCESS;
726}
727
728limit_remote_t *limit_remote_create(const char *name, const char *host, uint16_t port, const char *username, const char *password, int interval)
729{
730 limit_remote_t *r;
731 switch_memory_pool_t *pool;
732
733 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
734 if (switch_core_hash_find(globals.remote_hash, name)) {
735 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 735
, ((void*)0)
, SWITCH_LOG_ERROR, "Already have a remote instance named %s\n", name);
736 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
737 return NULL((void*)0);
738 }
739 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
740
741 if (switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "mod_hash.c", (
const char *)__func__, 741)
!= SWITCH_STATUS_SUCCESS) {
742 return NULL((void*)0);
743 }
744
745 r = switch_core_alloc(pool, sizeof(limit_remote_t))switch_core_perform_alloc(pool, sizeof(limit_remote_t), "mod_hash.c"
, (const char *)__func__, 745)
;
746 r->pool = pool;
747 r->name = switch_core_strdup(r->pool, name)switch_core_perform_strdup(r->pool, name, "mod_hash.c", (const
char *)__func__, 747)
;
748 r->host = switch_core_strdup(r->pool, host)switch_core_perform_strdup(r->pool, host, "mod_hash.c", (const
char *)__func__, 748)
;
749 r->port = port;
750 r->username = switch_core_strdup(r->pool, username)switch_core_perform_strdup(r->pool, username, "mod_hash.c"
, (const char *)__func__, 750)
;
751 r->password = switch_core_strdup(r->pool, password)switch_core_perform_strdup(r->pool, password, "mod_hash.c"
, (const char *)__func__, 751)
;
752 r->interval = interval;
753
754 switch_thread_rwlock_create(&r->rwlock, pool);
755 switch_core_hash_init(&r->index)switch_core_hash_init_case(&r->index, SWITCH_TRUE);
756
757 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
758 switch_core_hash_insert(globals.remote_hash, name, r)switch_core_hash_insert_destructor(globals.remote_hash, name,
r, ((void*)0))
;
759 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
760
761 return r;
762}
763
764void limit_remote_destroy(limit_remote_t **r)
765{
766 if (r && *r) {
767 switch_hash_index_t *hi;
768
769 (*r)->state = REMOTE_OFF;
770
771 if ((*r)->thread) {
772 switch_status_t retval;
773 switch_thread_join(&retval, (*r)->thread);
774 }
775
776 switch_thread_rwlock_wrlock((*r)->rwlock);
777
778 /* Free hashtable data */
779 for (hi = switch_core_hash_first((*r)->index)switch_core_hash_first_iter((*r)->index, ((void*)0)); hi; hi = switch_core_hash_next(&hi)) {
780 void *val;
781 const void *key;
782 switch_ssize_t keylen;
783 switch_core_hash_this(hi, &key, &keylen, &val);
784
785 free(val);
786 }
787
788 switch_thread_rwlock_unlock((*r)->rwlock);
789 switch_thread_rwlock_destroy((*r)->rwlock);
790
791 switch_core_destroy_memory_pool(&((*r)->pool))switch_core_perform_destroy_memory_pool(&((*r)->pool),
"mod_hash.c", (const char *)__func__, 791)
;
792 *r = NULL((void*)0);
793 }
794}
795
796/* Compute the usage sum of a resource on remote boxes */
797static limit_hash_item_t get_remote_usage(const char *key) {
798 limit_hash_item_t usage = { 0 };
799 switch_hash_index_t *hi;
800
801 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
802 for (hi = switch_core_hash_first(globals.remote_hash)switch_core_hash_first_iter(globals.remote_hash, ((void*)0)); hi; hi = switch_core_hash_next(&hi)) {
803 void *val;
804 const void *hashkey;
805 switch_ssize_t keylen;
806 limit_remote_t *remote;
807 limit_hash_item_t *item;
808 switch_core_hash_this(hi, &hashkey, &keylen, &val);
809
810 remote = (limit_remote_t *)val;
811 if (remote->state != REMOTE_UP) {
812 continue;
813 }
814
815 switch_thread_rwlock_rdlock(remote->rwlock);
816 if ((item = switch_core_hash_find(remote->index, key))) {
817 usage.total_usage += item->total_usage;
818 usage.rate_usage += item->rate_usage;
819 if (!usage.last_check) {
820 usage.last_check = item->last_check;
821 }
822 }
823 switch_thread_rwlock_unlock(remote->rwlock);
824 }
825
826 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
827
828 return usage;
829}
830
831static void *SWITCH_THREAD_FUNC limit_remote_thread(switch_thread_t *thread, void *obj)
832{
833 limit_remote_t *remote = (limit_remote_t*)obj;
834 while (remote->state > REMOTE_OFF) {
1
Loop condition is true. Entering loop body
835 if (remote->state != REMOTE_UP) {
2
Taking false branch
836 if (esl_connect_timeout(&remote->handle, remote->host, (esl_port_t)remote->port, remote->username, remote->password, 5000) == ESL_SUCCESS) {
837 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 837
, ((void*)0)
, SWITCH_LOG_INFO, "Connected to remote FreeSWITCH (%s) at %s:%d\n",
838 remote->name, remote->host, remote->port);
839
840 remote->state = REMOTE_UP;
841 } else {
842 esl_disconnect(&remote->handle);
843 memset(&remote->handle, 0, sizeof(remote->handle));
844 }
845 } else {
846 if (esl_send_recv_timed(&remote->handle, "api hash_dump limit", 5000) != ESL_SUCCESS) {
3
Taking false branch
847 esl_disconnect(&remote->handle);
848 memset(&remote->handle, 0, sizeof(remote->handle));
849 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 849
, ((void*)0)
, SWITCH_LOG_WARNING, "Disconnected from remote FreeSWITCH (%s) at %s:%d\n",
850 remote->name, remote->host, remote->port);
851 memset(&remote->handle, 0, sizeof(remote->handle));
852 remote->state = REMOTE_DOWN;
853 /* Delete all remote tracking entries */
854 switch_thread_rwlock_wrlock(remote->rwlock);
855 switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, NULL((void*)0));
856 switch_thread_rwlock_unlock(remote->rwlock);
857 } else {
858 if (!zstr(remote->handle.last_sr_event->body)_zstr(remote->handle.last_sr_event->body)) {
4
Taking true branch
859 char *data = strdup(remote->handle.last_sr_event->body)(__extension__ (__builtin_constant_p (remote->handle.last_sr_event
->body) && ((size_t)(const void *)((remote->handle
.last_sr_event->body) + 1) - (size_t)(const void *)(remote
->handle.last_sr_event->body) == 1) ? (((const char *) (
remote->handle.last_sr_event->body))[0] == '\0' ? (char
*) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen
(remote->handle.last_sr_event->body) + 1; char *__retval
= (char *) malloc (__len); if (__retval != ((void*)0)) __retval
= (char *) memcpy (__retval, remote->handle.last_sr_event
->body, __len); __retval; })) : __strdup (remote->handle
.last_sr_event->body)))
;
860 char *p = data, *p2;
861 switch_time_t now = switch_epoch_time_now(NULL((void*)0));
862 while (p && *p) {
5
Loop condition is true. Entering loop body
863 /* We are getting the limit data as:
864 L/key/usage/rate/interval/last_checked
865 */
866 if ((p2 = strchr(p, '\n')(__extension__ (__builtin_constant_p ('\n') && !__builtin_constant_p
(p) && ('\n') == '\0' ? (char *) __rawmemchr (p, '\n'
) : __builtin_strchr (p, '\n')))
)) {
6
Assuming 'p2' is null
7
Taking false branch
867 *p2++ = '\0';
868 }
869
870 /* Now p points at the beginning of the current line,
871 p2 at the start of the next one */
872 if (*p == 'L') { /* Limit data */
8
Taking true branch
873 char *argv[5];
874 int argc = switch_split(p+2, '/', argv)switch_separate_string(p+2, '/', argv, (sizeof(argv) / sizeof
(argv[0])))
;
875
876 if (argc < 5) {
9
Assuming 'argc' is >= 5
10
Taking false branch
877 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 877
, ((void*)0)
, SWITCH_LOG_WARNING, "[%s] Protocol error: missing argument in line: %s\n",
878 remote->name, p);
879 } else {
880 limit_hash_item_t *item;
881 switch_thread_rwlock_wrlock(remote->rwlock);
882 if (!(item = switch_core_hash_find(remote->index, argv[0]))) {
11
Assuming 'item' is null
12
Taking true branch
883 item = malloc(sizeof(*item));
13
Memory is allocated
884 switch_core_hash_insert(remote->index, argv[0], item)switch_core_hash_insert_destructor(remote->index, argv[0],
item, ((void*)0))
;
885 }
886 item->total_usage = atoi(argv[1]);
887 item->rate_usage = atoi(argv[2]);
888 item->interval = atoi(argv[3]);
889 item->last_check = atoi(argv[4]);
890 item->last_update = now;
891 switch_thread_rwlock_unlock(remote->rwlock);
14
Potential leak of memory pointed to by 'item'
892 }
893 }
894
895 p = p2;
896 }
897 free(data);
898
899 /* Now free up anything that wasn't in this update since it means their usage is 0 */
900 switch_thread_rwlock_wrlock(remote->rwlock);
901 switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, (void*)(intptr_t)now);
902 switch_thread_rwlock_unlock(remote->rwlock);
903 }
904 }
905 }
906
907 switch_yield(remote->interval * 1000)switch_sleep(remote->interval * 1000);;
908 }
909
910 remote->thread = NULL((void*)0);
911
912 return NULL((void*)0);
913}
914
915static void do_config(switch_bool_t reload)
916{
917 switch_xml_t xml = NULL((void*)0), x_lists = NULL((void*)0), x_list = NULL((void*)0), cfg = NULL((void*)0);
918 if ((xml = switch_xml_open_cfg("hash.conf", &cfg, NULL((void*)0)))) {
919 if ((x_lists = switch_xml_child(cfg, "remotes"))) {
920 for (x_list = switch_xml_child(x_lists, "remote"); x_list; x_list = x_list->next) {
921 const char *name = switch_xml_attr(x_list, "name");
922 const char *host = switch_xml_attr(x_list, "host");
923 const char *szport = switch_xml_attr(x_list, "port");
924 const char *username = switch_xml_attr(x_list, "username");
925 const char *password = switch_xml_attr(x_list, "password");
926 const char *szinterval = switch_xml_attr(x_list, "interval");
927 uint16_t port = 0;
928 int interval = 0;
929 limit_remote_t *remote;
930 switch_threadattr_t *thd_attr = NULL((void*)0);
931
932 if (reload) {
933 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
934 if (switch_core_hash_find(globals.remote_hash, name)) {
935 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
936 continue;
937 }
938 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
939 }
940
941 if (!zstr(szport)_zstr(szport)) {
942 port = (uint16_t)atoi(szport);
943 }
944
945 if (!zstr(szinterval)_zstr(szinterval)) {
946 interval = atoi(szinterval);
947 }
948
949 remote = limit_remote_create(name, host, port, username, password, interval);
950
951 remote->state = REMOTE_DOWN;
952
953 switch_threadattr_create(&thd_attr, remote->pool);
954 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024);
955 switch_thread_create(&remote->thread, thd_attr, limit_remote_thread, remote, remote->pool);
956 }
957 }
958 switch_xml_free(xml);
959 }
960}
961
962/* INIT/DEINIT STUFF */
963SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)switch_status_t mod_hash_load (switch_loadable_module_interface_t
**module_interface, switch_memory_pool_t *pool)
964{
965 switch_application_interface_t *app_interface;
966 switch_api_interface_t *commands_api_interface;
967 switch_limit_interface_t *limit_interface;
968 switch_status_t status;
969
970 memset(&globals, 0, sizeof(globals));
971 globals.pool = pool;
972
973 status = switch_event_reserve_subclass(LIMIT_EVENT_USAGE)switch_event_reserve_subclass_detailed("mod_hash.c", "limit::usage"
)
;
974 if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_INUSE) {
975 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 975
, ((void*)0)
, SWITCH_LOG_ERROR, "Couldn't register event subclass \"%s\" (%d)\n", LIMIT_EVENT_USAGE"limit::usage", status);
976 return SWITCH_STATUS_FALSE;
977 }
978
979 switch_thread_rwlock_create(&globals.limit_hash_rwlock, globals.pool);
980 switch_thread_rwlock_create(&globals.db_hash_rwlock, globals.pool);
981 switch_thread_rwlock_create(&globals.remote_hash_rwlock, globals.pool);
982 switch_core_hash_init(&globals.limit_hash)switch_core_hash_init_case(&globals.limit_hash, SWITCH_TRUE
)
;
983 switch_core_hash_init(&globals.db_hash)switch_core_hash_init_case(&globals.db_hash, SWITCH_TRUE);
984 switch_core_hash_init(&globals.remote_hash)switch_core_hash_init_case(&globals.remote_hash, SWITCH_TRUE
)
;
985
986 /* connect my internal structure to the blank pointer passed to me */
987 *module_interface = switch_loadable_module_create_module_interface(pool, modname);
988
989 /* register limit interfaces */
990 SWITCH_ADD_LIMIT(limit_interface, "hash", limit_incr_hash, limit_release_hash, limit_usage_hash, limit_reset_hash, limit_status_hash, limit_interval_reset_hash)for (;;) { limit_interface = (switch_limit_interface_t *)switch_loadable_module_create_interface
(*module_interface, SWITCH_LIMIT_INTERFACE); limit_interface->
incr = limit_incr_hash; limit_interface->release = limit_release_hash
; limit_interface->usage = limit_usage_hash; limit_interface
->reset = limit_reset_hash; limit_interface->interval_reset
= limit_interval_reset_hash; limit_interface->status = limit_status_hash
; limit_interface->interface_name = "hash"; break; }
;
991
992 switch_scheduler_add_task(switch_epoch_time_now(NULL((void*)0)) + LIMIT_HASH_CLEANUP_INTERVAL900, limit_hash_cleanup_callback, "limit_hash_cleanup", "mod_hash", 0, NULL((void*)0),
993 SSHF_NONE);
994
995 SWITCH_ADD_APP(app_interface, "hash", "Insert into the hashtable", HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC)for (;;) { app_interface = (switch_application_interface_t *)
switch_loadable_module_create_interface(*module_interface, SWITCH_APPLICATION_INTERFACE
); app_interface->interface_name = "hash"; app_interface->
application_function = hash_function; app_interface->short_desc
= "Insert into the hashtable"; app_interface->long_desc =
"save data"; app_interface->syntax = "[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>"
; app_interface->flags = SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC
; break; }
996 SWITCH_ADD_API(commands_api_interface, "hash", "hash get/set", hash_api_function, "[insert|delete|select]/<realm>/<key>/<value>")for (;;) { commands_api_interface = (switch_api_interface_t *
)switch_loadable_module_create_interface(*module_interface, SWITCH_API_INTERFACE
); commands_api_interface->interface_name = "hash"; commands_api_interface
->desc = "hash get/set"; commands_api_interface->function
= hash_api_function; commands_api_interface->syntax = "[insert|delete|select]/<realm>/<key>/<value>"
; break; }
;
997 SWITCH_ADD_API(commands_api_interface, "hash_dump", "dump hash/limit_hash data (used for synchronization)", hash_dump_function, HASH_DUMP_SYNTAX)for (;;) { commands_api_interface = (switch_api_interface_t *
)switch_loadable_module_create_interface(*module_interface, SWITCH_API_INTERFACE
); commands_api_interface->interface_name = "hash_dump"; commands_api_interface
->desc = "dump hash/limit_hash data (used for synchronization)"
; commands_api_interface->function = hash_dump_function; commands_api_interface
->syntax = "all|limit|db [<realm>]"; break; }
;
998 SWITCH_ADD_API(commands_api_interface, "hash_remote", "hash remote", hash_remote_function, HASH_REMOTE_SYNTAX)for (;;) { commands_api_interface = (switch_api_interface_t *
)switch_loadable_module_create_interface(*module_interface, SWITCH_API_INTERFACE
); commands_api_interface->interface_name = "hash_remote";
commands_api_interface->desc = "hash remote"; commands_api_interface
->function = hash_remote_function; commands_api_interface->
syntax = "list|kill [name]|rescan"; break; }
;
999
1000 switch_console_set_complete("add hash insert");
1001 switch_console_set_complete("add hash delete");
1002 switch_console_set_complete("add hash select");
1003
1004 switch_console_set_complete("add hash_remote list");
1005 switch_console_set_complete("add hash_remote kill");
1006 switch_console_set_complete("add hash_remote rescan");
1007
1008 do_config(SWITCH_FALSE);
1009
1010 /* indicate that the module should continue to be loaded */
1011 return SWITCH_STATUS_SUCCESS;
1012}
1013
1014
1015SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)switch_status_t mod_hash_shutdown (void)
1016{
1017 switch_hash_index_t *hi = NULL((void*)0);
1018 switch_bool_t remote_clean = SWITCH_TRUE;
1019
1020 switch_scheduler_del_task_group("mod_hash");
1021
1022 /* Kill remote connections, destroy needs a wrlock so we unlock after finding a pointer */
1023 while(remote_clean) {
1024 void *val;
1025 const void *key = NULL((void*)0);
1026 switch_ssize_t keylen;
1027 limit_remote_t *item = NULL((void*)0);
1028
1029 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
1030 if ((hi = switch_core_hash_first(globals.remote_hash)switch_core_hash_first_iter(globals.remote_hash, ((void*)0)))) {
1031 switch_core_hash_this(hi, &key, &keylen, &val);
1032 item = (limit_remote_t *)val;
1033 }
1034 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
1035
1036 if (!item) {
1037 remote_clean = SWITCH_FALSE;
1038 } else {
1039 limit_remote_destroy(&item);
1040 switch_thread_rwlock_wrlock(globals.remote_hash_rwlock);
1041 switch_core_hash_delete(globals.remote_hash, key);
1042 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
1043 }
1044 }
1045
1046 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
1047 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
1048
1049 while ((hi = switch_core_hash_first_iter( globals.limit_hash, hi))) {
1050 void *val = NULL((void*)0);
1051 const void *key;
1052 switch_ssize_t keylen;
1053 switch_core_hash_this(hi, &key, &keylen, &val);
1054 free(val);
1055 switch_core_hash_delete(globals.limit_hash, key);
1056 }
1057
1058 while ((hi = switch_core_hash_first_iter( globals.db_hash, hi))) {
1059 void *val = NULL((void*)0);
1060 const void *key;
1061 switch_ssize_t keylen;
1062 switch_core_hash_this(hi, &key, &keylen, &val);
1063 free(val);
1064 switch_core_hash_delete(globals.db_hash, key);
1065 }
1066
1067 switch_core_hash_destroy(&globals.limit_hash);
1068 switch_core_hash_destroy(&globals.db_hash);
1069 switch_core_hash_destroy(&globals.remote_hash);
1070
1071 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
1072 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
1073
1074 switch_thread_rwlock_destroy(globals.db_hash_rwlock);
1075 switch_thread_rwlock_destroy(globals.limit_hash_rwlock);
1076 switch_thread_rwlock_destroy(globals.remote_hash_rwlock);
1077
1078
1079 return SWITCH_STATUS_SUCCESS;
1080}
1081
1082/* For Emacs:
1083 * Local Variables:
1084 * mode:c
1085 * indent-tabs-mode:t
1086 * tab-width:4
1087 * c-basic-offset:4
1088 * End:
1089 * For VIM:
1090 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1091 */