aboutsummaryrefslogtreecommitdiffstats
path: root/main/kamailio/DMQ-multi-notify.patch
blob: 8fa20c550516bec5334168ac2bf7b3393f8529b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
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")
 </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>
         <section id="dmq.p.num_workers">
                 <title><varname>num_workers</varname>(int)</title>
                 <para>
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 = {&notification_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;
 }
 
 /**