<p>Alec Davis has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18828">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_redisd: add REDIS support modules to send asterisk DeviceState updates to a REDIS server<br><br>Code based on res_statsd and res_chan_stats, thank you David M. Lee<br><br>Tested on production system running asterisk 16.<br><br>ASTERISK-30147<br>Reported By: Alec Davis<br><br>Change-Id: I17dc11b1d0b4d046a3f092ddf7778108dbcd1cce<br>---<br>A configs/samples/redisd.conf.sample<br>A include/asterisk/redisd.h<br>A res/res_redis_device_state.c<br>A res/res_redisd.c<br>4 files changed, 672 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/28/18828/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/redisd.conf.sample b/configs/samples/redisd.conf.sample</span><br><span>new file mode 100644</span><br><span>index 0000000..e41fd93</span><br><span>--- /dev/null</span><br><span>+++ b/configs/samples/redisd.conf.sample</span><br><span>@@ -0,0 +1,10 @@</span><br><span style="color: hsl(120, 100%, 40%);">+[general]</span><br><span style="color: hsl(120, 100%, 40%);">+enabled = yes ; When set to yes, redisd support is enabled</span><br><span style="color: hsl(120, 100%, 40%);">+server = 127.0.0.1 ; server[:port] of REDIS server to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ ; If not specified, the port is 6379</span><br><span style="color: hsl(120, 100%, 40%);">+prefix = pabx: ; Prefix to prepend to all metrics</span><br><span style="color: hsl(120, 100%, 40%);">+;dbname = 0 ; DB to select, default = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bgsave = yes ; When set to yes, initiate a Background save when unloading module</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+;password = 12345678</span><br><span>diff --git a/include/asterisk/redisd.h b/include/asterisk/redisd.h</span><br><span>new file mode 100644</span><br><span>index 0000000..b88357e</span><br><span>--- /dev/null</span><br><span>+++ b/include/asterisk/redisd.h</span><br><span>@@ -0,0 +1,33 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2013, Digium, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * David M. Lee, II <dlee@digium.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _ASTERISK_REDISD_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define _ASTERISK_REDISD_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Support for publishing to a REDIS server.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author David M. Lee, II <dlee@digium.com></span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 12</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/optional_api.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(void, ast_redisd_command, (const char *command, const char *key_path, const char *_keyvalue, char *return_buffer, size_t return_buffwe_len), {});</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* _ASTERISK_REDISD_H */</span><br><span>diff --git a/res/res_redis_device_state.c b/res/res_redis_device_state.c</span><br><span>new file mode 100644</span><br><span>index 0000000..34bf9fb</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_redis_device_state.c</span><br><span>@@ -0,0 +1,109 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2005-2006, Digium, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Alec Davis</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Publish stasis devicestate to REDIS database.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This module subscribes to the stasis Device State topic and issues REDIS updates</span><br><span style="color: hsl(120, 100%, 40%);">+ * based on the received messages.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Alec Davis <alecbdt.co.nz></span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+ <defaultenabled>no</defaultenabled></span><br><span style="color: hsl(120, 100%, 40%);">+ <depend>res_redisd</depend></span><br><span style="color: hsl(120, 100%, 40%);">+ <support_level>extended</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <asterisk/module.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <asterisk/pbx.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/redisd.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Regular Stasis subscription */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_subscription *device_state_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Stasis subscription callback for device state updates */</span><br><span style="color: hsl(120, 100%, 40%);">+static void device_state_cb(void *data, struct stasis_subscription *device_state_sub, struct stasis_message *message)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_device_state_message *dev_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *device;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str *key_path;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (stasis_subscription_final_message(device_state_sub, message)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "remove stasis subscription\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (stasis_message_type(message) != ast_device_state_message_type()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "message type doesn't match\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ dev_state = stasis_message_data(message);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (dev_state->eid) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* ignore non-aggregate states */</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ device = dev_state->device;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(device)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "device length zero\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ key_path = ast_str_create(256);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!key_path) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_set(&key_path, 0, "deviceState:%s", device);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ //throw away result</span><br><span style="color: hsl(120, 100%, 40%);">+ char return_buffer[4096];</span><br><span style="color: hsl(120, 100%, 40%);">+ return_buffer[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_redisd_command( "SET", ast_str_buffer(key_path), ast_devstate_str(dev_state->state), return_buffer, sizeof(return_buffer));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(key_path);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ stasis_unsubscribe_and_join(device_state_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+ device_state_sub = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "REDIS Device State support",</span><br><span style="color: hsl(120, 100%, 40%);">+ .support_level = AST_MODULE_SUPPORT_EXTENDED,</span><br><span style="color: hsl(120, 100%, 40%);">+ .load = load_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .unload = unload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .requires = "res_redisd"</span><br><span style="color: hsl(120, 100%, 40%);">+);</span><br><span>diff --git a/res/res_redisd.c b/res/res_redisd.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8a573e0</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_redisd.c</span><br><span>@@ -0,0 +1,520 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2005-2006, Digium, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Alec Davis</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Support for working with a REDIS server.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Alec Davis <alec@bdt.co.nz></span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * For external depends refer /https://wiki.asterisk.org/wiki/display/AST/Build+System+Architecture</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+ <defaultenabled>no</defaultenabled></span><br><span style="color: hsl(120, 100%, 40%);">+ <depend>hiredis</depend></span><br><span style="color: hsl(120, 100%, 40%);">+ <support_level>extended</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/config_options.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include <asterisk/module.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <asterisk/pbx.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <asterisk/logger.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_API_MODULE</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/redisd.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <hiredis/hiredis.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** DOCUMENTATION</span><br><span style="color: hsl(120, 100%, 40%);">+ <configInfo name="res_redisd" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>REDIS client</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>The <literal>res_redisd</literal> module provides an API that</span><br><span style="color: hsl(120, 100%, 40%);">+ allows Asterisk and its modules to communicate with a REDIS</span><br><span style="color: hsl(120, 100%, 40%);">+ server.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ <configFile name="redisd.conf"></span><br><span style="color: hsl(120, 100%, 40%);">+ <configObject name="global"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Global configuration settings</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="enabled"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Enable/Disable the REDIS module</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="server"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Address of the REDIS server</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="prefix"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Prefix to prepend to every command</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="dbname"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>REDIS database to use</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="password"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>REDIS password</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="bgsave"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Background Save</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ </configObject></span><br><span style="color: hsl(120, 100%, 40%);">+ </configFile></span><br><span style="color: hsl(120, 100%, 40%);">+ </configInfo></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_REDIS_PORT 6379</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAX_PREFIX 40</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define STR_CONF_SZ 256</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct timeval timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Global configuration options for REDIS client. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct conf_global_options {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Disabled by default, Enabled if true. */</span><br><span style="color: hsl(120, 100%, 40%);">+ int enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! REDIS server address[:port]. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sockaddr redis_server;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Prefix to put on every keypath. */</span><br><span style="color: hsl(120, 100%, 40%);">+ char prefix[MAX_PREFIX + 1];</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! AUTH Password. */</span><br><span style="color: hsl(120, 100%, 40%);">+ char password[STR_CONF_SZ];</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! DB to select. */</span><br><span style="color: hsl(120, 100%, 40%);">+ char dbname[STR_CONF_SZ];</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! BGSAVE on exit. */</span><br><span style="color: hsl(120, 100%, 40%);">+ int bgsave;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief All configuration options for REDIS client. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct conf {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The general section configuration options. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct conf_global_options *global;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Locking container for safe configuration access. */</span><br><span style="color: hsl(120, 100%, 40%);">+static AO2_GLOBAL_OBJ_STATIC(confs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char is_enabled(void);</span><br><span style="color: hsl(120, 100%, 40%);">+static void conf_server(const struct conf *cfg, struct ast_sockaddr *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Connect to REDIS, with optional AUTH and DB selection</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int redisd_connect(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!is_enabled()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_WARNING, "REDIS module is not enabled. Reason: redisd.conf enabled=no?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sockaddr redis_server;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ conf_server(cfg, &redis_server);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisContext *redisd_context = redisConnectWithTimeout(\</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_stringify_addr(&redis_server),\</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_port(&redis_server), timeout);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (redisd_context == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_ERROR, "Couldn't establish connection. Reason: UNKNOWN\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (redisd_context->err != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_ERROR, "Couldn't establish connection to %s:%d socket_fd[%d] Reason: %s\n",\</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_stringify_addr(&redis_server),\</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_port(&redis_server),\</span><br><span style="color: hsl(120, 100%, 40%);">+ redisd_context->fd, redisd_context->errstr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisFree(redisd_context);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "socket_fd[%d]\n", redisd_context->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisReply *reply = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(cfg->global->password)) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ reply = redisCommand(redisd_context,"AUTH %s", cfg->global->password);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reply != NULL && reply->type == REDIS_REPLY_ERROR) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Unable to authenticate. Reason: %s\n", reply->str);</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisFree(redisd_context);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Authenticated.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(cfg->global->dbname)) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ reply = redisCommand(redisd_context,"SELECT %s", cfg->global->dbname);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reply != NULL && reply->type == REDIS_REPLY_ERROR) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_ERROR, "Unable to select DB %s. Reason: %s\n", cfg->global->dbname, reply->str);</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisFree(redisd_context);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Database %s selected.\n", cfg->global->dbname);</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(data, redisd_context, sizeof(redisContext));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(redisd_context);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void redisd_disconnect(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ redisContext *redisd_context = data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (redisd_context == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_ERROR, "No redisd_context. Reason: UNKNOWN\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "socket_fd[%d]\n", redisd_context->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisFree(redisd_context);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_THREADSTORAGE_CUSTOM(redisd_instance, redisd_connect, redisd_disconnect)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int redisd_command(const char *cmd, char *return_buffer, size_t return_buffer_length)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int attempt = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ redisReply *reply = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return_buffer[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisContext *redisd_context = ast_threadstorage_get(&redisd_instance, sizeof(redisContext));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!redisd_context) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_ERROR, "Error retrieving the redis context from thread\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+try:</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "socket_fd[%d] cmd[%s]\n", redisd_context->fd, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ reply = redisCommand(redisd_context, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reply == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (attempt++ < 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_NOTICE, "Attempting to reconnect to REDIS,\</span><br><span style="color: hsl(120, 100%, 40%);">+ socket_fd[%d] Attempt[%d] cmd[%s] \n",\</span><br><span style="color: hsl(120, 100%, 40%);">+ redisd_context->fd, attempt, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisReconnect(redisd_context);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto try;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reply != NULL && reply->type == REDIS_REPLY_ERROR) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_ERROR, "%s\n", reply->str);</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = ast_str_create(4096);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t reply_str_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (reply->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case REDIS_REPLY_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+ case REDIS_REPLY_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+ case REDIS_REPLY_STRING:</span><br><span style="color: hsl(120, 100%, 40%);">+ reply_str_len = ast_str_set(&msg, 0, "%s", reply->str);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case REDIS_REPLY_INTEGER:</span><br><span style="color: hsl(120, 100%, 40%);">+ reply_str_len = ast_str_set(&msg, 0, "%lld", reply->integer);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case REDIS_REPLY_ARRAY:</span><br><span style="color: hsl(120, 100%, 40%);">+ for (size_t element_idx = 0; element_idx < reply->elements; ++element_idx) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (element_idx) {</span><br><span style="color: hsl(120, 100%, 40%);">+ reply_str_len += ast_str_append(&msg, 0, ",%s", reply->element[element_idx]->str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ reply_str_len = ast_str_set(&msg, 0, "%s", reply->element[element_idx]->str);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case REDIS_REPLY_NIL:</span><br><span style="color: hsl(120, 100%, 40%);">+ reply_str_len = ast_str_set(&msg, 0, "%s", "nil");</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reply_str_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+ strncpy(return_buffer, ast_str_buffer(msg), return_buffer_length);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ freeReplyObject(reply);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void AST_OPTIONAL_API_NAME(ast_redisd_command)(const char *command, const char *key_path,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *key_value, char *return_buffer, size_t return_buffer_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!is_enabled()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = ast_str_create(256);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_append(&msg, 0, "%s", command);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strlen(key_path)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(cfg->global->prefix)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_append(&msg, 0, " %s%s", cfg->global->prefix, key_path);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_append(&msg, 0, " %s", key_path);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strlen(key_value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_append(&msg, 0, " %s", key_value);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ redisd_command(ast_str_buffer(msg), return_buffer, return_buffer_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void conf_server(const struct conf *cfg, struct ast_sockaddr *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ *addr = cfg->global->redis_server;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_sockaddr_port(addr) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_set_port(addr, DEFAULT_REDIS_PORT);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Mapping of the REDIS conf struct's globals to the</span><br><span style="color: hsl(120, 100%, 40%);">+ * general context in the config file. */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct aco_type global_option = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .type = ACO_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "global",</span><br><span style="color: hsl(120, 100%, 40%);">+ .item_offset = offsetof(struct conf, global),</span><br><span style="color: hsl(120, 100%, 40%);">+ .category = "general",</span><br><span style="color: hsl(120, 100%, 40%);">+ .category_match = ACO_WHITELIST_EXACT,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct aco_type *global_options[] = ACO_TYPES(&global_option);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Disposes of the REDIS conf object */</span><br><span style="color: hsl(120, 100%, 40%);">+static void conf_destructor(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct conf *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(cfg->global);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Creates the REDIS conf object. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void *conf_alloc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct conf *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(cfg = ao2_alloc(sizeof(*cfg), conf_destructor))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(cfg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief The conf file that's processed for the module. */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct aco_file conf_file = {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The config file name. */</span><br><span style="color: hsl(120, 100%, 40%);">+ .filename = "redisd.conf",</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The mapping object types to be processed. */</span><br><span style="color: hsl(120, 100%, 40%);">+ .types = ACO_TYPES(&global_option),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,</span><br><span style="color: hsl(120, 100%, 40%);">+ .files = ACO_FILES(&conf_file));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper function to check if module is enabled. */</span><br><span style="color: hsl(120, 100%, 40%);">+static char is_enabled(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ return cfg->global->enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int redisd_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sockaddr redis_server;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_assert(is_enabled());</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Configuring REDIS client.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ conf_server(cfg, &redis_server);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, " server = %s:%d\n", ast_sockaddr_stringify_addr(&redis_server), ast_sockaddr_port(&redis_server));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, " prefix = %s\n", cfg->global->prefix);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, " dbname = %s\n", cfg->global->dbname);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, " password = %s\n", cfg->global->password);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, " bgsave = %s\n", cfg->global->bgsave?"yes":"no");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void redisd_shutdown(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Shutting down REDIS client.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->global->bgsave) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_NOTICE, "Sending BGSAVE before closing connection.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ //throw away result</span><br><span style="color: hsl(120, 100%, 40%);">+ char return_buffer[4096];</span><br><span style="color: hsl(120, 100%, 40%);">+ return_buffer[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_redisd_command("BGSAVE", "", "", return_buffer, sizeof(return_buffer));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ redisd_shutdown();</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_info_destroy(&cfg_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_global_obj_release(confs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (aco_info_init(&cfg_info)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_NOTICE, "aco_info_init failed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_info_destroy(&cfg_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ "no", OPT_BOOL_T, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ FLDSET(struct conf_global_options, enabled));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register(&cfg_info, "server", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ "127.0.0.1", OPT_SOCKADDR_T, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ FLDSET(struct conf_global_options, redis_server));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register(&cfg_info, "prefix", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ "", OPT_CHAR_ARRAY_T, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ CHARFLDSET(struct conf_global_options, prefix));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register(&cfg_info, "dbname", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ "", OPT_CHAR_ARRAY_T, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ CHARFLDSET(struct conf_global_options, dbname));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register(&cfg_info, "password", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ "", OPT_CHAR_ARRAY_T, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ CHARFLDSET(struct conf_global_options, password));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register(&cfg_info, "bgsave", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ "no", OPT_BOOL_T, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ FLDSET(struct conf_global_options, bgsave));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct conf *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_NOTICE, "Could not load redis config; using defaults\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg = conf_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cfg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_info_destroy(&cfg_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (aco_set_defaults(&global_option, "general", cfg->global)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to initialize redis defaults.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(cfg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_info_destroy(&cfg_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_global_obj_replace_unref(confs, cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(cfg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!is_enabled()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (redisd_init()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* The priority of this module is set just after realtime, since it loads</span><br><span style="color: hsl(120, 100%, 40%);">+ * configuration and could be used by any other sort of module.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "REDIS client support",</span><br><span style="color: hsl(120, 100%, 40%);">+ .support_level = AST_MODULE_SUPPORT_EXTENDED,</span><br><span style="color: hsl(120, 100%, 40%);">+ .load = load_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .unload = unload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .load_pri = AST_MODPRI_REALTIME_DRIVER + 5,</span><br><span style="color: hsl(120, 100%, 40%);">+);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18828">change 18828</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/18828"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I17dc11b1d0b4d046a3f092ddf7778108dbcd1cce </div>
<div style="display:none"> Gerrit-Change-Number: 18828 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Alec Davis <alec@bdt.co.nz> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>