Bug Summary

File:mod_hash.c
Warning:line 560, column 8
Although the value stored to 'item' is used in the enclosing expression, the value is never actually read from 'item'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mod_hash.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -menable-no-infs -menable-no-nans -fapprox-func -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/drone/src/src/mod/applications/mod_hash -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D HAVE_CONFIG_H -I . -I ../../../../src/include -I ../../../../libs/esl/src/include -I ../../../../libs/xmlrpc-c -I /drone/src/src/include -I /drone/src/src/include -I /drone/src/libs/libteletone/src -D SWITCH_API_VISIBILITY=1 -D CJSON_API_VISIBILITY=1 -D HAVE_VISIBILITY=1 -I /usr/include/uuid -I /drone/src/src/include -I /drone/src/src/include -I /drone/src/libs/libteletone/src -D SWITCH_API_VISIBILITY=1 -D CJSON_API_VISIBILITY=1 -D HAVE_VISIBILITY=1 -D HAVE_OPENSSL -I /drone/src/libs/esl/src/include -D PIC -U NDEBUG -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-result -Wno-misleading-indentation -std=c99 -fdebug-compilation-dir=/drone/src/src/mod/applications/mod_hash -ferror-limit 19 -fvisibility hidden -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /drone/src/scan-build/2024-07-03-153247-157-1 -x c mod_hash.c
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*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG10, "Creating new limit structure: key: %s\n", hashkey);
147 item = (limit_hash_item_t *)switch_core_hash_insert_alloc(globals.limit_hash, hashkey, sizeof(limit_hash_item_t))switch_core_hash_insert_alloc_destructor(globals.limit_hash, hashkey
, sizeof(limit_hash_item_t), ((void*)0))
;
148 }
149
150 if (!(pvt = switch_channel_get_private(channel, "limit_hash"))) {
151 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__, 151)
;
152 memset(pvt, 0, sizeof(limit_hash_private_t));
153 switch_channel_set_private(channel, "limit_hash", pvt);
154 }
155 if (!(pvt->hash)) {
156 switch_core_hash_init(&pvt->hash)switch_core_hash_init_case(&pvt->hash, SWITCH_TRUE);
157 }
158 increment = !switch_core_hash_find(pvt->hash, hashkey);
159 remote_usage = get_remote_usage(hashkey);
160
161 if (interval > 0) {
162 item->interval = interval;
163 if (item->last_check <= (now - interval)) {
164 item->rate_usage = 1;
165 item->last_check = now;
166 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 166, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG10, "Usage for %s reset to 1\n",
167 hashkey);
168 } else {
169 /* Always increment rate when its checked as it doesnt depend on the channel */
170 item->rate_usage++;
171
172 if ((max >= 0) && (item->rate_usage > (uint32_t) max)) {
173 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 173, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_INFO, "Usage for %s exceeds maximum rate of %d/%ds, now at %d\n",
174 hashkey, max, interval, item->rate_usage);
175 status = SWITCH_STATUS_GENERR;
176 goto end;
177 }
178 }
179 } else if ((max >= 0) && (item->total_usage + increment + remote_usage.total_usage > (uint32_t) max)) {
180 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 180, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_INFO, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage);
181 status = SWITCH_STATUS_GENERR;
182 goto end;
183 }
184
185 if (increment) {
186 item->total_usage++;
187
188 switch_core_hash_insert(pvt->hash, hashkey, item)switch_core_hash_insert_destructor(pvt->hash, hashkey, item
, ((void*)0))
;
189
190 if (max == -1) {
191 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 191, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d\n", hashkey, item->total_usage + remote_usage.total_usage);
192 } else if (interval == 0) {
193 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 193, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d/%d\n", hashkey, item->total_usage + remote_usage.total_usage, max);
194 } else {
195 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 195, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d/%d for the last %d seconds\n", hashkey,
196 item->rate_usage, max, interval);
197 }
198
199 switch_limit_fire_event("hash", realm, resource, item->total_usage, item->rate_usage, max, max >= 0 ? (uint32_t) max : 0);
200 }
201
202 /* Save current usage & rate into channel variables so it can be used later in the dialplan, or added to CDR records */
203 {
204 const char *susage = switch_core_session_sprintf(session, "%d", item->total_usage);
205 const char *srate = switch_core_session_sprintf(session, "%d", item->rate_usage);
206
207 switch_channel_set_variable(channel, "limit_usage", susage)switch_channel_set_variable_var_check(channel, "limit_usage",
susage, SWITCH_TRUE)
;
208 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)
;
209
210 switch_channel_set_variable(channel, "limit_rate", srate)switch_channel_set_variable_var_check(channel, "limit_rate", srate
, SWITCH_TRUE)
;
211 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)
;
212 }
213
214 end:
215 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
216 return status;
217}
218
219/* !\brief Determines whether a given entry is ready to be removed. */
220SWITCH_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)
{
221 limit_hash_item_t *item = (limit_hash_item_t *) val;
222 time_t now = switch_epoch_time_now(NULL((void*)0));
223
224 /* reset to 0 if window has passed so we can clean it up */
225 if (item->rate_usage > 0 && (item->last_check <= (now - item->interval))) {
226 item->rate_usage = 0;
227 }
228
229 if (item->total_usage == 0 && item->rate_usage == 0) {
230 /* Noone is using this item anymore */
231 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 231
, ((void*)0)
, SWITCH_LOG_DEBUG, "Freeing limit item: %s\n", (const char *) key);
232
233 free(item);
234 return SWITCH_TRUE;
235 }
236
237 return SWITCH_FALSE;
238}
239
240SWITCH_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)
241{
242 limit_hash_item_t *item = (limit_hash_item_t *) val;
243 switch_time_t now = (switch_time_t)(intptr_t)pData;
244
245 if (item->last_update != now) {
246 return SWITCH_TRUE;
247 }
248
249 return SWITCH_FALSE;
250}
251
252/* !\brief Periodically checks for unused limit entries and frees them */
253SWITCH_STANDARD_SCHED_FUNC(limit_hash_cleanup_callback)static void limit_hash_cleanup_callback (switch_scheduler_task_t
*task)
254{
255 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
256 if (globals.limit_hash) {
257 switch_core_hash_delete_multi(globals.limit_hash, limit_hash_cleanup_delete_callback, NULL((void*)0));
258 }
259 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
260
261 if (globals.limit_hash) {
262 task->runtime = switch_epoch_time_now(NULL((void*)0)) + LIMIT_HASH_CLEANUP_INTERVAL900;
263 }
264}
265
266/* !\brief Releases usage of a limit_hash-controlled resource */
267SWITCH_LIMIT_RELEASE(limit_release_hash)static switch_status_t limit_release_hash (switch_core_session_t
*session, const char *realm, const char *resource)
268{
269 switch_channel_t *channel = switch_core_session_get_channel(session);
270 limit_hash_private_t *pvt = switch_channel_get_private(channel, "limit_hash");
271 limit_hash_item_t *item = NULL((void*)0);
272
273 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
274
275 if (!pvt || !pvt->hash) {
276 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
277 return SWITCH_STATUS_SUCCESS;
278 }
279
280 /* clear for uuid */
281 if (realm == NULL((void*)0) && resource == NULL((void*)0)) {
282 switch_hash_index_t *hi = NULL((void*)0);
283 /* Loop through the channel's hashtable which contains mapping to all the limit_hash_item_t referenced by that channel */
284 while ((hi = switch_core_hash_first_iter(pvt->hash, hi))) {
285 void *val = NULL((void*)0);
286 const void *key;
287 switch_ssize_t keylen;
288
289 switch_core_hash_this(hi, &key, &keylen, &val);
290
291 item = (limit_hash_item_t *) val;
292 item->total_usage--;
293 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 293, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d\n", (const char *) key, item->total_usage);
294
295 if (item->total_usage == 0 && item->rate_usage == 0) {
296 /* Noone is using this item anymore */
297 switch_core_hash_delete(globals.limit_hash, (const char *) key);
298 free(item);
299 }
300
301 switch_core_hash_delete(pvt->hash, (const char *) key);
302 }
303 switch_core_hash_destroy(&pvt->hash);
304 } else {
305 char *hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
306
307 if ((item = (limit_hash_item_t *) switch_core_hash_find(pvt->hash, hashkey))) {
308 item->total_usage--;
309 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 309, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_DEBUG, "Usage for %s is now %d\n", (const char *) hashkey, item->total_usage);
310
311 switch_core_hash_delete(pvt->hash, hashkey);
312
313 if (item->total_usage == 0 && item->rate_usage == 0) {
314 /* Noone is using this item anymore */
315 switch_core_hash_delete(globals.limit_hash, (const char *) hashkey);
316 free(item);
317 }
318 }
319 }
320
321 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
322
323 return SWITCH_STATUS_SUCCESS;
324}
325
326SWITCH_LIMIT_USAGE(limit_usage_hash)static int limit_usage_hash (const char *realm, const char *resource
, uint32_t *rcount)
327{
328 char *hash_key = NULL((void*)0);
329 limit_hash_item_t *item = NULL((void*)0);
330 int count = 0;
331 limit_hash_item_t remote_usage;
332
333 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
334
335 hash_key = switch_mprintf("%s_%s", realm, resource);
336 remote_usage = get_remote_usage(hash_key);
337
338 count = remote_usage.total_usage;
339 *rcount = remote_usage.rate_usage;
340
341 if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
342 count += item->total_usage;
343 *rcount += item->rate_usage;
344 }
345
346 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
347 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
348
349 return count;
350}
351
352SWITCH_LIMIT_RESET(limit_reset_hash)static switch_status_t limit_reset_hash (void)
353{
354 return SWITCH_STATUS_GENERR;
355}
356
357SWITCH_LIMIT_INTERVAL_RESET(limit_interval_reset_hash)static switch_status_t limit_interval_reset_hash (const char *
realm, const char *resource)
358{
359 char *hash_key = NULL((void*)0);
360 limit_hash_item_t *item = NULL((void*)0);
361
362 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
363
364 hash_key = switch_mprintf("%s_%s", realm, resource);
365 if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
366 item->rate_usage = 0;
367 item->last_check = switch_epoch_time_now(NULL((void*)0));
368 }
369
370 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
371 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
372 return SWITCH_STATUS_SUCCESS;
373}
374
375SWITCH_LIMIT_STATUS(limit_status_hash)static char * limit_status_hash (void)
376{
377 /*
378 switch_hash_index_t *hi = NULL;
379 int count = 0;
380 char *ret = NULL;
381
382 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
383
384 for (hi = switch_core_hash_first(globals.limit_hash); hi; switch_core_hash_next(hi)) {
385 count++;
386 }
387
388 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
389
390 ret = switch_mprintf("There are %d elements being tracked.", count);
391 return ret;
392 */
393 return strdup("-ERR not supported yet (locking problems).");
394}
395
396/* APP/API STUFF */
397
398/* CORE HASH STUFF */
399
400#define HASH_USAGE"[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>" "[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>"
401#define HASH_DESC"save data" "save data"
402
403SWITCH_STANDARD_APP(hash_function)static void hash_function (switch_core_session_t *session, const
char *data)
404{
405 int argc = 0;
406 char *argv[4] = { 0 };
407 char *mydata = NULL((void*)0);
408 char *hash_key = NULL((void*)0);
409 char *value = NULL((void*)0);
410
411 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
412
413 if (!zstr(data)_zstr(data)) {
414 mydata = strdup(data);
415 switch_assert(mydata)((mydata) ? (void) (0) : __assert_fail ("mydata", "mod_hash.c"
, 415, __extension__ __PRETTY_FUNCTION__))
;
416 argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
417 }
418
419 if (argc < 3 || !argv[0]) {
420 goto usage;
421 }
422
423 hash_key = switch_mprintf("%s_%s", argv[1], argv[2]);
424
425 if (!strcasecmp(argv[0], "insert")) {
426 if (argc < 4) {
427 goto usage;
428 }
429 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
430 free(value);
431 switch_core_hash_delete(globals.db_hash, hash_key);
432 }
433 switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3])switch_core_hash_insert_dup_destructor(globals.db_hash, hash_key
, argv[3], ((void*)0))
;
434 } else if (!strcasecmp(argv[0], "insert_ifempty")) {
435 if (argc < 4) {
436 goto usage;
437 }
438 if (!switch_core_hash_find(globals.db_hash, hash_key)) {
439 switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3])switch_core_hash_insert_dup_destructor(globals.db_hash, hash_key
, argv[3], ((void*)0))
;
440 }
441
442 } else if (!strcasecmp(argv[0], "delete")) {
443 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
444 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
445 switch_core_hash_delete(globals.db_hash, hash_key);
446 }
447 } else if (!strcasecmp(argv[0], "delete_ifmatch")) {
448 if (argc < 4) {
449 goto usage;
450 }
451 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
452 if(!strcmp(argv[3], value)) {
453 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
454 switch_core_hash_delete(globals.db_hash, hash_key);
455 }
456 }
457 } else {
458 goto usage;
459 }
460
461 goto done;
462
463 usage:
464 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_hash.c", (const char *)__func__
, 464, (const char*)switch_core_session_type_check(session)
, SWITCH_LOG_WARNING, "USAGE: hash %s\n", HASH_USAGE"[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>");
465
466 done:
467 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
468 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
469 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
470}
471
472#define HASH_API_USAGE"insert|insert_ifempty|select|delete|delete_ifmatch|select_limit|delete_limit/realm/key[/value]" "insert|insert_ifempty|select|delete|delete_ifmatch|select_limit|delete_limit/realm/key[/value]"
473SWITCH_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)
474{
475 int argc = 0;
476 char *argv[4] = { 0 };
477 char *mydata = NULL((void*)0);
478 char *value = NULL((void*)0);
479 char *hash_key = NULL((void*)0);
480
481 if (!zstr(cmd)_zstr(cmd)) {
482 mydata = strdup(cmd);
483 switch_assert(mydata)((mydata) ? (void) (0) : __assert_fail ("mydata", "mod_hash.c"
, 483, __extension__ __PRETTY_FUNCTION__))
;
484 argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
485 }
486
487 if (argc < 3 || !argv[0]) {
488 goto usage;
489 }
490
491 hash_key = switch_mprintf("%s_%s", argv[1], argv[2]);
492
493 if (!strcasecmp(argv[0], "insert")) {
494 if (argc < 4) {
495 goto usage;
496 }
497 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
498 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
499 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
500 switch_core_hash_delete(globals.db_hash, hash_key);
501 }
502 switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3])switch_core_hash_insert_dup_destructor(globals.db_hash, hash_key
, argv[3], ((void*)0))
;
503 stream->write_function(stream, "+OK\n");
504 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
505 } else if (!strcasecmp(argv[0], "insert_ifempty")) {
506 if (argc < 4) {
507 goto usage;
508 }
509 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
510 if (switch_core_hash_find(globals.db_hash, hash_key)) {
511 stream->write_function(stream, "-ERR key already exists\n");
512 } else {
513 switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3])switch_core_hash_insert_dup_destructor(globals.db_hash, hash_key
, argv[3], ((void*)0))
;
514 stream->write_function(stream, "+OK\n");
515 }
516 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
517 } else if (!strcasecmp(argv[0], "delete")) {
518 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
519 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
520 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
521 switch_core_hash_delete(globals.db_hash, hash_key);
522 stream->write_function(stream, "+OK\n");
523 } else {
524 stream->write_function(stream, "-ERR Not found\n");
525 }
526 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
527 } else if (!strcasecmp(argv[0], "delete_ifmatch")) {
528 if (argc < 4) {
529 goto usage;
530 }
531 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
532 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
533 if(!strcmp(argv[3],value)) {
534 switch_safe_free(value)if (value) {free(value);value=((void*)0);};
535 switch_core_hash_delete(globals.db_hash, hash_key);
536 stream->write_function(stream, "+OK\n");
537 } else {
538 stream->write_function(stream, "-ERR Doesn't match\n");
539 }
540 } else {
541 stream->write_function(stream, "-ERR Not found\n");
542 }
543 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
544 } else if (!strcasecmp(argv[0], "select")) {
545 switch_thread_rwlock_rdlock(globals.db_hash_rwlock);
546 if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
547 stream->write_function(stream, "%s", value);
548 }
549 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
550 } else if (!strcasecmp(argv[0], "select_limit")) {
551 limit_hash_item_t *item = NULL((void*)0);
552 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
553 if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
554 stream->write_function(stream, "%d", item->total_usage);
555 }
556 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
557 } else if (!strcasecmp(argv[0], "delete_limit")) {
558 limit_hash_item_t *item = NULL((void*)0);
559 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
560 if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
Although the value stored to 'item' is used in the enclosing expression, the value is never actually read from 'item'
561 switch_core_hash_delete(globals.limit_hash, hash_key);
562 stream->write_function(stream, "+OK\n");
563 } else {
564 stream->write_function(stream, "-ERR Not found\n");
565 }
566 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
567 } else {
568 goto usage;
569 }
570
571 goto done;
572
573 usage:
574 stream->write_function(stream, "-ERR Usage: hash %s\n", HASH_API_USAGE"insert|insert_ifempty|select|delete|delete_ifmatch|select_limit|delete_limit/realm/key[/value]");
575
576 done:
577
578 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
579 switch_safe_free(hash_key)if (hash_key) {free(hash_key);hash_key=((void*)0);};
580
581 return SWITCH_STATUS_SUCCESS;
582}
583
584#define HASH_DUMP_SYNTAX"all|limit|db [<realm>]" "all|limit|db [<realm>]"
585SWITCH_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)
586{
587 int mode;
588 switch_hash_index_t *hi;
589 int argc = 0;
590 char *argv[4] = { 0 };
591 char *mydata = NULL((void*)0);
592 int realm = 0;
593 char *realmvalue = NULL((void*)0);
594
595 if (zstr(cmd)_zstr(cmd)) {
596 stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"all|limit|db [<realm>]""\n");
597 goto done;
598 }
599
600 mydata = strdup(cmd);
601 switch_assert(mydata)((mydata) ? (void) (0) : __assert_fail ("mydata", "mod_hash.c"
, 601, __extension__ __PRETTY_FUNCTION__))
;
602 argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
603 cmd = argv[0];
604
605 if (argc == 2) {
606 realm = 1;
607 realmvalue = switch_mprintf("%s_", argv[1]);
608 }
609
610 if (!strcmp(cmd, "all")) {
611 mode = 3;
612 } else if (!strcmp(cmd, "limit")) {
613 mode = 1;
614 } else if (!strcmp(cmd, "db")) {
615 mode = 2;
616 } else {
617 stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"all|limit|db [<realm>]""\n");
618 goto done;
619 }
620
621 if (mode & 1) {
622 switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
623 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)) {
624 void *val = NULL((void*)0);
625 const void *key;
626 switch_ssize_t keylen;
627 limit_hash_item_t *item;
628 switch_core_hash_this(hi, &key, &keylen, &val);
629
630 item = (limit_hash_item_t *)val;
631
632 stream->write_function(stream, "L/%s/%d/%d/%d/%d\n", key, item->total_usage, item->rate_usage, item->interval, item->last_check);
633 }
634 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
635 }
636
637 if (mode & 2) {
638 switch_thread_rwlock_rdlock(globals.db_hash_rwlock);
639 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)) {
640 void *val = NULL((void*)0);
641 const void *key;
642 switch_ssize_t keylen;
643 switch_core_hash_this(hi, &key, &keylen, &val);
644 if (realm) {
645 if (strstr(key, realmvalue)) {
646 stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
647 }
648 } else {
649 stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
650 }
651 }
652 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
653 }
654
655 done:
656 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
657 switch_safe_free(realmvalue)if (realmvalue) {free(realmvalue);realmvalue=((void*)0);};
658
659 return SWITCH_STATUS_SUCCESS;
660}
661
662#define HASH_REMOTE_SYNTAX"list|kill [name]|rescan" "list|kill [name]|rescan"
663SWITCH_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
)
664{
665 //int argc;
666 char *argv[10];
667 char *dup = NULL((void*)0);
668
669 if (zstr(cmd)_zstr(cmd)) {
670 stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"list|kill [name]|rescan""\n");
671 return SWITCH_STATUS_SUCCESS;
672 }
673
674 dup = strdup(cmd);
675
676 switch_split(dup, ' ', argv)switch_separate_string(dup, ' ', argv, (sizeof(argv) / sizeof
(argv[0])))
;
677 if (argv[0] && !strcmp(argv[0], "list")) {
678 switch_hash_index_t *hi;
679 stream->write_function(stream, "Remote connections:\nName\t\t\tState\n");
680
681 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
682 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)) {
683 void *val;
684 const void *key;
685 switch_ssize_t keylen;
686 limit_remote_t *item;
687 switch_core_hash_this(hi, &key, &keylen, &val);
688
689 item = (limit_remote_t *)val;
690 stream->write_function(stream, "%s\t\t\t%s\n", item->name, state_str(item->state));
691 }
692 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
693 stream->write_function(stream, "+OK\n");
694
695 } else if (argv[0] && !strcmp(argv[0], "kill")) {
696 const char *name = argv[1];
697 limit_remote_t *remote;
698 if (zstr(name)_zstr(name)) {
699 stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"list|kill [name]|rescan""\n");
700 goto done;
701 }
702 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
703 remote = switch_core_hash_find(globals.remote_hash, name);
704 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
705
706 if (remote) {
707 limit_remote_destroy(&remote);
708
709 switch_thread_rwlock_wrlock(globals.remote_hash_rwlock);
710 switch_core_hash_delete(globals.remote_hash, name);
711 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
712
713 stream->write_function(stream, "+OK\n");
714 } else {
715 stream->write_function(stream, "-ERR No such remote instance %s\n", name);
716 }
717 } else if (argv[0] && !strcmp(argv[0], "rescan")) {
718 do_config(SWITCH_TRUE);
719 stream->write_function(stream, "+OK\n");
720 } else {
721 stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"list|kill [name]|rescan""\n");
722
723 }
724
725done:
726
727 switch_safe_free(dup)if (dup) {free(dup);dup=((void*)0);};
728
729 return SWITCH_STATUS_SUCCESS;
730}
731
732limit_remote_t *limit_remote_create(const char *name, const char *host, uint16_t port, const char *username, const char *password, int interval)
733{
734 limit_remote_t *r;
735 switch_memory_pool_t *pool;
736
737 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
738 if (switch_core_hash_find(globals.remote_hash, name)) {
739 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 739
, ((void*)0)
, SWITCH_LOG_ERROR, "Already have a remote instance named %s\n", name);
740 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
741 return NULL((void*)0);
742 }
743 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
744
745 if (switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "mod_hash.c", (
const char *)__func__, 745)
!= SWITCH_STATUS_SUCCESS) {
746 return NULL((void*)0);
747 }
748
749 r = switch_core_alloc(pool, sizeof(limit_remote_t))switch_core_perform_alloc(pool, sizeof(limit_remote_t), "mod_hash.c"
, (const char *)__func__, 749)
;
750 r->pool = pool;
751 r->name = switch_core_strdup(r->pool, name)switch_core_perform_strdup(r->pool, name, "mod_hash.c", (const
char *)__func__, 751)
;
752 r->host = switch_core_strdup(r->pool, host)switch_core_perform_strdup(r->pool, host, "mod_hash.c", (const
char *)__func__, 752)
;
753 r->port = port;
754 r->username = switch_core_strdup(r->pool, username)switch_core_perform_strdup(r->pool, username, "mod_hash.c"
, (const char *)__func__, 754)
;
755 r->password = switch_core_strdup(r->pool, password)switch_core_perform_strdup(r->pool, password, "mod_hash.c"
, (const char *)__func__, 755)
;
756 r->interval = interval;
757
758 switch_thread_rwlock_create(&r->rwlock, pool);
759 switch_core_hash_init(&r->index)switch_core_hash_init_case(&r->index, SWITCH_TRUE);
760
761 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
762 switch_core_hash_insert(globals.remote_hash, name, r)switch_core_hash_insert_destructor(globals.remote_hash, name,
r, ((void*)0))
;
763 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
764
765 return r;
766}
767
768void limit_remote_destroy(limit_remote_t **r)
769{
770 if (r && *r) {
771 (*r)->state = REMOTE_OFF;
772
773 if ((*r)->thread) {
774 switch_status_t retval;
775 switch_thread_join(&retval, (*r)->thread);
776 }
777
778 switch_thread_rwlock_wrlock((*r)->rwlock);
779
780 /* Free hashtable data */
781 switch_core_hash_destroy(&(*r)->index);
782
783 switch_thread_rwlock_unlock((*r)->rwlock);
784 switch_thread_rwlock_destroy((*r)->rwlock);
785
786 switch_core_destroy_memory_pool(&((*r)->pool))switch_core_perform_destroy_memory_pool(&((*r)->pool),
"mod_hash.c", (const char *)__func__, 786)
;
787 *r = NULL((void*)0);
788 }
789}
790
791/* Compute the usage sum of a resource on remote boxes */
792static limit_hash_item_t get_remote_usage(const char *key) {
793 limit_hash_item_t usage = { 0 };
794 switch_hash_index_t *hi;
795
796 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
797 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)) {
798 void *val;
799 const void *hashkey;
800 switch_ssize_t keylen;
801 limit_remote_t *remote;
802 limit_hash_item_t *item;
803 switch_core_hash_this(hi, &hashkey, &keylen, &val);
804
805 remote = (limit_remote_t *)val;
806 if (remote->state != REMOTE_UP) {
807 continue;
808 }
809
810 switch_thread_rwlock_rdlock(remote->rwlock);
811 if ((item = switch_core_hash_find(remote->index, key))) {
812 usage.total_usage += item->total_usage;
813 usage.rate_usage += item->rate_usage;
814 if (!usage.last_check) {
815 usage.last_check = item->last_check;
816 }
817 }
818 switch_thread_rwlock_unlock(remote->rwlock);
819 }
820
821 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
822
823 return usage;
824}
825
826static void *SWITCH_THREAD_FUNC limit_remote_thread(switch_thread_t *thread, void *obj)
827{
828 limit_remote_t *remote = (limit_remote_t*)obj;
829 while (remote->state > REMOTE_OFF) {
830 if (remote->state != REMOTE_UP) {
831 if (esl_connect_timeout(&remote->handle, remote->host, (esl_port_t)remote->port, remote->username, remote->password, 5000) == ESL_SUCCESS) {
832 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 832
, ((void*)0)
, SWITCH_LOG_INFO, "Connected to remote FreeSWITCH (%s) at %s:%d\n",
833 remote->name, remote->host, remote->port);
834
835 remote->state = REMOTE_UP;
836 } else {
837 esl_disconnect(&remote->handle);
838 memset(&remote->handle, 0, sizeof(remote->handle));
839 }
840 } else {
841 if (esl_send_recv_timed(&remote->handle, "api hash_dump limit", 5000) != ESL_SUCCESS) {
842 esl_disconnect(&remote->handle);
843 memset(&remote->handle, 0, sizeof(remote->handle));
844 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 844
, ((void*)0)
, SWITCH_LOG_WARNING, "Disconnected from remote FreeSWITCH (%s) at %s:%d\n",
845 remote->name, remote->host, remote->port);
846 memset(&remote->handle, 0, sizeof(remote->handle));
847 remote->state = REMOTE_DOWN;
848 /* Delete all remote tracking entries */
849 switch_thread_rwlock_wrlock(remote->rwlock);
850 switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, NULL((void*)0));
851 switch_thread_rwlock_unlock(remote->rwlock);
852 } else {
853 if (!zstr(remote->handle.last_sr_event->body)_zstr(remote->handle.last_sr_event->body)) {
854 char *data = strdup(remote->handle.last_sr_event->body);
855 char *p = data, *p2;
856 switch_time_t now = switch_epoch_time_now(NULL((void*)0));
857 while (p && *p) {
858 /* We are getting the limit data as:
859 L/key/usage/rate/interval/last_checked
860 */
861 if ((p2 = strchr(p, '\n'))) {
862 *p2++ = '\0';
863 }
864
865 /* Now p points at the beginning of the current line,
866 p2 at the start of the next one */
867 if (*p == 'L') { /* Limit data */
868 char *argv[5];
869 int argc = switch_split(p+2, '/', argv)switch_separate_string(p+2, '/', argv, (sizeof(argv) / sizeof
(argv[0])))
;
870
871 if (argc < 5) {
872 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 872
, ((void*)0)
, SWITCH_LOG_WARNING, "[%s] Protocol error: missing argument in line: %s\n",
873 remote->name, p);
874 } else {
875 limit_hash_item_t *item;
876 switch_thread_rwlock_wrlock(remote->rwlock);
877 if (!(item = switch_core_hash_find(remote->index, argv[0]))) {
878 switch_zmalloc(item, sizeof(*item))(void)((((item = switch_calloc(1, (sizeof(*item))))) ? (void)
(0) : __assert_fail ("(item = switch_calloc(1, (sizeof(*item))))"
, "mod_hash.c", 878, __extension__ __PRETTY_FUNCTION__)),item
)
;
879 switch_core_hash_insert_auto_free(remote->index, argv[0], item);
880 }
881 item->total_usage = atoi(argv[1]);
882 item->rate_usage = atoi(argv[2]);
883 item->interval = atoi(argv[3]);
884 item->last_check = atoi(argv[4]);
885 item->last_update = now;
886 switch_thread_rwlock_unlock(remote->rwlock);
887 }
888 }
889
890 p = p2;
891 }
892 free(data);
893
894 /* Now free up anything that wasn't in this update since it means their usage is 0 */
895 switch_thread_rwlock_wrlock(remote->rwlock);
896 switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, (void*)(intptr_t)now);
897 switch_thread_rwlock_unlock(remote->rwlock);
898 }
899 }
900 }
901
902 switch_yield(remote->interval * 1000)switch_sleep(remote->interval * 1000);;
903 }
904
905 remote->thread = NULL((void*)0);
906
907 return NULL((void*)0);
908}
909
910static void do_config(switch_bool_t reload)
911{
912 switch_xml_t xml = NULL((void*)0), x_lists = NULL((void*)0), x_list = NULL((void*)0), cfg = NULL((void*)0);
913 if ((xml = switch_xml_open_cfg("hash.conf", &cfg, NULL((void*)0)))) {
914 if ((x_lists = switch_xml_child(cfg, "remotes"))) {
915 for (x_list = switch_xml_child(x_lists, "remote"); x_list; x_list = x_list->next) {
916 const char *name = switch_xml_attr(x_list, "name");
917 const char *host = switch_xml_attr(x_list, "host");
918 const char *szport = switch_xml_attr(x_list, "port");
919 const char *username = switch_xml_attr(x_list, "username");
920 const char *password = switch_xml_attr(x_list, "password");
921 const char *szinterval = switch_xml_attr(x_list, "interval");
922 uint16_t port = 0;
923 int interval = 0;
924 limit_remote_t *remote;
925 switch_threadattr_t *thd_attr = NULL((void*)0);
926
927 if (reload) {
928 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
929 if (switch_core_hash_find(globals.remote_hash, name)) {
930 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
931 continue;
932 }
933 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
934 }
935
936 if (!zstr(szport)_zstr(szport)) {
937 port = (uint16_t)atoi(szport);
938 }
939
940 if (!zstr(szinterval)_zstr(szinterval)) {
941 interval = atoi(szinterval);
942 }
943
944 remote = limit_remote_create(name, host, port, username, password, interval);
945
946 remote->state = REMOTE_DOWN;
947
948 switch_threadattr_create(&thd_attr, remote->pool);
949 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024);
950 switch_thread_create(&remote->thread, thd_attr, limit_remote_thread, remote, remote->pool);
951 }
952 }
953 switch_xml_free(xml);
954 }
955}
956
957/* INIT/DEINIT STUFF */
958SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)switch_status_t mod_hash_load (switch_loadable_module_interface_t
**module_interface, switch_memory_pool_t *pool)
959{
960 switch_application_interface_t *app_interface;
961 switch_api_interface_t *commands_api_interface;
962 switch_limit_interface_t *limit_interface;
963 switch_status_t status;
964
965 memset(&globals, 0, sizeof(globals));
966 globals.pool = pool;
967
968 status = switch_event_reserve_subclass(LIMIT_EVENT_USAGE)switch_event_reserve_subclass_detailed("mod_hash.c", "limit::usage"
)
;
969 if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_INUSE) {
970 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_hash.c", (const char *)__func__, 970
, ((void*)0)
, SWITCH_LOG_ERROR, "Couldn't register event subclass \"%s\" (%d)\n", LIMIT_EVENT_USAGE"limit::usage", status);
971 return SWITCH_STATUS_FALSE;
972 }
973
974 switch_thread_rwlock_create(&globals.limit_hash_rwlock, globals.pool);
975 switch_thread_rwlock_create(&globals.db_hash_rwlock, globals.pool);
976 switch_thread_rwlock_create(&globals.remote_hash_rwlock, globals.pool);
977 switch_core_hash_init(&globals.limit_hash)switch_core_hash_init_case(&globals.limit_hash, SWITCH_TRUE
)
;
978 switch_core_hash_init(&globals.db_hash)switch_core_hash_init_case(&globals.db_hash, SWITCH_TRUE);
979 switch_core_hash_init(&globals.remote_hash)switch_core_hash_init_case(&globals.remote_hash, SWITCH_TRUE
)
;
980
981 /* connect my internal structure to the blank pointer passed to me */
982 *module_interface = switch_loadable_module_create_module_interface(pool, modname);
983
984 /* register limit interfaces */
985 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; }
;
986
987 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),
988 SSHF_NONE);
989
990 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; }
991 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; }
;
992 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; }
;
993 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; }
;
994
995 switch_console_set_complete("add hash insert");
996 switch_console_set_complete("add hash delete");
997 switch_console_set_complete("add hash select");
998
999 switch_console_set_complete("add hash_remote list");
1000 switch_console_set_complete("add hash_remote kill");
1001 switch_console_set_complete("add hash_remote rescan");
1002
1003 do_config(SWITCH_FALSE);
1004
1005 /* indicate that the module should continue to be loaded */
1006 return SWITCH_STATUS_SUCCESS;
1007}
1008
1009
1010SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)switch_status_t mod_hash_shutdown (void)
1011{
1012 switch_hash_index_t *hi = NULL((void*)0);
1013 switch_bool_t remote_clean = SWITCH_TRUE;
1014
1015 switch_scheduler_del_task_group("mod_hash");
1016
1017 /* Kill remote connections, destroy needs a wrlock so we unlock after finding a pointer */
1018 while(remote_clean) {
1019 void *val;
1020 const void *key = NULL((void*)0);
1021 switch_ssize_t keylen;
1022 limit_remote_t *item = NULL((void*)0);
1023
1024 switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
1025 if ((hi = switch_core_hash_first(globals.remote_hash)switch_core_hash_first_iter(globals.remote_hash, ((void*)0)))) {
1026 switch_core_hash_this(hi, &key, &keylen, &val);
1027 item = (limit_remote_t *)val;
1028 }
1029 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
1030
1031 if (!item) {
1032 remote_clean = SWITCH_FALSE;
1033 } else {
1034 limit_remote_destroy(&item);
1035 switch_thread_rwlock_wrlock(globals.remote_hash_rwlock);
1036 switch_core_hash_delete(globals.remote_hash, key);
1037 switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
1038 }
1039 }
1040
1041 switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
1042 switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
1043
1044 while ((hi = switch_core_hash_first_iter( globals.limit_hash, hi))) {
1045 void *val = NULL((void*)0);
1046 const void *key;
1047 switch_ssize_t keylen;
1048 switch_core_hash_this(hi, &key, &keylen, &val);
1049 free(val);
1050 switch_core_hash_delete(globals.limit_hash, key);
1051 }
1052
1053 while ((hi = switch_core_hash_first_iter( globals.db_hash, hi))) {
1054 void *val = NULL((void*)0);
1055 const void *key;
1056 switch_ssize_t keylen;
1057 switch_core_hash_this(hi, &key, &keylen, &val);
1058 free(val);
1059 switch_core_hash_delete(globals.db_hash, key);
1060 }
1061
1062 switch_core_hash_destroy(&globals.limit_hash);
1063 switch_core_hash_destroy(&globals.db_hash);
1064 switch_core_hash_destroy(&globals.remote_hash);
1065
1066 switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
1067 switch_thread_rwlock_unlock(globals.db_hash_rwlock);
1068
1069 switch_thread_rwlock_destroy(globals.db_hash_rwlock);
1070 switch_thread_rwlock_destroy(globals.limit_hash_rwlock);
1071 switch_thread_rwlock_destroy(globals.remote_hash_rwlock);
1072
1073
1074 return SWITCH_STATUS_SUCCESS;
1075}
1076
1077/* For Emacs:
1078 * Local Variables:
1079 * mode:c
1080 * indent-tabs-mode:t
1081 * tab-width:4
1082 * c-basic-offset:4
1083 * End:
1084 * For VIM:
1085 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1086 */