Implemented controler connection manager
[apps/native/gear-racing-car.git] / src / controller_connection_manager.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Flora License, Version 1.1 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "controller_connection_manager.h"
18 #include "messages/message_manager.h"
19 #include "messages/message_command.h"
20 #include "messages/message_ack.h"
21 #include "messages/message_factory.h"
22 #include <string.h>
23 #include <glib.h>
24 #include "log.h"
25 #include "assert.h"
26
27 #define KEEP_ALIVE_CHECK_ATTEMPTS 5
28 #define HELLO_ACCEPT_ATTEMPTS 5
29 #define HELLO_ACCEPT_INTERVAL 1000 //In ms
30 #define KEEP_ALIVE_CHECK_INTERVAL 1000 //In ms
31
32 #define SAFE_SOURCE_REMOVE(source)\
33 do { \
34         if(source) { \
35                 g_source_remove(source); \
36         } \
37         source = 0; \
38 } while(0)
39
40 typedef struct _controller_connection_manager_info {
41         controller_connection_state_e state;
42         char *controller_address;
43         int controller_port;
44         connection_state_cb state_cb;
45         command_received_cb command_cb;
46         int keep_alive_check_attempts_left;
47         int connect_accept_attempts_left;
48         guint connect_accept_timer;
49         guint keep_alive_check_timer;
50         unsigned long long int last_serial;
51         message_factory_t *message_factory;
52 } _controller_connection_manager_s;
53
54 static _controller_connection_manager_s s_info = {
55         .state = CONTROLLER_CONNECTION_STATE_READY,
56         .controller_address = NULL,
57         .state_cb = NULL,
58         .keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS,
59         .connect_accept_attempts_left = HELLO_ACCEPT_ATTEMPTS,
60         .connect_accept_timer = 0,
61         .keep_alive_check_timer = 0
62 };
63
64 static int _try_connect(const char *ip, int port);
65 static void _disconnect();
66 static void _set_state(controller_connection_state_e state);
67 static void _receive_cb(message_t *message, void *data);
68 static void _reset_counters();
69 static gboolean _send_connect_accept();
70 static gboolean _connect_accept_timer_cb(gpointer data);
71 static gboolean _keep_alive_check_timer_cb(gpointer data);
72 static int _addr_cmp(const char *addr1, int port1, const char *addr2, int port2);
73
74 int controller_connection_manager_listen()
75 {
76         s_info.message_factory = message_factory_create();
77         if(!s_info.message_factory) {
78                 return -1;
79         }
80         message_manager_set_receive_message_cb(_receive_cb, NULL);
81         return 0;
82 }
83
84 controller_connection_state_e controller_connection_manager_get_state()
85 {
86         return s_info.state;
87 }
88
89 void controller_connection_manager_set_state_change_cb(connection_state_cb callback)
90 {
91         s_info.state_cb = callback;
92 }
93
94 void controller_connection_manager_set_command_received_cb(command_received_cb callback)
95 {
96         s_info.command_cb = callback;
97 }
98
99 void controller_connection_manager_handle_message(message_t *message)
100 {
101         if(!s_info.message_factory) {
102                 _E("Message factory not initialized");
103                 return;
104         }
105         const char *msg_address;
106         int msg_port;
107         message_get_sender(message, &msg_address, &msg_port);
108         int address_match = !_addr_cmp(s_info.controller_address, s_info.controller_port, msg_address, msg_port);
109
110         switch(message_get_type(message)) {
111         case MESSAGE_CONNECT:
112                 if(s_info.state == CONTROLLER_CONNECTION_STATE_READY) {
113                         if(_try_connect(msg_address, msg_port)) {
114                                 _E("Received CONNECT, but cannot establish connection");
115                         } else {
116                                 s_info.last_serial = message_get_serial(message);
117                                 _I("Established connection with %s:%d", s_info.controller_address, s_info.controller_port);
118                         }
119                 } else {
120                         message_t *response = message_factory_create_message(s_info.message_factory, MESSAGE_CONNECT_REFUSED);
121                         if(!response) {
122                                 _W("Failed to create CONNECT_REFUSED message");
123                                 break;
124                         }
125                         message_set_receiver(response, msg_address, msg_port);
126                         message_manager_send_message(response);
127                         message_destroy(response);
128                 }
129                 break;
130         case MESSAGE_KEEP_ALIVE:
131                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
132                         unsigned long long int serial = message_get_serial(message);
133                         if(serial > s_info.last_serial) {
134                                 SAFE_SOURCE_REMOVE(s_info.connect_accept_timer);
135                                 s_info.keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS;
136                                 message_ack_t response;
137                                 message_ack_init_from_request(&response, message);
138                                 message_set_receiver((message_t*)&response, s_info.controller_address, s_info.controller_port);
139                                 message_manager_send_message((message_t*)&response);
140                                 message_destroy((message_t*)&response);
141                                 s_info.last_serial = serial;
142                         } else {
143                                 _W("Received late KEEP_ALIVE (%d, when last is %d)", serial, s_info.last_serial);
144                         }
145                 } else {
146                         _W("Unexpectedly received KEEP_ALIVE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
147                 }
148                 break;
149         case MESSAGE_COMMAND:
150                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
151                         const command_s *command = message_command_get_command((message_command_t *) message);
152                         if(!command) {
153                                 _E("Failed to obtain command");
154                                 break;
155                         }
156                         if(s_info.command_cb) {
157                                 s_info.command_cb(*command);
158                         }
159                 } else {
160                         _W("Unexpectedly received COMMAND from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
161                 }
162                 break;
163         case MESSAGE_BYE:
164                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
165                         _disconnect();
166                 } else {
167                         _W("Unexpectedly received BYE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
168                 }
169                 break;
170         default:
171                 _W("Received incorrect message");
172         }
173 }
174
175 void controller_connection_manager_release()
176 {
177         if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED) {
178                 _disconnect();
179         }
180         message_factory_destroy(s_info.message_factory);
181         message_manager_shutdown();
182         s_info.message_factory = NULL;
183 }
184
185 static void _set_state(controller_connection_state_e state)
186 {
187         if(state == s_info.state) {
188                 return;
189         }
190
191         controller_connection_state_e previous = s_info.state;
192         s_info.state = state;
193         _I("Connection state changed from %d to %d", previous, state);
194         if(s_info.state_cb) {
195                 s_info.state_cb(previous, state);
196         }
197 }
198
199 static void _receive_cb(message_t *message, void *data)
200 {
201         controller_connection_manager_handle_message(message);
202 }
203
204 static int _try_connect(const char *ip, int port)
205 {
206         if(s_info.state != CONTROLLER_CONNECTION_STATE_READY) {
207                 _E("Attempt to connect failed - already reserved by %s:%d", s_info.controller_address, s_info.controller_port);
208                 return -1;
209         }
210
211         s_info.controller_address = strdup(ip);
212         if(!s_info.controller_address) {
213                 _E("Failed to save controller address");
214                 return -1;
215         }
216
217         s_info.controller_port = port;
218         _set_state(CONTROLLER_CONNECTION_STATE_RESERVED);
219         if(!_send_connect_accept()) {
220                 _E("Failed to send CONNECT_ACCEPT");
221         }
222         _reset_counters();
223         s_info.connect_accept_timer = g_timeout_add(HELLO_ACCEPT_INTERVAL, _connect_accept_timer_cb, NULL);
224         s_info.keep_alive_check_timer = g_timeout_add(KEEP_ALIVE_CHECK_INTERVAL, _keep_alive_check_timer_cb, NULL);
225         return 0;
226 }
227
228 static void _disconnect()
229 {
230         if(s_info.state == CONTROLLER_CONNECTION_STATE_READY) {
231                 _W("No connection already initiated");
232                 return;
233         }
234
235         SAFE_SOURCE_REMOVE(s_info.connect_accept_timer);
236
237         SAFE_SOURCE_REMOVE(s_info.keep_alive_check_timer);
238
239         free(s_info.controller_address);
240         s_info.controller_port = 0;
241         _set_state(CONTROLLER_CONNECTION_STATE_READY);
242 }
243
244 static gboolean _send_connect_accept()
245 {
246         if(s_info.state != CONTROLLER_CONNECTION_STATE_RESERVED) {
247                 _E("Car is not reserved");
248                 return FALSE;
249         }
250         if(!--s_info.connect_accept_attempts_left) {
251                 _W("Connect accepted, but no KEEP ALIVE received - disconnecting started");
252                 _disconnect();
253                 return FALSE;
254         }
255         message_t *message = message_factory_create_message(s_info.message_factory, MESSAGE_CONNECT_ACCEPTED);
256         message_set_receiver(message, s_info.controller_address, s_info. controller_port);
257         message_manager_send_message(message);
258         message_destroy(message);
259         return TRUE;
260 }
261
262 static gboolean _connect_accept_timer_cb(gpointer data)
263 {
264         return _send_connect_accept();
265 }
266
267 static gboolean _keep_alive_check_timer_cb(gpointer data)
268 {
269         if(s_info.state != CONTROLLER_CONNECTION_STATE_RESERVED) {
270                 _E("Incorrect state of connection");
271         }
272
273         if(!s_info.keep_alive_check_attempts_left--) {
274                 _W("KEEP ALIVE timeout reached - disconnecting started");
275                 _disconnect();
276                 return FALSE;
277         }
278         return TRUE;
279 }
280
281 static void _reset_counters()
282 {
283         s_info.keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS;
284         s_info.connect_accept_attempts_left = HELLO_ACCEPT_ATTEMPTS;
285 }
286
287 static int _addr_cmp(const char *addr1, int port1, const char *addr2, int port2)
288 {
289         if(addr1 == NULL || addr2 == NULL) {
290                 return -1;
291         }
292
293         unsigned int address_length = strlen(addr2);
294         return port1 != port2 || strlen(addr1) != address_length || strncmp(addr1, addr2, address_length);
295 }