Browse code

keepalive: prevent race condition when deleting a destination

- Added a lock to ka_dest type, so we get it when we run callbacks that may be associated to an OPTIONS response
- Same lock is used to not remove destinations that are running callbacks
- Now find destinations consider owner and uri

Nacho Garcia Segovia authored on 14/09/2020 11:18:37
Showing 1 changed files
... ...
@@ -103,13 +103,22 @@ static void ka_options_callback(
103 103
 
104 104
 	str *uuid = (str *)(*ps->param);
105 105
 
106
+	LM_DBG("ka_options_callback with uuid: %.*s\n", uuid->len, uuid->s);
107
+
106 108
 	// Retrieve ka_dest by uuid from destination list
109
+	ka_lock_destination_list();
107 110
 	ka_dest_t *ka_dest=0,*hollow=0;
108 111
 	if (!ka_find_destination_by_uuid(*uuid, &ka_dest, &hollow)) {
109 112
 		LM_ERR("Couldn't find destination \r\n");
113
+		shm_free(uuid->s);
114
+		shm_free(uuid);
115
+		ka_unlock_destination_list();
110 116
 		return;
111 117
 	}
118
+	lock_get(&ka_dest->lock); // Lock record so we prevent to be removed in the meantime
119
+	shm_free(uuid->s);
112 120
 	shm_free(uuid);
121
+	ka_unlock_destination_list();
113 122
 
114 123
 	uri.s = t->to.s + 5;
115 124
 	uri.len = t->to.len - 8;
... ...
@@ -141,6 +150,7 @@ static void ka_options_callback(
141 150
 	if(ka_dest->response_clb != NULL) {
142 151
 		ka_dest->response_clb(&ka_dest->uri, ps, ka_dest->user_attr);
143 152
 	}
153
+	lock_release(&ka_dest->lock);
144 154
 }
145 155
 
146 156
 /*
Browse code

keepalive: added uuid to ka_dest structure to avoid passing the whole struct to tm

- This avoids a race condition that may happen processing tm_request callbacl
- Allows to identify uniquely a ka_dest record

Nacho Garcia Segovia authored on 02/09/2020 13:15:41
Showing 1 changed files
... ...
@@ -67,12 +67,14 @@ ticks_t ka_check_timer(ticks_t ticks, struct timer_ln* tl, void* param)
67 67
         return (ticks_t)(0); /* stops the timer */
68 68
     }
69 69
 
70
+	str *uuid = shm_malloc(sizeof(str));
71
+	ka_str_copy(&(ka_dest->uuid), uuid, NULL);
70 72
     /* Send ping using TM-Module.
71 73
      * int request(str* m, str* ruri, str* to, str* from, str* h,
72 74
      *		str* b, str *oburi,
73 75
      *		transaction_cb cb, void* cbp); */
74 76
     set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0, TMCB_LOCAL_COMPLETED,
75
-            ka_options_callback, (void *)ka_dest);
77
+            ka_options_callback, (void *)uuid);
76 78
 
77 79
     if(tmb.t_request(&uac_r, &ka_dest->uri, &ka_dest->uri, &ka_ping_from,
78 80
                &ka_outbound_proxy)
... ...
@@ -99,8 +101,15 @@ static void ka_options_callback(
99 101
 
100 102
 	char *state_routes[] = {"", "keepalive:dst-up", "keepalive:dst-down"};
101 103
 
102
-	//NOTE: how to be sure destination is still allocated ?
103
-	ka_dest_t *ka_dest = (ka_dest_t *)(*ps->param);
104
+	str *uuid = (str *)(*ps->param);
105
+
106
+	// Retrieve ka_dest by uuid from destination list
107
+	ka_dest_t *ka_dest=0,*hollow=0;
108
+	if (!ka_find_destination_by_uuid(*uuid, &ka_dest, &hollow)) {
109
+		LM_ERR("Couldn't find destination \r\n");
110
+		return;
111
+	}
112
+	shm_free(uuid);
104 113
 
105 114
 	uri.s = t->to.s + 5;
106 115
 	uri.len = t->to.len - 8;
Browse code

keepalive: removed function name from log messages

Daniel-Constantin Mierla authored on 31/08/2020 10:15:00
Showing 1 changed files
... ...
@@ -61,7 +61,7 @@ ticks_t ka_check_timer(ticks_t ticks, struct timer_ln* tl, void* param)
61 61
 
62 62
 	ka_dest = (ka_dest_t *)param;
63 63
 
64
-    LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
64
+    LM_DBG("dest: %.*s\n", ka_dest->uri.len, ka_dest->uri.s);
65 65
 
66 66
     if(ka_counter_del > 0 && ka_dest->counter > ka_counter_del) {
67 67
         return (ticks_t)(0); /* stops the timer */
... ...
@@ -104,7 +104,7 @@ static void ka_options_callback(
104 104
 
105 105
 	uri.s = t->to.s + 5;
106 106
 	uri.len = t->to.len - 8;
107
-	LM_DBG("OPTIONS-Request was finished with code %d (to %.*s)\n", ps->code,
107
+	LM_DBG("OPTIONS request was finished with code %d (to %.*s)\n", ps->code,
108 108
 			ka_dest->uri.len, ka_dest->uri.s); //uri.len, uri.s);
109 109
 
110 110
 
... ...
@@ -149,7 +149,7 @@ static void ka_run_route(sip_msg_t *msg, str *uri, char *route)
149 149
 		return;
150 150
 	}
151 151
 
152
-	LM_DBG("ka_run_route event_route[%s]\n", route);
152
+	LM_DBG("run event_route[%s]\n", route);
153 153
 
154 154
 	rt = route_get(&event_rt, route);
155 155
 	if(rt < 0 || event_rt.rlist[rt] == NULL) {
Browse code

keepalive: logging state of dest just if changed

Luis Martin Gil authored on 09/06/2020 08:48:16
Showing 1 changed files
... ...
@@ -119,7 +119,6 @@ static void ka_options_callback(
119 119
 		ka_dest->counter++;
120 120
 	}
121 121
 
122
-	LM_DBG("new state is: %d\n", state);
123 122
 	if(state != ka_dest->state) {
124 123
 		ka_run_route(msg, &uri, state_routes[state]);
125 124
 
... ...
@@ -127,6 +126,7 @@ static void ka_options_callback(
127 126
 			ka_dest->statechanged_clb(&ka_dest->uri, state, ka_dest->user_attr);
128 127
 		}
129 128
 
129
+		LM_DBG("new state is: %d\n", state);
130 130
 		ka_dest->state = state;
131 131
 	}
132 132
 	if(ka_dest->response_clb != NULL) {
Browse code

keepalive: early start of OPTIONS checking

- Current code takes some time to start checking (ping_interval). So, if someone sets a really high ping_interval it takes a while to get destination status. This change fires the first OPTIONS check just 3 seconds (fixed) after the destination is added. The checks would be done with the pace defined in ping_interval.

Nacho Garcia Segovia authored on 15/05/2020 06:21:15
Showing 1 changed files
... ...
@@ -82,7 +82,7 @@ ticks_t ka_check_timer(ticks_t ticks, struct timer_ln* tl, void* param)
82 82
 
83 83
     ka_dest->last_checked = time(NULL);
84 84
 
85
-	return (ticks_t)(-1); /* periodical */
85
+	return ka_dest->ping_interval; /* periodical, but based on dest->ping_interval, not on initial_timeout */
86 86
 }
87 87
 
88 88
 /*! \brief
Browse code

keepalive: Added callback to run on each destination response.

- This functionality it's just available when using api.h bindings. For exported functions no callback will be used, so this doesn't break cfg or rpc api.
- Modified add_destination function to provide this new callback as a parameter.

Nacho Garcia Segovia authored on 07/05/2020 21:50:10
Showing 1 changed files
... ...
@@ -129,6 +129,9 @@ static void ka_options_callback(
129 129
 
130 130
 		ka_dest->state = state;
131 131
 	}
132
+	if(ka_dest->response_clb != NULL) {
133
+		ka_dest->response_clb(&ka_dest->uri, ps, ka_dest->user_attr);
134
+	}
132 135
 }
133 136
 
134 137
 /*
Browse code

keepalive: custom pinging interval per destination

- This functionality it's just available when using api.h bindings. For exported functions current value ka_ping_interval is used.
- Modified add_destination function to provide this new parameter.
- Now we have one timer per destination, instead of multiple, so we don't need to iterate over all destinations. Timers are cleaned when destinations are removed.

Nacho Garcia Segovia authored on 06/05/2020 21:10:40
Showing 1 changed files
... ...
@@ -48,47 +48,41 @@ static void ka_options_callback(struct cell *t, int type,
48 48
 
49 49
 extern str ka_ping_from;
50 50
 /*! \brief
51
- * Timer for checking probing destinations
51
+ * Callback run from timer,  for probing a destination
52 52
  *
53 53
  * This timer is regularly fired.
54 54
  */
55
-void ka_check_timer(unsigned int ticks, void *param)
55
+ticks_t ka_check_timer(ticks_t ticks, struct timer_ln* tl, void* param)
56 56
 {
57 57
 	ka_dest_t *ka_dest;
58 58
 	str ka_ping_method = str_init("OPTIONS");
59 59
 	str ka_outbound_proxy = {0, 0};
60 60
 	uac_req_t uac_r;
61 61
 
62
-	LM_DBG("ka check timer\n");
62
+	ka_dest = (ka_dest_t *)param;
63 63
 
64
-	ka_lock_destination_list();
64
+    LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
65 65
 
66
-	for(ka_dest = ka_destinations_list->first; ka_dest != NULL;
67
-			ka_dest = ka_dest->next) {
68
-		LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
66
+    if(ka_counter_del > 0 && ka_dest->counter > ka_counter_del) {
67
+        return (ticks_t)(0); /* stops the timer */
68
+    }
69 69
 
70
-		if(ka_counter_del > 0 && ka_dest->counter > ka_counter_del) {
71
-			continue;
72
-		}
70
+    /* Send ping using TM-Module.
71
+     * int request(str* m, str* ruri, str* to, str* from, str* h,
72
+     *		str* b, str *oburi,
73
+     *		transaction_cb cb, void* cbp); */
74
+    set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0, TMCB_LOCAL_COMPLETED,
75
+            ka_options_callback, (void *)ka_dest);
73 76
 
74
-		/* Send ping using TM-Module.
75
-		 * int request(str* m, str* ruri, str* to, str* from, str* h,
76
-		 *		str* b, str *oburi,
77
-		 *		transaction_cb cb, void* cbp); */
78
-		set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0, TMCB_LOCAL_COMPLETED,
79
-				ka_options_callback, (void *)ka_dest);
80
-
81
-		if(tmb.t_request(&uac_r, &ka_dest->uri, &ka_dest->uri, &ka_ping_from,
82
-				   &ka_outbound_proxy)
83
-				< 0) {
84
-			LM_ERR("unable to ping [%.*s]\n", ka_dest->uri.len, ka_dest->uri.s);
85
-		}
77
+    if(tmb.t_request(&uac_r, &ka_dest->uri, &ka_dest->uri, &ka_ping_from,
78
+               &ka_outbound_proxy)
79
+            < 0) {
80
+        LM_ERR("unable to ping [%.*s]\n", ka_dest->uri.len, ka_dest->uri.s);
81
+    }
86 82
 
87
-		ka_dest->last_checked = time(NULL);
88
-	}
89
-	ka_unlock_destination_list();
83
+    ka_dest->last_checked = time(NULL);
90 84
 
91
-	return;
85
+	return (ticks_t)(-1); /* periodical */
92 86
 }
93 87
 
94 88
 /*! \brief
Browse code

keepalive: ignore delete_counter if it is set to 0

Nacho Garcia Segovia authored on 28/04/2020 12:08:19
Showing 1 changed files
... ...
@@ -67,15 +67,14 @@ void ka_check_timer(unsigned int ticks, void *param)
67 67
 			ka_dest = ka_dest->next) {
68 68
 		LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
69 69
 
70
+		if(ka_counter_del > 0 && ka_dest->counter > ka_counter_del) {
71
+			continue;
72
+		}
73
+
70 74
 		/* Send ping using TM-Module.
71 75
 		 * int request(str* m, str* ruri, str* to, str* from, str* h,
72 76
 		 *		str* b, str *oburi,
73 77
 		 *		transaction_cb cb, void* cbp); */
74
-
75
-		if(ka_dest->counter>ka_counter_del){
76
-			continue;
77
-		}
78
-
79 78
 		set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0, TMCB_LOCAL_COMPLETED,
80 79
 				ka_options_callback, (void *)ka_dest);
81 80
 
Browse code

keepalive : added new function del_destination and added cfg functions (#2133)

* keepalive : added new function del_destination and added .cfg functions

added new function del_destination that deletes sip address from list
added add_destination module functions for kamailio.cfg
added counter parameter for attempt count. after count pass, module dont try until it adds again.
added kemi interfaces both of them
added lock to stack
added find_destination function

* keepalive : fixed function names and re-placed un/lock functions

fixed function names and re-placed un/lock functions

* keepalive : added doc for exported new functions ka_add_destination and ka_del_destination [skip ci]

added documents for exported new function ka_add_destination and ka_del_destination
renamed in documents from is_alive to ka_is_alive
added missing rpc command in documents

Yasin CANER authored on 12/12/2019 11:06:24 • Daniel-Constantin Mierla committed on 12/12/2019 11:06:24
Showing 1 changed files
... ...
@@ -46,7 +46,7 @@ static void ka_run_route(sip_msg_t *msg, str *uri, char *route);
46 46
 static void ka_options_callback(struct cell *t, int type,
47 47
 		struct tmcb_params *ps);
48 48
 
49
-
49
+extern str ka_ping_from;
50 50
 /*! \brief
51 51
  * Timer for checking probing destinations
52 52
  *
... ...
@@ -56,12 +56,13 @@ void ka_check_timer(unsigned int ticks, void *param)
56 56
 {
57 57
 	ka_dest_t *ka_dest;
58 58
 	str ka_ping_method = str_init("OPTIONS");
59
-	str ka_ping_from = str_init("sip:dispatcher@localhost");
60 59
 	str ka_outbound_proxy = {0, 0};
61 60
 	uac_req_t uac_r;
62 61
 
63 62
 	LM_DBG("ka check timer\n");
64 63
 
64
+	ka_lock_destination_list();
65
+
65 66
 	for(ka_dest = ka_destinations_list->first; ka_dest != NULL;
66 67
 			ka_dest = ka_dest->next) {
67 68
 		LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
... ...
@@ -70,6 +71,11 @@ void ka_check_timer(unsigned int ticks, void *param)
70 71
 		 * int request(str* m, str* ruri, str* to, str* from, str* h,
71 72
 		 *		str* b, str *oburi,
72 73
 		 *		transaction_cb cb, void* cbp); */
74
+
75
+		if(ka_dest->counter>ka_counter_del){
76
+			continue;
77
+		}
78
+
73 79
 		set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0, TMCB_LOCAL_COMPLETED,
74 80
 				ka_options_callback, (void *)ka_dest);
75 81
 
... ...
@@ -81,6 +87,7 @@ void ka_check_timer(unsigned int ticks, void *param)
81 87
 
82 88
 		ka_dest->last_checked = time(NULL);
83 89
 	}
90
+	ka_unlock_destination_list();
84 91
 
85 92
 	return;
86 93
 }
... ...
@@ -112,9 +119,11 @@ static void ka_options_callback(
112 119
 	if(ps->code >= 200 && ps->code <= 299) {
113 120
 		state = KA_STATE_UP;
114 121
 		ka_dest->last_down = time(NULL);
122
+		ka_dest->counter=0;
115 123
 	} else {
116 124
 		state = KA_STATE_DOWN;
117 125
 		ka_dest->last_up = time(NULL);
126
+		ka_dest->counter++;
118 127
 	}
119 128
 
120 129
 	LM_DBG("new state is: %d\n", state);
Browse code

keepalive: allow variables in cfg function parameters

- use str* instead of str for api functions

Daniel-Constantin Mierla authored on 29/05/2017 05:18:14
Showing 1 changed files
... ...
@@ -122,7 +122,7 @@ static void ka_options_callback(
122 122
 		ka_run_route(msg, &uri, state_routes[state]);
123 123
 
124 124
 		if(ka_dest->statechanged_clb != NULL) {
125
-			ka_dest->statechanged_clb(ka_dest->uri, state, ka_dest->user_attr);
125
+			ka_dest->statechanged_clb(&ka_dest->uri, state, ka_dest->user_attr);
126 126
 		}
127 127
 
128 128
 		ka_dest->state = state;
... ...
@@ -174,11 +174,11 @@ static void ka_run_route(sip_msg_t *msg, str *uri, char *route)
174 174
 /*
175 175
  * copy str into dynamically allocated shm memory
176 176
  */
177
-int ka_str_copy(str src, str *dest, char *prefix)
177
+int ka_str_copy(str *src, str *dest, char *prefix)
178 178
 {
179 179
 	int lp = prefix ? strlen(prefix) : 0;
180 180
 
181
-	dest->s = (char *)shm_malloc((src.len + 1 + lp) * sizeof(char));
181
+	dest->s = (char *)shm_malloc((src->len + 1 + lp) * sizeof(char));
182 182
 	if(dest->s == NULL) {
183 183
 		LM_ERR("no more memory!\n");
184 184
 		return -1;
... ...
@@ -186,9 +186,9 @@ int ka_str_copy(str src, str *dest, char *prefix)
186 186
 
187 187
 	if(prefix)
188 188
 		strncpy(dest->s, prefix, lp);
189
-	strncpy(dest->s + lp, src.s, src.len);
190
-	dest->s[src.len + lp] = '\0';
191
-	dest->len = src.len + lp;
189
+	strncpy(dest->s + lp, src->s, src->len);
190
+	dest->s[src->len + lp] = '\0';
191
+	dest->len = src->len + lp;
192 192
 
193 193
 	return 0;
194 194
 }
Browse code

keepalive: format to match default conding style and 80 chars lines

Daniel-Constantin Mierla authored on 05/04/2017 06:52:01
Showing 1 changed files
... ...
@@ -43,7 +43,8 @@
43 43
 struct tm_binds tmb;
44 44
 
45 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 );
46
+static void ka_options_callback(struct cell *t, int type,
47
+		struct tmcb_params *ps);
47 48
 
48 49
 
49 50
 /*! \brief
... ...
@@ -51,32 +52,30 @@ static void ka_options_callback( struct cell *t, int type, struct tmcb_params *p
51 52
  *
52 53
  * This timer is regularly fired.
53 54
  */
54
-void ka_check_timer(unsigned int ticks, void* param)
55
+void ka_check_timer(unsigned int ticks, void *param)
55 56
 {
56 57
 	ka_dest_t *ka_dest;
57 58
 	str ka_ping_method = str_init("OPTIONS");
58
-	str ka_ping_from   = str_init("sip:dispatcher@localhost");
59
+	str ka_ping_from = str_init("sip:dispatcher@localhost");
59 60
 	str ka_outbound_proxy = {0, 0};
60 61
 	uac_req_t uac_r;
61 62
 
62 63
 	LM_DBG("ka check timer\n");
63 64
 
64
-	for(ka_dest = ka_destinations_list->first; ka_dest != NULL; ka_dest = ka_dest->next) {
65
+	for(ka_dest = ka_destinations_list->first; ka_dest != NULL;
66
+			ka_dest = ka_dest->next) {
65 67
 		LM_DBG("ka_check_timer dest:%.*s\n", ka_dest->uri.len, ka_dest->uri.s);
66 68
 
67 69
 		/* Send ping using TM-Module.
68 70
 		 * int request(str* m, str* ruri, str* to, str* from, str* h,
69 71
 		 *		str* b, str *oburi,
70 72
 		 *		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) {
73
+		set_uac_req(&uac_r, &ka_ping_method, 0, 0, 0, TMCB_LOCAL_COMPLETED,
74
+				ka_options_callback, (void *)ka_dest);
75
+
76
+		if(tmb.t_request(&uac_r, &ka_dest->uri, &ka_dest->uri, &ka_ping_from,
77
+				   &ka_outbound_proxy)
78
+				< 0) {
80 79
 			LM_ERR("unable to ping [%.*s]\n", ka_dest->uri.len, ka_dest->uri.s);
81 80
 		}
82 81
 
... ...
@@ -91,8 +90,8 @@ void ka_check_timer(unsigned int ticks, void* param)
91 90
  * This Function is called, as soon as the Transaction is finished
92 91
  * (e. g. a Response came in, the timeout was hit, ...)
93 92
  */
94
-static void ka_options_callback( struct cell *t, int type,
95
-		struct tmcb_params *ps )
93
+static void ka_options_callback(
94
+		struct cell *t, int type, struct tmcb_params *ps)
96 95
 {
97 96
 	str uri = {0, 0};
98 97
 	sip_msg_t *msg = NULL;
... ...
@@ -101,25 +100,25 @@ static void ka_options_callback( struct cell *t, int type,
101 100
 	char *state_routes[] = {"", "keepalive:dst-up", "keepalive:dst-down"};
102 101
 
103 102
 	//NOTE: how to be sure destination is still allocated ?
104
-	ka_dest_t *ka_dest = (ka_dest_t *) (*ps->param);
103
+	ka_dest_t *ka_dest = (ka_dest_t *)(*ps->param);
105 104
 
106
-	uri.s   = t->to.s + 5;
105
+	uri.s = t->to.s + 5;
107 106
 	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);
107
+	LM_DBG("OPTIONS-Request was finished with code %d (to %.*s)\n", ps->code,
108
+			ka_dest->uri.len, ka_dest->uri.s); //uri.len, uri.s);
110 109
 
111 110
 
112 111
 	// accepting 2XX return codes
113
-	if (ps->code >= 200 && ps->code <= 299) {
114
-		state              = KA_STATE_UP;
112
+	if(ps->code >= 200 && ps->code <= 299) {
113
+		state = KA_STATE_UP;
115 114
 		ka_dest->last_down = time(NULL);
116 115
 	} else {
117
-		state              = KA_STATE_DOWN;
118
-		ka_dest->last_up   = time(NULL);
116
+		state = KA_STATE_DOWN;
117
+		ka_dest->last_up = time(NULL);
119 118
 	}
120 119
 
121 120
 	LM_DBG("new state is: %d\n", state);
122
-	if (state != ka_dest->state) {
121
+	if(state != ka_dest->state) {
123 122
 		ka_run_route(msg, &uri, state_routes[state]);
124 123
 
125 124
 		if(ka_dest->statechanged_clb != NULL) {
... ...
@@ -140,8 +139,7 @@ static void ka_run_route(sip_msg_t *msg, str *uri, char *route)
140 139
 	struct run_act_ctx ctx;
141 140
 	sip_msg_t *fmsg;
142 141
 
143
-	if (route == NULL)
144
-	{
142
+	if(route == NULL) {
145 143
 		LM_ERR("bad route\n");
146 144
 		return;
147 145
 	}
... ...
@@ -149,17 +147,14 @@ static void ka_run_route(sip_msg_t *msg, str *uri, char *route)
149 147
 	LM_DBG("ka_run_route event_route[%s]\n", route);
150 148
 
151 149
 	rt = route_get(&event_rt, route);
152
-	if (rt < 0 || event_rt.rlist[rt] == NULL)
153
-	{
150
+	if(rt < 0 || event_rt.rlist[rt] == NULL) {
154 151
 		LM_DBG("route *%s* does not exist", route);
155 152
 		return;
156 153
 	}
157 154
 
158 155
 	fmsg = msg;
159
-	if (fmsg == NULL)
160
-	{
161
-		if (faked_msg_init() < 0)
162
-		{
156
+	if(fmsg == NULL) {
157
+		if(faked_msg_init() < 0) {
163 158
 			LM_ERR("faked_msg_init() failed\n");
164 159
 			return;
165 160
 		}
... ...
@@ -179,22 +174,21 @@ static void ka_run_route(sip_msg_t *msg, str *uri, char *route)
179 174
 /*
180 175
  * copy str into dynamically allocated shm memory
181 176
  */
182
-int ka_str_copy(str src, str *dest, char *prefix) {
183
-	int lp = prefix?strlen(prefix):0;
177
+int ka_str_copy(str src, str *dest, char *prefix)
178
+{
179
+	int lp = prefix ? strlen(prefix) : 0;
184 180
 
185
-	dest->s = (char *) shm_malloc((src.len + 1 + lp) * sizeof(char));
186
-	if(dest->s == NULL)
187
-	{
181
+	dest->s = (char *)shm_malloc((src.len + 1 + lp) * sizeof(char));
182
+	if(dest->s == NULL) {
188 183
 		LM_ERR("no more memory!\n");
189 184
 		return -1;
190 185
 	}
191 186
 
192 187
 	if(prefix)
193 188
 		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;
189
+	strncpy(dest->s + lp, src.s, src.len);
190
+	dest->s[src.len + lp] = '\0';
191
+	dest->len = src.len + lp;
197 192
 
198 193
 	return 0;
199 194
 }
200
-
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 1 changed files
1 1
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
+