<p>Alec Davis has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18826">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: Ibd70851ecf7aebe41b3830b52599fe7d14c311e9<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/26/18826/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/+/18826">change 18826</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/+/18826"/><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: Ibd70851ecf7aebe41b3830b52599fe7d14c311e9 </div>
<div style="display:none"> Gerrit-Change-Number: 18826 </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>