Added service of message_config_user_name
[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 "messages/message_config_user_name.h"
23 #include <string.h>
24 #include <glib.h>
25 #include "log.h"
26 #include "assert.h"
27
28 #define KEEP_ALIVE_CHECK_ATTEMPTS 5
29 #define HELLO_ACCEPT_ATTEMPTS 5
30 #define HELLO_ACCEPT_INTERVAL 1000 //In ms
31 #define KEEP_ALIVE_CHECK_INTERVAL 1000 //In ms
32
33 #define SAFE_SOURCE_REMOVE(source)\
34 do { \
35         if(source) { \
36                 g_source_remove(source); \
37         } \
38         source = 0; \
39 } while(0)
40
41 typedef struct _controller_connection_manager_info {
42         controller_connection_state_e state;
43         char *controller_address;
44         int controller_port;
45         connection_state_cb state_cb;
46         command_received_cb command_cb;
47         user_name_received_cb user_name_cb;
48         int keep_alive_check_attempts_left;
49         int connect_accept_attempts_left;
50         guint connect_accept_timer;
51         guint keep_alive_check_timer;
52         unsigned long long int last_serial;
53         message_factory_t *message_factory;
54 } _controller_connection_manager_s;
55
56 static _controller_connection_manager_s s_info = {
57         .state = CONTROLLER_CONNECTION_STATE_READY,
58         .controller_address = NULL,
59         .state_cb = NULL,
60         .keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS,
61         .connect_accept_attempts_left = HELLO_ACCEPT_ATTEMPTS,
62         .connect_accept_timer = 0,
63         .keep_alive_check_timer = 0
64 };
65
66 static int _try_connect(const char *ip, int port);
67 static void _disconnect();
68 static void _set_state(controller_connection_state_e state);
69 static void _receive_cb(message_t *message, void *data);
70 static void _reset_counters();
71 static gboolean _send_connect_accept();
72 static gboolean _connect_accept_timer_cb(gpointer data);
73 static gboolean _keep_alive_check_timer_cb(gpointer data);
74 static int _addr_cmp(const char *addr1, int port1, const char *addr2, int port2);
75
76 int controller_connection_manager_listen()
77 {
78         s_info.message_factory = message_factory_create();
79         if(!s_info.message_factory) {
80                 return -1;
81         }
82         message_manager_set_receive_message_cb(_receive_cb, NULL);
83         return 0;
84 }
85
86 controller_connection_state_e controller_connection_manager_get_state()
87 {
88         return s_info.state;
89 }
90
91 void controller_connection_manager_set_state_change_cb(connection_state_cb callback)
92 {
93         s_info.state_cb = callback;
94 }
95
96 void controller_connection_manager_set_command_received_cb(command_received_cb callback)
97 {
98         s_info.command_cb = callback;
99 }
100
101 void controller_connection_manager_set_user_name_received_cb(user_name_received_cb callback)
102 {
103         s_info.user_name_cb = callback;
104 }
105
106 void controller_connection_manager_handle_message(message_t *message)
107 {
108         if(!s_info.message_factory) {
109                 _E("Message factory not initialized");
110                 return;
111         }
112         const char *msg_address;
113         int msg_port;
114         message_get_sender(message, &msg_address, &msg_port);
115         int address_match = !_addr_cmp(s_info.controller_address, s_info.controller_port, msg_address, msg_port);
116
117         switch(message_get_type(message)) {
118         case MESSAGE_CONNECT:
119                 if(s_info.state == CONTROLLER_CONNECTION_STATE_READY) {
120                         if(_try_connect(msg_address, msg_port)) {
121                                 _E("Received CONNECT, but cannot establish connection");
122                         } else {
123                                 s_info.last_serial = message_get_serial(message);
124                                 _I("Established connection with %s:%d", s_info.controller_address, s_info.controller_port);
125                         }
126                 } else {
127                         message_t *response = message_factory_create_message(s_info.message_factory, MESSAGE_CONNECT_REFUSED);
128                         if(!response) {
129                                 _W("Failed to create CONNECT_REFUSED message");
130                                 break;
131                         }
132                         message_set_receiver(response, msg_address, msg_port);
133                         message_manager_send_message(response);
134                         message_destroy(response);
135                 }
136                 break;
137         case MESSAGE_KEEP_ALIVE:
138                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
139                         unsigned long long int serial = message_get_serial(message);
140                         if(serial > s_info.last_serial) {
141                                 SAFE_SOURCE_REMOVE(s_info.connect_accept_timer);
142                                 s_info.keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS;
143                                 message_ack_t response;
144                                 message_ack_init_from_request(&response, message);
145                                 message_set_receiver((message_t*)&response, s_info.controller_address, s_info.controller_port);
146                                 message_manager_send_message((message_t*)&response);
147                                 message_destroy((message_t*)&response);
148                                 s_info.last_serial = serial;
149                         } else {
150                                 _W("Received late KEEP_ALIVE (%d, when last is %d)", serial, s_info.last_serial);
151                         }
152                 } else {
153                         _W("Unexpectedly received KEEP_ALIVE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
154                 }
155                 break;
156         case MESSAGE_COMMAND:
157                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
158                         const command_s *command = message_command_get_command((message_command_t *) message);
159                         if(!command) {
160                                 _E("Failed to obtain command");
161                                 break;
162                         }
163                         if(s_info.command_cb) {
164                                 s_info.command_cb(*command);
165                         }
166                 } else {
167                         _W("Unexpectedly received COMMAND from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
168                 }
169                 break;
170         case MESSAGE_BYE:
171                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
172                         _disconnect();
173                 } else {
174                         _W("Unexpectedly received BYE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
175                 }
176                 break;
177         case MESSAGE_CONFIG_USER_NAME:
178                 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
179                         if(s_info.user_name_cb) {
180                                 s_info.user_name_cb(message_config_user_name_get_name((message_config_user_name_t*)message));
181                         }
182                         message_ack_t response;
183                         message_ack_init_from_request(&response, message);
184                         message_set_receiver((message_t*)&response, s_info.controller_address, s_info.controller_port);
185                         message_manager_send_message((message_t*)&response);
186                         message_destroy((message_t*)&response);
187                 } else {
188                         _W("Unexpectedly received BYE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
189                 };
190                 break;
191         default:
192                 _W("Received incorrect message");
193         }
194 }
195
196 void controller_connection_manager_release()
197 {
198         if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED) {
199                 _disconnect();
200         }
201         message_factory_destroy(s_info.message_factory);
202         message_manager_shutdown();
203         s_info.message_factory = NULL;
204 }
205
206 static void _set_state(controller_connection_state_e state)
207 {
208         if(state == s_info.state) {
209                 return;
210         }
211
212         controller_connection_state_e previous = s_info.state;
213         s_info.state = state;
214         _I("Connection state changed from %d to %d", previous, state);
215         if(s_info.state_cb) {
216                 s_info.state_cb(previous, state);
217         }
218 }
219
220 static void _receive_cb(message_t *message, void *data)
221 {
222         controller_connection_manager_handle_message(message);
223 }
224
225 static int _try_connect(const char *ip, int port)
226 {
227         if(s_info.state != CONTROLLER_CONNECTION_STATE_READY) {
228                 _E("Attempt to connect failed - already reserved by %s:%d", s_info.controller_address, s_info.controller_port);
229                 return -1;
230         }
231
232         s_info.controller_address = strdup(ip);
233         if(!s_info.controller_address) {
234                 _E("Failed to save controller address");
235                 return -1;
236         }
237
238         s_info.controller_port = port;
239         _set_state(CONTROLLER_CONNECTION_STATE_RESERVED);
240         if(!_send_connect_accept()) {
241                 _E("Failed to send CONNECT_ACCEPT");
242         }
243         _reset_counters();
244         s_info.connect_accept_timer = g_timeout_add(HELLO_ACCEPT_INTERVAL, _connect_accept_timer_cb, NULL);
245         s_info.keep_alive_check_timer = g_timeout_add(KEEP_ALIVE_CHECK_INTERVAL, _keep_alive_check_timer_cb, NULL);
246         return 0;
247 }
248
249 static void _disconnect()
250 {
251         if(s_info.state == CONTROLLER_CONNECTION_STATE_READY) {
252                 _W("No connection already initiated");
253                 return;
254         }
255
256         SAFE_SOURCE_REMOVE(s_info.connect_accept_timer);
257
258         SAFE_SOURCE_REMOVE(s_info.keep_alive_check_timer);
259
260         free(s_info.controller_address);
261         s_info.controller_port = 0;
262         _set_state(CONTROLLER_CONNECTION_STATE_READY);
263 }
264
265 static gboolean _send_connect_accept()
266 {
267         if(s_info.state != CONTROLLER_CONNECTION_STATE_RESERVED) {
268                 _E("Car is not reserved");
269                 return FALSE;
270         }
271         if(!--s_info.connect_accept_attempts_left) {
272                 _W("Connect accepted, but no KEEP ALIVE received - disconnecting started");
273                 _disconnect();
274                 return FALSE;
275         }
276         message_t *message = message_factory_create_message(s_info.message_factory, MESSAGE_CONNECT_ACCEPTED);
277         message_set_receiver(message, s_info.controller_address, s_info. controller_port);
278         message_manager_send_message(message);
279         message_destroy(message);
280         return TRUE;
281 }
282
283 static gboolean _connect_accept_timer_cb(gpointer data)
284 {
285         return _send_connect_accept();
286 }
287
288 static gboolean _keep_alive_check_timer_cb(gpointer data)
289 {
290         if(s_info.state != CONTROLLER_CONNECTION_STATE_RESERVED) {
291                 _E("Incorrect state of connection");
292         }
293
294         if(!s_info.keep_alive_check_attempts_left--) {
295                 _W("KEEP ALIVE timeout reached - disconnecting started");
296                 _disconnect();
297                 return FALSE;
298         }
299         return TRUE;
300 }
301
302 static void _reset_counters()
303 {
304         s_info.keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS;
305         s_info.connect_accept_attempts_left = HELLO_ACCEPT_ATTEMPTS;
306 }
307
308 static int _addr_cmp(const char *addr1, int port1, const char *addr2, int port2)
309 {
310         if(addr1 == NULL || addr2 == NULL) {
311                 return -1;
312         }
313
314         unsigned int address_length = strlen(addr2);
315         return port1 != port2 || strlen(addr1) != address_length || strncmp(addr1, addr2, address_length);
316 }