diff --git a/modules/dmq/dmq.c b/modules/dmq/dmq.c
index fcbd8f8..8deed9b 100644
--- a/modules/dmq/dmq.c
+++ b/modules/dmq/dmq.c
@@ -65,6 +65,7 @@ str dmq_server_socket = {0, 0};
struct sip_uri dmq_server_uri;
str dmq_notification_address = {0, 0};
+int multi_notify = 0;
struct sip_uri dmq_notification_uri;
int ping_interval = MIN_PING_INTERVAL;
@@ -112,6 +113,7 @@ static param_export_t params[] = {
{"ping_interval", INT_PARAM, &ping_interval},
{"server_address", PARAM_STR, &dmq_server_address},
{"notification_address", PARAM_STR, &dmq_notification_address},
+ {"multi_notify", INT_PARAM, &multi_notify},
{0, 0, 0}
};
diff --git a/modules/dmq/dmq.h b/modules/dmq/dmq.h
index eedadb3..f96ac03 100644
--- a/modules/dmq/dmq.h
+++ b/modules/dmq/dmq.h
@@ -47,6 +47,7 @@ extern str dmq_request_method;
extern str dmq_server_socket;
extern struct sip_uri dmq_server_uri;
extern str dmq_notification_address;
+extern int multi_notify;
extern struct sip_uri dmq_notification_uri;
/* sl and tm */
extern struct tm_binds tmb;
diff --git a/modules/dmq/doc/dmq_admin.xml b/modules/dmq/doc/dmq_admin.xml
index 7eabc1a..7e9c048 100644
--- a/modules/dmq/doc/dmq_admin.xml
+++ b/modules/dmq/doc/dmq_admin.xml
@@ -101,6 +101,26 @@ modparam("dmq", "notification_address", "sip:10.0.0.21:5060")
+
+ multi_notify(int)
+
+ Enables the ability to resolve multiple IPv4/IPv6 addresses for a single notification address.
+
+
+ A value of zero resolves to the first IP address found. A non-zero value resolves to all IP addresses associated with the host. This includes addresses from DNS SRV records, A and AAAA records.
+
+
+ Default value is 0
.
+
+
+ Set multi_notify parameter
+
+...
+modparam("dmq", "multi_notify", 1)
+...
+
+
+
num_workers(int)
diff --git a/modules/dmq/notification_peer.c b/modules/dmq/notification_peer.c
index 2acb9a8..2f281c5 100644
--- a/modules/dmq/notification_peer.c
+++ b/modules/dmq/notification_peer.c
@@ -26,6 +26,9 @@
#include "notification_peer.h"
+#define MAXDMQURILEN 255
+#define MAXDMQHOSTS 30
+
str notification_content_type = str_init("text/plain");
dmq_resp_cback_t notification_callback = {¬ification_resp_callback_f, 0};
@@ -58,27 +61,277 @@ error:
return -1;
}
+/**********
+* Create IP URI
+*
+* INPUT:
+* Arg (1) = container for hosts
+* Arg (2) = host index
+* Arg (3) = host name pointer
+* Arg (4) = host name length
+* Arg (5) = parsed URI pointer
+* OUTPUT: 0=unable to create URI
+**********/
+
+int create_IP_uri (char **puri_list, int host_index, char *phost,
+ int hostlen, sip_uri_t *puri)
+
+{
+ int pos;
+ char *plist;
+ char *perr = "notification host count reached max!\n";
+
+ /**********
+ * insert
+ * o scheme
+ * o user name/password
+ * o host
+ * o port
+ * o parameters
+ **********/
+
+ plist = puri_list [host_index];
+ if (puri->type == SIPS_URI_T) {
+ strncpy (plist, "sips:", 5);
+ pos = 5;
+ } else {
+ strncpy (plist, "sip:", 4);
+ pos = 4;
+ }
+ if (puri->user.s) {
+ strncpy (&plist [pos], puri->user.s, puri->user.len);
+ pos += puri->user.len;
+ if (puri->passwd.s) {
+ plist [pos++] = ':';
+ strncpy (&plist [pos], puri->passwd.s, puri->passwd.len);
+ pos += puri->passwd.len;
+ }
+ plist [pos++] = '@';
+ }
+ if ((pos + hostlen) > MAXDMQURILEN) {
+ LM_WARN ("%s", perr);
+ return 0;
+ }
+ strncpy (&plist [pos], phost, hostlen);
+ pos += hostlen;
+ if (puri->port_no) {
+ if ((pos + 6) > MAXDMQURILEN) {
+ LM_WARN ("%s", perr);
+ return 0;
+ }
+ plist [pos++] = ':';
+ pos += ushort2sbuf (puri->port_no, &plist [pos], 5);
+ }
+ if (puri->params.s) {
+ if ((pos + puri->params.len) >= MAXDMQURILEN) {
+ LM_WARN ("%s", perr);
+ return 0;
+ }
+ plist [pos++] = ';';
+ strncpy (&plist [pos], puri->params.s, puri->params.len);
+ pos += puri->params.len;
+ }
+ plist [pos] = '\0';
+ return 1;
+}
+
+/**********
+* Get DMQ Host List
+*
+* INPUT:
+* Arg (1) = container for hosts
+* Arg (2) = maximum number of hosts
+* Arg (3) = host string pointer
+* Arg (4) = parsed URI pointer
+* Arg (5) = search SRV flag
+* OUTPUT: number of hosts found
+**********/
+
+int get_dmq_host_list (char **puri_list, int max_hosts, str *phost,
+ sip_uri_t *puri, int bSRV)
+
+{
+ int host_cnt, len;
+ unsigned short origport, port;
+ str pstr [1];
+ char pname [256], pIP [IP6_MAX_STR_SIZE + 2];
+ struct rdata *phead, *prec;
+ struct srv_rdata *psrv;
+
+ /**********
+ * o IP address?
+ * o make null terminated name
+ * o search SRV?
+ **********/
+
+ if (str2ip (phost) || str2ip6 (phost)) {
+ if (!create_IP_uri (puri_list, 0, phost->s, phost->len, puri)) {
+ LM_DBG ("adding DMQ node IP host %.*s=%s\n",
+ phost->len, phost->s, puri_list [0]);
+ return 0;
+ }
+ return 1;
+ }
+ strncpy (pname, phost->s, phost->len);
+ pname [phost->len] = '\0';
+ host_cnt = 0;
+ if (bSRV) {
+ /**********
+ * get SRV records
+ **********/
+
+ port = puri->port_no;
+ phead = get_record (pname, T_SRV, RES_ONLY_TYPE);
+ for (prec = phead; prec; prec = prec->next) {
+ /**********
+ * o matching port?
+ * o check max
+ * o save original port
+ * o check target
+ * o restore port
+ **********/
+
+ psrv = (struct srv_rdata *) prec->rdata;
+ if (port && (port != psrv->port))
+ { continue; }
+ if (host_cnt == max_hosts) {
+ LM_WARN ("notification host count reached max!\n");
+ free_rdata_list (phead);
+ return host_cnt;
+ }
+ pstr->s = psrv->name;
+ pstr->len = psrv->name_len;
+ origport = puri->port_no;
+ puri->port_no = psrv->port;
+ host_cnt += get_dmq_host_list (&puri_list [host_cnt],
+ MAXDMQHOSTS - host_cnt, pstr, puri, 0);
+ puri->port_no = origport;
+ }
+ if (phead)
+ free_rdata_list (phead);
+ }
+
+ /**********
+ * get A records
+ **********/
+
+ phead = get_record (pname, T_A, RES_ONLY_TYPE);
+ for (prec = phead; prec; prec = prec->next) {
+ /**********
+ * o check max
+ * o create URI
+ **********/
+
+ if (host_cnt == max_hosts) {
+ LM_WARN ("notification host count reached max!\n");
+ free_rdata_list (phead);
+ return host_cnt;
+ }
+ len = ip4tosbuf (((struct a_rdata *) prec->rdata)->ip,
+ pIP, IP4_MAX_STR_SIZE);
+ pIP [len] = '\0';
+ if (create_IP_uri (puri_list, host_cnt, pIP, len, puri)) {
+ LM_DBG ("adding DMQ node A host %s=%s\n", pname, puri_list [host_cnt]);
+ host_cnt++;
+ }
+ }
+ if (phead)
+ free_rdata_list (phead);
+
+ /**********
+ * get AAAA records
+ **********/
+
+ phead = get_record (pname, T_AAAA, RES_ONLY_TYPE);
+ for (prec = phead; prec; prec = prec->next) {
+ /**********
+ * o check max
+ * o create URI
+ **********/
+
+ if (host_cnt == max_hosts) {
+ LM_WARN ("notification host count reached max!\n");
+ free_rdata_list (phead);
+ return host_cnt;
+ }
+ pIP [0] = '[';
+ len = ip6tosbuf (((struct aaaa_rdata *) prec->rdata)->ip6,
+ &pIP [1], IP6_MAX_STR_SIZE) + 1;
+ pIP [len++] = ']';
+ pIP [len] = '\0';
+ if (create_IP_uri (puri_list, host_cnt, pIP, len, puri)) {
+ LM_DBG
+ ("adding DMQ node AAAA host %s=%s\n", pname, puri_list [host_cnt]);
+ host_cnt++;
+ }
+ }
+ if (phead)
+ free_rdata_list (phead);
+ return host_cnt;
+}
+
/**
* @brief add a server node and notify it
*/
-dmq_node_t* add_server_and_notify(str* server_address)
+dmq_node_t* add_server_and_notify (str *paddr)
+
{
- /* add the notification server to the node list - if any */
- dmq_node_t* node;
-
- node = add_dmq_node(node_list, server_address);
- if(!node) {
- LM_ERR("error adding notification node\n");
- goto error;
+ char puri_data [MAXDMQHOSTS * (MAXDMQURILEN + 1)];
+ char *puri_list [MAXDMQHOSTS];
+ dmq_node_t *pfirst, *pnode;
+ int host_cnt, index;
+ sip_uri_t puri [1];
+ str pstr [1];
+
+ /**********
+ * o init data area
+ * o get list of hosts
+ * o process list
+ **********/
+
+ if (!multi_notify) {
+ pfirst = add_dmq_node (node_list, paddr);
+ } else {
+ /**********
+ * o init data area
+ * o get list of hosts
+ * o process list
+ **********/
+
+ for (index = 0; index < MAXDMQHOSTS; index++) {
+ puri_list [index] = &puri_data [index * (MAXDMQURILEN + 1)];
+ }
+ if (parse_uri (paddr->s, paddr->len, puri) < 0) {
+ /* this is supposed to be good but just in case... */
+ LM_ERR ("add_server_and_notify address invalid\n");
+ return 0;
+ }
+ pfirst = NULL;
+ host_cnt =
+ get_dmq_host_list (puri_list, MAXDMQHOSTS, &puri->host, puri, 1);
+ for (index = 0; index < host_cnt; index++) {
+ pstr->s = puri_list [index];
+ pstr->len = strlen (puri_list [index]);
+ pnode = add_dmq_node (node_list, pstr);
+ if (pnode && !pfirst)
+ { pfirst = pnode; }
+ }
}
- /* request initial list from the notification server */
- if(request_nodelist(node, 2) < 0) {
- LM_ERR("error requesting initial nodelist\n");
- goto error;
+
+ /**********
+ * o found at least one?
+ * o request node list
+ **********/
+
+ if (!pfirst) {
+ LM_ERR ("error adding notification node\n");
+ return NULL;
}
- return node;
-error:
- return NULL;
+ if (request_nodelist (pfirst, 2) < 0) {
+ LM_ERR ("error requesting initial nodelist\n");
+ return NULL;
+ }
+ return pfirst;
}
/**