2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
8 * http://floralicense.org/license/
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.
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"
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
32 #define SAFE_SOURCE_REMOVE(source)\
35 g_source_remove(source); \
40 typedef struct _controller_connection_manager_info {
41 controller_connection_state_e state;
42 char *controller_address;
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;
54 static _controller_connection_manager_s s_info = {
55 .state = CONTROLLER_CONNECTION_STATE_READY,
56 .controller_address = 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
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);
74 int controller_connection_manager_listen()
76 s_info.message_factory = message_factory_create();
77 if(!s_info.message_factory) {
80 message_manager_set_receive_message_cb(_receive_cb, NULL);
84 controller_connection_state_e controller_connection_manager_get_state()
89 void controller_connection_manager_set_state_change_cb(connection_state_cb callback)
91 s_info.state_cb = callback;
94 void controller_connection_manager_set_command_received_cb(command_received_cb callback)
96 s_info.command_cb = callback;
99 void controller_connection_manager_handle_message(message_t *message)
101 if(!s_info.message_factory) {
102 _E("Message factory not initialized");
105 const char *msg_address;
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);
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");
116 s_info.last_serial = message_get_serial(message);
117 _I("Established connection with %s:%d", s_info.controller_address, s_info.controller_port);
120 message_t *response = message_factory_create_message(s_info.message_factory, MESSAGE_CONNECT_REFUSED);
122 _W("Failed to create CONNECT_REFUSED message");
125 message_set_receiver(response, msg_address, msg_port);
126 message_manager_send_message(response);
127 message_destroy(response);
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;
143 _W("Received late KEEP_ALIVE (%d, when last is %d)", serial, s_info.last_serial);
146 _W("Unexpectedly received KEEP_ALIVE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
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);
153 _E("Failed to obtain command");
156 if(s_info.command_cb) {
157 s_info.command_cb(*command);
160 _W("Unexpectedly received COMMAND from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
164 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED && address_match) {
167 _W("Unexpectedly received BYE from %s:%d (address_match == %d)", msg_address, msg_port, address_match);
171 _W("Received incorrect message");
175 void controller_connection_manager_release()
177 if(s_info.state == CONTROLLER_CONNECTION_STATE_RESERVED) {
180 message_factory_destroy(s_info.message_factory);
181 message_manager_shutdown();
182 s_info.message_factory = NULL;
185 static void _set_state(controller_connection_state_e state)
187 if(state == s_info.state) {
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);
199 static void _receive_cb(message_t *message, void *data)
201 controller_connection_manager_handle_message(message);
204 static int _try_connect(const char *ip, int port)
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);
211 s_info.controller_address = strdup(ip);
212 if(!s_info.controller_address) {
213 _E("Failed to save controller address");
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");
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);
228 static void _disconnect()
230 if(s_info.state == CONTROLLER_CONNECTION_STATE_READY) {
231 _W("No connection already initiated");
235 SAFE_SOURCE_REMOVE(s_info.connect_accept_timer);
237 SAFE_SOURCE_REMOVE(s_info.keep_alive_check_timer);
239 free(s_info.controller_address);
240 s_info.controller_port = 0;
241 _set_state(CONTROLLER_CONNECTION_STATE_READY);
244 static gboolean _send_connect_accept()
246 if(s_info.state != CONTROLLER_CONNECTION_STATE_RESERVED) {
247 _E("Car is not reserved");
250 if(!--s_info.connect_accept_attempts_left) {
251 _W("Connect accepted, but no KEEP ALIVE received - disconnecting started");
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);
262 static gboolean _connect_accept_timer_cb(gpointer data)
264 return _send_connect_accept();
267 static gboolean _keep_alive_check_timer_cb(gpointer data)
269 if(s_info.state != CONTROLLER_CONNECTION_STATE_RESERVED) {
270 _E("Incorrect state of connection");
273 if(!s_info.keep_alive_check_attempts_left--) {
274 _W("KEEP ALIVE timeout reached - disconnecting started");
281 static void _reset_counters()
283 s_info.keep_alive_check_attempts_left = KEEP_ALIVE_CHECK_ATTEMPTS;
284 s_info.connect_accept_attempts_left = HELLO_ACCEPT_ATTEMPTS;
287 static int _addr_cmp(const char *addr1, int port1, const char *addr2, int port2)
289 if(addr1 == NULL || addr2 == NULL) {
293 unsigned int address_length = strlen(addr2);
294 return port1 != port2 || strlen(addr1) != address_length || strncmp(addr1, addr2, address_length);