Browse code

keepalive: new module to monitor remote destinations

Guillaume Bour authored on 04/04/2017 14:00:15 • Daniel-Constantin Mierla committed on 04/04/2017 14:00:15
Showing 10 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,18 @@
1
+#
2
+# example module makefile
3
+#
4
+# 
5
+# WARNING: do not run this directly, it should be run by the master Makefile
6
+
7
+include ../../Makefile.defs
8
+
9
+auto_gen=
10
+NAME=keepalive.so
11
+
12
+LIBS=
13
+
14
+DEFS+=-DKAMAILIO_MOD_INTERFACE
15
+
16
+SERLIBPATH=../../lib
17
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
18
+include ../../Makefile.modules
0 19
new file mode 100644
... ...
@@ -0,0 +1,74 @@
1
+/**
2
+ * keepalive module - remote destinations probing
3
+ *
4
+ * Copyright (C) 2017 Guillaume Bour <guillaume@bour.cc>
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ */
22
+
23
+/*! \file
24
+ * \ingroup keepalive
25
+ * \brief Keepalive :: Send keepalives
26
+ */
27
+
28
+#ifndef __KEEPALIVE_API_H_
29
+#define __KEEPALIVE_API_H_
30
+
31
+#include "../../core/sr_module.h"
32
+
33
+typedef int ka_state;
34
+
35
+#define KA_STATE_UNKNOWN    0
36
+#define KA_STATE_UP         1
37
+#define KA_STATE_DOWN       2
38
+
39
+typedef void (*ka_statechanged_f)(str uri, int state, void *user_attr);
40
+typedef int  (*ka_add_dest_f)(str uri, str owner, int flags, ka_statechanged_f callback,
41
+                              void *user_attr);
42
+typedef ka_state (*ka_dest_state_f)(str uri);
43
+
44
+typedef struct keepalive_api {
45
+	ka_add_dest_f	  add_destination;
46
+	ka_dest_state_f   destination_state;
47
+} keepalive_api_t;
48
+
49
+typedef int (*bind_keepalive_f)(keepalive_api_t* api);
50
+int bind_keepalive(keepalive_api_t* api);
51
+
52
+/**
53
+ * @brief Load the dispatcher API
54
+ */
55
+static inline int keepalive_load_api(keepalive_api_t *api)
56
+{
57
+	bind_keepalive_f bindkeepalive;
58
+
59
+	bindkeepalive = (bind_keepalive_f)find_export("bind_keepalive", 0, 0);
60
+	if(bindkeepalive == 0) {
61
+		LM_ERR("cannot find bind_keepalive\n");
62
+		return -1;
63
+	}
64
+
65
+	if(bindkeepalive(api) < 0)
66
+	{
67
+		LM_ERR("cannot bind keepalive api\n");
68
+		return -1;
69
+	}
70
+	return 0;
71
+}
72
+
73
+#endif /* __KEEPALIVE_API_H__ */
74
+
0 75
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+docs = keepalive.xml
2
+
3
+docbook_dir = ../../../../doc/docbook
4
+include $(docbook_dir)/Makefile.module
0 5
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+<?xml version="1.0" encoding='ISO-8859-1'?>
2
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
4
+
5
+<!-- Include general documentation entities -->
6
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
7
+%docentities;
8
+
9
+]>
10
+
11
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
12
+    <bookinfo>
13
+	<title>KeepAlive Module</title>
14
+	<productname class="trade">kamailio.org</productname>
15
+	<authorgroup>
16
+	    <author>
17
+		<firstname>Guillaume</firstname>
18
+		<surname>Bour</surname>
19
+		<email>guillaume@bour.cc</email>
20
+	    </author>
21
+
22
+		<editor>
23
+		<firstname>Guillaume</firstname>
24
+		<surname>Bour</surname>
25
+		<email>guillaume@bour.cc</email>
26
+	    </editor>
27
+	</authorgroup>
28
+	<copyright>
29
+	    <year>2017</year>
30
+	    <holder>Guillaume Bour</holder>
31
+	</copyright>
32
+    </bookinfo>
33
+    <toc></toc>
34
+    
35
+    <xi:include href="keepalive_admin.xml"/>
36
+    
37
+    
38
+</book>
0 39
new file mode 100644
... ...
@@ -0,0 +1,120 @@
1
+<?xml version="1.0" encoding='ISO-8859-1'?>
2
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
4
+
5
+<!-- Include general documentation entities -->
6
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
7
+%docentities;
8
+
9
+]>
10
+<!-- Module User's Guide -->
11
+
12
+<chapter>
13
+	
14
+	<title>&adminguide;</title>
15
+	
16
+	<section>
17
+		<title>Overview</title>
18
+		<para>
19
+		This module performs destinations monitoring either for itself, or on the behalf of other modules
20
+		</para>
21
+	</section>
22
+
23
+	<section>
24
+		<title>Dependencies</title>
25
+		<section>
26
+			<title>&kamailio; Modules</title>
27
+			<para>
28
+				The following modules must be loaded before this module:
29
+				<itemizedlist>
30
+				<listitem>
31
+				<para>
32
+					<emphasis>tm</emphasis> - Transaction module
33
+				</para>
34
+				</listitem>
35
+				</itemizedlist>
36
+			</para>
37
+		</section>
38
+		<section>
39
+			<title>External Libraries or Applications</title>
40
+			<para>
41
+				The following libraries or applications must be installed before running
42
+				&kamailio; with this module loaded:
43
+				<itemizedlist>
44
+				<listitem>
45
+	            <para>
46
+					<emphasis>none</emphasis>
47
+				</para>
48
+				</listitem>
49
+				</itemizedlist>
50
+			</para>
51
+		</section>
52
+		<section>
53
+			<title>Parameters</title>
54
+			<section>
55
+				<title><varname>ping_interval</varname> (integer)</title>
56
+				<para>
57
+					Interval requests are sent to destinations (in seconds)
58
+				</para>
59
+				<para>
60
+				<emphasis>
61
+					Default value is 30 seconds.
62
+				</emphasis>
63
+				</para>
64
+				<example>
65
+					<title>Set <varname>ping_interval</varname> parameter</title>
66
+					<programlisting format="linespecific">
67
+...
68
+modparam("keepalive", "ping_interval", 10)
69
+...
70
+					</programlisting>
71
+				</example>
72
+			</section>
73
+			<section>
74
+				<title><varname>destination</varname> (string)</title>
75
+				<para>
76
+					Allows to specify statically destinations you want to monitor
77
+				</para>
78
+				<example>
79
+					<title>Set <varname>destination</varname> parameter</title>
80
+					<programlisting format="linespecific">
81
+...
82
+modparam("keepalive", "destination", "192.168.10.20")
83
+modparam("keepalive", "destination", "sip.provider.com")
84
+...
85
+					</programlisting>
86
+				</example>
87
+			</section>
88
+		</section>
89
+
90
+		<section>
91
+			<title>Functions</title>
92
+			<section id="keepalive.is_alive">
93
+			    <title>
94
+					<function moreinfo="none">is_alive(destination)</function>
95
+			    </title>
96
+				<para>
97
+					Get destination status
98
+				</para>
99
+		        <para>
100
+					Parameter <quote>destination</quote> is destination you want to check status
101
+		        </para>
102
+        		<para>
103
+		            Return value: 1 if destination is up, 2 if destination is down, -1 on error.
104
+        		</para>
105
+		        <para>
106
+				    This function can be used from ANY_ROUTE.
107
+		        </para>
108
+				<example>
109
+					<title><function>is_alive()</function> usage</title>
110
+					<programlisting format="linespecific">
111
+...
112
+is_alive("192.168.10.20");
113
+...
114
+			        </programlisting>
115
+			    </example>
116
+			</section>
117
+		</section>
118
+	</section>
119
+</chapter>
120
+
0 121
new file mode 100644
... ...
@@ -0,0 +1,85 @@
1
+/**
2
+ * keepalive module - remote destinations probing
3
+ * 
4
+ * Copyright (C) 2017 Guillaume Bour <guillaume@bour.cc>
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ */
22
+
23
+/*! \file
24
+ * \ingroup keepalive
25
+ * \brief Keepalive :: Keepalive
26
+ */
27
+
28
+#ifndef _KEEPALIVE_H_
29
+#define _KEEPALIVE_H_
30
+
31
+#include <time.h>
32
+#include "../../core/sr_module.h"
33
+
34
+
35
+#define KA_INACTIVE_DST		1  /*!< inactive destination */
36
+#define KA_TRYING_DST		2  /*!< temporary trying destination */
37
+#define KA_DISABLED_DST		4  /*!< admin disabled destination */
38
+#define KA_PROBING_DST		8  /*!< checking destination */
39
+#define KA_STATES_ALL		15  /*!< all bits for the states of destination */
40
+
41
+#define ds_skip_dst(flags)	((flags) & (KA_INACTIVE_DST|KA_DISABLED_DST))
42
+
43
+#define KA_PROBE_NONE			0
44
+#define KA_PROBE_ALL			1
45
+#define KA_PROBE_INACTIVE		2
46
+#define KA_PROBE_ONLYFLAGGED	3
47
+
48
+typedef void (*ka_statechanged_f)(str uri, int state, void *user_attr);
49
+
50
+typedef struct _ka_dest
51
+{
52
+	str uri;
53
+	str owner;                  // name of destination "owner"
54
+                                // (module asking to monitor this destination
55
+	int flags;
56
+	int state;
57
+	time_t last_checked,
58
+		   last_up,
59
+		   last_down;
60
+	//ds_attrs_t attrs;
61
+
62
+	void *user_attr;
63
+	ka_statechanged_f statechanged_clb;
64
+
65
+	struct socket_info * sock;
66
+	struct ip_addr ip_address; 	/*!< IP-Address of the entry */
67
+	unsigned short int port; 	/*!< Port of the URI */
68
+	unsigned short int proto; 	/*!< Protocol of the URI */
69
+	//int message_count;
70
+	struct _ka_dest *next;
71
+} ka_dest_t;
72
+
73
+typedef struct _ka_destinations_list
74
+{
75
+	ka_dest_t *first;
76
+} ka_destinations_list_t;
77
+
78
+extern ka_destinations_list_t *ka_destinations_list;
79
+
80
+int ka_add_dest(str uri, str owner, int flags, ka_statechanged_f callback, void *user_attr);
81
+int ka_destination_state(str uri);
82
+int ka_str_copy(str src, str *dest, char *prefix);
83
+
84
+#endif
85
+
0 86
new file mode 100644
... ...
@@ -0,0 +1,135 @@
1
+/**
2
+ * keepalive module - remote destinations probing
3
+ *
4
+ * Copyright (C) 2017 Guillaume Bour <guillaume@bour.cc>
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ */
22
+
23
+/*! \file
24
+ * \ingroup keepalive
25
+ * \brief Keepalive :: Send keepalives
26
+ */
27
+
28
+/*! \defgroup keepalive Keepalive :: Probing remote gateways by sending keepalives
29
+ */
30
+
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <stdlib.h>
34
+#include <sys/types.h>
35
+#include <unistd.h>
36
+
37
+#include "../tm/tm_load.h"
38
+
39
+#include "keepalive.h"
40
+#include "api.h"
41
+
42
+
43
+/*
44
+ * Regroup all exported functions in keepalive_api_t structure
45
+ *
46
+ */
47
+int bind_keepalive(keepalive_api_t* api)
48
+{
49
+	if (!api) {
50
+		ERR("Invalid parameter value\n");
51
+		return -1;
52
+	}
53
+
54
+	api->add_destination = ka_add_dest;
55
+	api->destination_state = ka_destination_state;
56
+	return 0;
57
+}
58
+
59
+/*
60
+ * Add a new destination in keepalive pool
61
+ */
62
+int ka_add_dest(str uri, str owner, int flags, ka_statechanged_f callback, void *user_attr) {
63
+	LM_INFO("adding destination: %.*s\n", uri.len, uri.s);
64
+
65
+	ka_dest_t *dest = (ka_dest_t *) shm_malloc(sizeof(ka_dest_t));
66
+	if(dest == NULL) {
67
+		LM_ERR("no more memory.\n");
68
+		goto err;
69
+	}
70
+	memset(dest, 0, sizeof(ka_dest_t));
71
+
72
+	if (uri.len >= 4 && (!strncasecmp("sip:", uri.s, 4) || !strncasecmp("sips:", uri.s, 5))) {
73
+		// protocol found
74
+		if (ka_str_copy(uri  , &(dest->uri), NULL) < 0)
75
+			goto err;
76
+	} else {
77
+		if (ka_str_copy(uri  , &(dest->uri), "sip:") < 0)
78
+			goto err;
79
+	}
80
+
81
+	// checking uri is valid
82
+	struct sip_uri _uri;
83
+	if (parse_uri(dest->uri.s, dest->uri.len, &_uri) != 0) {
84
+		LM_ERR("invalid uri <%.*s>\n", dest->uri.len, dest->uri.s);
85
+		goto err;
86
+	}
87
+
88
+	if (ka_str_copy(owner, &(dest->owner), NULL) < 0)
89
+		goto err;
90
+
91
+	dest->flags                 = flags;
92
+	dest->statechanged_clb      = callback;
93
+	dest->user_attr             = user_attr;
94
+
95
+	dest->next                  = ka_destinations_list->first;
96
+	ka_destinations_list->first = dest;
97
+
98
+	return 0;
99
+
100
+err:
101
+	if (dest) {
102
+		if (dest->uri.s)
103
+			shm_free(dest->uri.s);
104
+
105
+		shm_free(dest);
106
+	}
107
+	return -1;
108
+}
109
+
110
+/*
111
+ * TODO
112
+ */
113
+int ka_rm_dest() {
114
+	return -1;
115
+}
116
+
117
+/*
118
+ *
119
+ */
120
+ka_state ka_destination_state(str destination) {
121
+	ka_dest_t *ka_dest = NULL;
122
+
123
+	for(ka_dest = ka_destinations_list->first; ka_dest != NULL; ka_dest = ka_dest->next) {
124
+		if (strncmp(ka_dest->uri.s+4, destination.s, ka_dest->uri.len-4) == 0) {
125
+			break;
126
+		}
127
+	}
128
+
129
+	if (ka_dest == NULL) {
130
+		return(-1);
131
+	}
132
+
133
+	return ka_dest->state;
134
+}
135
+
0 136
new file mode 100644
... ...
@@ -0,0 +1,200 @@
1
+/**
2
+ * keepalive module - remote destinations probing
3
+ *
4
+ * Copyright (C) 2017 Guillaume Bour <guillaume@bour.cc>
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ */
22
+
23
+/*! \file
24
+ * \ingroup keepalive
25
+ * \brief Keepalive :: Send keepalives
26
+ */
27
+
28
+/*! \defgroup keepalive Keepalive :: Probing remote gateways by sending keepalives
29
+ */
30
+
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <stdlib.h>
34
+#include <sys/types.h>
35
+#include <unistd.h>
36
+
37
+#include "../../core/fmsg.h"
38
+#include "../tm/tm_load.h"
39
+
40
+#include "keepalive.h"
41
+#include "api.h"
42
+
43
+struct tm_binds tmb;
44
+
45
+static void ka_run_route(sip_msg_t *msg, str *uri, char *route);
46
+static void ka_options_callback( struct cell *t, int type, struct tmcb_params *ps );
47
+
48
+
49
+/*! \brief
50
+ * Timer for checking probing destinations
51
+ *
52
+ * This timer is regularly fired.
53
+ */
54
+void ka_check_timer(unsigned int ticks, void* param)
55
+{
56
+	ka_dest_t *ka_dest;
57
+	str ka_ping_method = str_init("OPTIONS");
58
+	str ka_ping_from   = str_init("sip:dispatcher@localhost");
59
+	str ka_outbound_proxy = {0, 0};
60
+	uac_req_t uac_r;
61
+
62
+	LM_DBG("ka check timer\n");
63
+
64
+	for(ka_dest = ka_destinations_list->first; ka_dest != NULL; ka_dest = ka_dest->next) {
65
+		LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
66
+
67
+		/* Send ping using TM-Module.
68
+		 * int request(str* m, str* ruri, str* to, str* from, str* h,
69
+		 *		str* b, str *oburi,
70
+		 *		transaction_cb cb, void* cbp); */
71
+		set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0,
72
+				TMCB_LOCAL_COMPLETED, ka_options_callback,
73
+				(void *) ka_dest);
74
+
75
+		if (tmb.t_request(&uac_r,
76
+					&ka_dest->uri,
77
+					&ka_dest->uri,
78
+					&ka_ping_from,
79
+					&ka_outbound_proxy) < 0) {
80
+			LM_ERR("unable to ping [%.*s]\n", ka_dest->uri.len, ka_dest->uri.s);
81
+		}
82
+
83
+		ka_dest->last_checked = time(NULL);
84
+	}
85
+
86
+	return;
87
+}
88
+
89
+/*! \brief
90
+ * Callback-Function for the OPTIONS-Request
91
+ * This Function is called, as soon as the Transaction is finished
92
+ * (e. g. a Response came in, the timeout was hit, ...)
93
+ */
94
+static void ka_options_callback( struct cell *t, int type,
95
+		struct tmcb_params *ps )
96
+{
97
+	str uri = {0, 0};
98
+	sip_msg_t *msg = NULL;
99
+	ka_state state;
100
+
101
+	char *state_routes[] = {"", "keepalive:dst-up", "keepalive:dst-down"};
102
+
103
+	//NOTE: how to be sure destination is still allocated ?
104
+	ka_dest_t *ka_dest = (ka_dest_t *) (*ps->param);
105
+
106
+	uri.s   = t->to.s + 5;
107
+	uri.len = t->to.len - 8;
108
+	LM_DBG("OPTIONS-Request was finished with code %d (to %.*s)\n",
109
+			ps->code, ka_dest->uri.len, ka_dest->uri.s); //uri.len, uri.s);
110
+
111
+
112
+	// accepting 2XX return codes
113
+	if (ps->code >= 200 && ps->code <= 299) {
114
+		state              = KA_STATE_UP;
115
+		ka_dest->last_down = time(NULL);
116
+	} else {
117
+		state              = KA_STATE_DOWN;
118
+		ka_dest->last_up   = time(NULL);
119
+	}
120
+
121
+	LM_DBG("new state is: %d\n", state);
122
+	if (state != ka_dest->state) {
123
+		ka_run_route(msg, &uri, state_routes[state]);
124
+
125
+		if(ka_dest->statechanged_clb != NULL) {
126
+			ka_dest->statechanged_clb(ka_dest->uri, state, ka_dest->user_attr);
127
+		}
128
+
129
+		ka_dest->state = state;
130
+	}
131
+}
132
+
133
+/*
134
+ * Execute kamailio script event routes
135
+ *
136
+ */
137
+static void ka_run_route(sip_msg_t *msg, str *uri, char *route)
138
+{
139
+	int rt, backup_rt;
140
+	struct run_act_ctx ctx;
141
+	sip_msg_t *fmsg;
142
+
143
+	if (route == NULL)
144
+	{
145
+		LM_ERR("bad route\n");
146
+		return;
147
+	}
148
+
149
+	LM_DBG("ka_run_route event_route[%s]\n", route);
150
+
151
+	rt = route_get(&event_rt, route);
152
+	if (rt < 0 || event_rt.rlist[rt] == NULL)
153
+	{
154
+		LM_DBG("route *%s* does not exist", route);
155
+		return;
156
+	}
157
+
158
+	fmsg = msg;
159
+	if (fmsg == NULL)
160
+	{
161
+		if (faked_msg_init() < 0)
162
+		{
163
+			LM_ERR("faked_msg_init() failed\n");
164
+			return;
165
+		}
166
+		fmsg = faked_msg_next();
167
+		fmsg->parsed_orig_ruri_ok = 0;
168
+		fmsg->new_uri = *uri;
169
+	}
170
+
171
+	backup_rt = get_route_type();
172
+	set_route_type(REQUEST_ROUTE);
173
+	init_run_actions_ctx(&ctx);
174
+	run_top_route(event_rt.rlist[rt], fmsg, 0);
175
+	set_route_type(backup_rt);
176
+}
177
+
178
+
179
+/*
180
+ * copy str into dynamically allocated shm memory
181
+ */
182
+int ka_str_copy(str src, str *dest, char *prefix) {
183
+	int lp = prefix?strlen(prefix):0;
184
+
185
+	dest->s = (char *) shm_malloc((src.len + 1 + lp) * sizeof(char));
186
+	if(dest->s == NULL)
187
+	{
188
+		LM_ERR("no more memory!\n");
189
+		return -1;
190
+	}
191
+
192
+	if(prefix)
193
+		strncpy(dest->s, prefix, lp);
194
+	strncpy(dest->s+lp, src.s, src.len);
195
+	dest->s[src.len+lp] = '\0';
196
+	dest->len           = src.len+lp;
197
+
198
+	return 0;
199
+}
200
+
0 201
new file mode 100644
... ...
@@ -0,0 +1,190 @@
1
+/**
2
+ * keepalive module - remote destinations probing
3
+ *
4
+ * Copyright (C) 2017 Guillaume Bour <guillaume@bour.cc>
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ */
22
+
23
+/*! \file
24
+ * \ingroup keepalive
25
+ * \brief Keepalive :: Send keepalives
26
+ */
27
+
28
+/*! \defgroup keepalive Keepalive :: Probing remote gateways by sending keepalives
29
+ */
30
+
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <stdlib.h>
34
+#include <sys/types.h>
35
+#include <unistd.h>
36
+
37
+#include "../tm/tm_load.h"
38
+#include "../dispatcher/api.h"
39
+
40
+#include "keepalive.h"
41
+#include "api.h"
42
+
43
+MODULE_VERSION
44
+
45
+
46
+static int  mod_init(void);
47
+static void mod_destroy(void);
48
+static int  ka_mod_add_destination(modparam_t type, void *val);
49
+int  ka_init_rpc(void);
50
+int         ka_alloc_destinations_list();
51
+extern void ka_check_timer(unsigned int ticks, void* param);
52
+
53
+static int cmd_is_alive(struct sip_msg* msg, char *str1, char *str2);
54
+
55
+extern struct tm_binds tmb;
56
+
57
+int ka_ping_interval = 30;
58
+ka_destinations_list_t *ka_destinations_list = NULL;
59
+
60
+
61
+static cmd_export_t cmds[]={
62
+	{"is_alive",       (cmd_function)cmd_is_alive, 1, 0, 0,
63
+		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
64
+	// internal API
65
+	{"bind_keepalive", (cmd_function)bind_keepalive, 0, 0, 0, 0},
66
+	{0,0,0,0,0,0}
67
+};
68
+
69
+
70
+static param_export_t params[]={
71
+	{"ping_interval", PARAM_INT                  , &ka_ping_interval},
72
+	{"destination"  , PARAM_STRING|USE_FUNC_PARAM, (void *)ka_mod_add_destination},
73
+	{0,0,0}
74
+};
75
+
76
+
77
+/** module exports */
78
+struct module_exports exports= {
79
+	"keepalive",
80
+	DEFAULT_DLFLAGS, /* dlopen flags */
81
+	cmds,
82
+	params,
83
+	0,          /* exported statistics */
84
+	0,          /* exported MI functions - no available anymore since 5.0 */
85
+	0,          /* exported pseudo-variables */
86
+	0,          /* extra processes */
87
+	mod_init,   /* module initialization function */
88
+	0,
89
+	(destroy_function) mod_destroy,
90
+	0           /* per-child init function */
91
+};
92
+
93
+
94
+/**
95
+ * Module initialization
96
+ */
97
+static int mod_init(void)
98
+{
99
+	LM_INFO("Initializing keepalive module\n");
100
+
101
+	if (load_tm_api( &tmb ) == -1)
102
+	{
103
+		LM_ERR("could not load the TM-functions - please load tm module\n");
104
+		return -1;
105
+	}
106
+
107
+	if(ka_init_rpc() < 0) {
108
+		LM_ERR("failed to register RPC commands\n");
109
+		return -1;
110
+	}
111
+
112
+	if (ka_alloc_destinations_list() < 0)
113
+		return -1;
114
+
115
+	if(register_timer(ka_check_timer, NULL, ka_ping_interval) < 0) {
116
+		LM_ERR("failed registering timer\n");
117
+		return -1;
118
+	}
119
+
120
+	return 0;
121
+}
122
+
123
+/*! \brief
124
+ * destroy function
125
+ */
126
+static void mod_destroy(void)
127
+{
128
+}
129
+
130
+
131
+/*! \brief
132
+ * parses string to dispatcher dst flags set
133
+ * returns <0 on failure or int with flag on success.
134
+ */
135
+int ka_parse_flags( char* flag_str, int flag_len )
136
+{
137
+	return 0;
138
+}
139
+
140
+
141
+/*
142
+ * Function callback executer per module param "destination".
143
+ * Is just a wrapper to ka_add_dest() api function
144
+ */
145
+static int ka_mod_add_destination(modparam_t type, void *val) 
146
+{
147
+	if (ka_alloc_destinations_list() < 0)
148
+		return -1;
149
+
150
+	str dest = {val, strlen(val)};
151
+	str owner = str_init("_params");
152
+	LM_DBG("adding destination %.*s\n", dest.len, dest.s);
153
+
154
+	return ka_add_dest(dest, owner, 0, 0, 0);
155
+}
156
+
157
+/*
158
+ * Allocate global variable *ka_destination_list* if not already done
159
+ * WHY:  when specifying static destinations as module param, ka_mod_add_destination() is 
160
+ *       executed BEFORE mod_init()
161
+ */
162
+int ka_alloc_destinations_list()
163
+{
164
+	if (ka_destinations_list != NULL) {
165
+		LM_DBG("ka_destinations_list already allocated\n");
166
+		return 1;
167
+	}
168
+
169
+	ka_destinations_list = (ka_destinations_list_t *) shm_malloc(sizeof(ka_destinations_list_t));
170
+	if(ka_destinations_list == NULL) {
171
+		LM_ERR("no more memory.\n");
172
+		return -1;
173
+	}
174
+
175
+	return 0;
176
+}
177
+
178
+
179
+static int cmd_is_alive(struct sip_msg* msg, char *str1, char *str2)
180
+{
181
+	str dest = {str1, strlen(str1)};
182
+
183
+	ka_state state = ka_destination_state(dest);
184
+	// must not return 0, as it stops dialplan execution
185
+	if (state == KA_STATE_UNKNOWN) {
186
+		return KA_STATE_UP;
187
+	}
188
+
189
+	return state;
190
+}
0 191
new file mode 100644
... ...
@@ -0,0 +1,101 @@
1
+/**
2
+ * keepalive module - remote destinations probing
3
+ *
4
+ * Copyright (C) 2017 Guillaume Bour <guillaume@bour.cc>
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
+ */
22
+
23
+/*! \file
24
+ * \ingroup keepalive
25
+ * \brief Keepalive :: Send keepalives
26
+ */
27
+
28
+/*! \defgroup keepalive Keepalive :: Probing remote gateways by sending keepalives
29
+ */
30
+
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <stdlib.h>
34
+#include <sys/types.h>
35
+#include <unistd.h>
36
+#include <time.h>
37
+
38
+#include "../../core/rpc.h"
39
+#include "../../core/rpc_lookup.h"
40
+
41
+#include "keepalive.h"
42
+#include "api.h"
43
+
44
+static const char *keepalive_rpc_list_doc[2];
45
+static void keepalive_rpc_list(rpc_t *rpc, void *ctx);
46
+
47
+rpc_export_t keepalive_rpc_cmds[] = {
48
+	{"keepalive.list", keepalive_rpc_list, keepalive_rpc_list_doc, 0},
49
+	{0, 0, 0, 0}
50
+};
51
+
52
+int ka_init_rpc(void) {
53
+	if (rpc_register_array(keepalive_rpc_cmds) != 0) {
54
+		LM_ERR("failed to register RPC commands\n");
55
+	}
56
+
57
+	return 0;
58
+}
59
+
60
+static const char *keepalive_rpc_list_doc[2] = {
61
+		"Return the content of dispatcher sets", 0};
62
+
63
+static void keepalive_rpc_list(rpc_t *rpc, void *ctx) {
64
+	str text = str_init("foobar");
65
+	if (rpc->add(ctx, "Sd", &text, 42) < 0) 
66
+		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
67
+	if (rpc->add(ctx, "Sd", &text, 42) < 0) 
68
+		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
69
+
70
+	void *foo;
71
+	rpc->add(ctx, "{", &foo);
72
+	rpc->struct_add(foo, "Sd", "text", &text, "number", 42);
73
+
74
+	void *bar, *baz;
75
+	rpc->add(ctx, "{", &bar);
76
+	rpc->struct_add(bar, "[", "list", &baz);
77
+	rpc->struct_add(baz, "d", "nn", 17);
78
+	rpc->struct_add(baz, "d", "nn", 22);
79
+	
80
+
81
+	for(ka_dest_t *dest = ka_destinations_list->first; dest != NULL; dest = dest->next) {
82
+		void *sub;
83
+		rpc->add(ctx, "{", &sub);
84
+
85
+		rpc->struct_add(sub, "SS", 
86
+			"uri"  , &dest->uri,
87
+			"owner", &dest->owner);
88
+
89
+		char *_ctime = ctime(&dest->last_checked);
90
+		_ctime[strlen(_ctime) - 1] = '\0';
91
+		rpc->struct_add(sub, "s", "last checked", _ctime);
92
+		char *_utime = ctime(&dest->last_up);
93
+		_utime[strlen(_utime) - 1] = '\0';
94
+		rpc->struct_add(sub, "s", "last up", _utime);
95
+		char *_dtime = ctime(&dest->last_down);
96
+		_dtime[strlen(_dtime) - 1] = '\0';
97
+		rpc->struct_add(sub, "s", "last down", _dtime);
98
+	}
99
+
100
+	return;
101
+}