فهرست منبع

dmq: resolve multiple IPv4/IPv6 addresses for a single notification address

- optionally enabled by new parameter "multi_notify"
- includes addresses from DNS SRV records, A and AAAA records
- patch provided by Robert Boisvert on sr-dev list
Charles Chance 10 سال پیش
والد
کامیت
c55ec2ba2d
4فایلهای تغییر یافته به همراه293 افزوده شده و 15 حذف شده
  1. 2 0
      modules/dmq/dmq.c
  2. 1 0
      modules/dmq/dmq.h
  3. 23 0
      modules/dmq/doc/dmq_admin.xml
  4. 267 15
      modules/dmq/notification_peer.c

+ 2 - 0
modules/dmq/dmq.c

@@ -63,6 +63,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 = 60;
 
@@ -110,6 +111,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}
 };
 

+ 1 - 0
modules/dmq/dmq.h

@@ -45,6 +45,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;

+ 23 - 0
modules/dmq/doc/dmq_admin.xml

@@ -128,6 +128,29 @@ modparam("dmq", "server_address", "sip:10.0.0.20:5060")
 ...
 modparam("dmq", "notification_address", "sip:10.0.0.21:5060")
 ...
+</programlisting>
+		</example>
+	</section>
+	<section id="dmq.p.multi_notify">
+		<title><varname>multi_notify</varname>(int)</title>
+		<para>
+		Enables the ability to resolve multiple IPv4/IPv6 addresses for 
+		a single notification address.
+		</para>
+		<para>
+		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.
+		</para>
+		<para>
+		<emphasis>Default value is <quote>0</quote>.</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>multi_notify</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("dmq", "multi_notify", 1)
+...
 </programlisting>
 		</example>
 	</section>

+ 267 - 15
modules/dmq/notification_peer.c

@@ -24,6 +24,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 = {&notification_resp_callback_f, 0};
 
@@ -62,27 +65,276 @@ 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;
 }
 
 /**