Modify time measure & some error on config.c
[apps/native/tizen-things-daemon.git] / daemon / src / tizen-things-daemon.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 <stdio.h>
18 #include <stdlib.h>
19 #include <glib.h>
20 #include <glib-unix.h>
21 #include <vconf.h>
22
23 #include "ttd-log.h"
24 #include "ttd-cloud-conn-state.h"
25 #include "ttd-cmd.h"
26 #include "ttd-queue.h"
27 #include "ttd-conn-mgr.h"
28 #include "ttd-task.h"
29 #include "ttd-config.h"
30 #include "ttd-http.h"
31 #include "ttd-parse-cmd.h"
32 #include "ttd-worker-interface.h"
33 #include "ttd-worker-handle.h"
34 #include "common-util.h"
35
36 #ifndef SERVER_URL
37 /* TODO : remove it after test */
38 #define TEST_SERVER_URL "http://test.showiot.xyz/api/cmd?&target=test-page-device&owner=test-page&state=created"
39 #define SERVER_URL TEST_SERVER_URL
40 #endif
41
42 typedef struct __ttd_data {
43         GMainLoop *mainloop;
44         GThreadPool *thread_pool;
45         worker_interface_h worker_itf_h;
46         bool is_time_set;
47 } ttd_data;
48
49 static gboolean __daemon_job_handler(gpointer data);
50 static gboolean __cloud_try_connect(gpointer data);
51
52 static long long _get_monotonic_time(void)
53 {
54         long long m_time = 0;
55         m_time  = common_get_monotonic_time();
56         if (m_time == 0)
57                 _E("failed to get monotonic time");
58
59         return m_time;
60 }
61
62 static const char *__ttd_get_cloud_url(void)
63 {
64         const char *url = NULL;
65
66         /* TODO : get cloud url */
67         url = SERVER_URL;
68
69         return url;
70 }
71
72 static gboolean _handle_sigint(gpointer data)
73 {
74         ttd_data *d_data = data;
75
76         _I("SIGINT received");
77
78         if (d_data && d_data->mainloop)
79                 g_main_loop_quit(d_data->mainloop);
80
81         return FALSE;
82 }
83
84 static gboolean _handle_sigterm(gpointer data)
85 {
86         ttd_data *d_data = data;
87
88         _I("SIGTERM received");
89
90         if (d_data && d_data->mainloop)
91                 g_main_loop_quit(d_data->mainloop);
92
93         return FALSE;
94 }
95
96 static void __main_thread_pool_func(gpointer thread_data, gpointer pool_data)
97 {
98         ttd_task *task = thread_data;
99         int ret = 0;
100
101         retm_if(!task, "task is NULL");
102
103         ret = ttd_task_run(task);
104         if (ret)
105                 _E("Failed to ttd_task_func_run()");
106
107         ttd_task_free(task);
108 }
109
110 static ttd_task_func __get_task_func(ttd_cmd_data *cmd)
111 {
112         ttd_task_func func = NULL;
113         retv_if(!cmd, NULL);
114
115         switch (ttd_cmd_get_type(cmd)) {
116         case TTD_CMD_TYPE_POWER:
117                 break;
118         case TTD_CMD_TYPE_CONFIG:
119                 func = ttd_config_write;
120                 break;
121         case TTD_CMD_TYPE_PACKAGE:
122         case TTD_CMD_TYPE_INFO:
123                 func = ttd_worker_launch;
124                 break;
125         case TTD_CMD_TYPE_DIAGNOSIS:
126                 break;
127         case TTD_CMD_TYPE_LOCAL:
128                 break;
129         case TTD_CMD_TYPE_UNKNOWN:
130         case TTD_CMD_TYPE_MAX:
131         default:
132                 break;
133         }
134
135         return func;
136 }
137
138 static gboolean __daemon_job_handler(gpointer data)
139 {
140         ttd_data *d_data = data;
141
142         ttd_cmd_data *cmd_data = NULL;
143         ttd_result_data_s *res_data = NULL;
144
145         if (!data) {
146                 /* Must not reach here */
147                 _E("data is NULL, daemon will be stop");
148                 abort();
149                 return FALSE;
150         }
151
152         res_data = ttd_queue_timeout_pop(TTD_QUEUE_TYPE_RESULT, 500);
153         if (res_data) {
154                 /* Do something, handles result...jfkdjlfjklajflkdsjfkdslajfkdlsjlk */
155                 /* pushes new task? or creates new command? */
156         }
157
158         cmd_data = ttd_queue_timeout_pop(TTD_QUEUE_TYPE_CMD, 500);
159         if (cmd_data) {
160                 ttd_task *new_task = NULL;
161                 ttd_task_func func = NULL;
162                 /* Do something, creates task... */
163                 func = __get_task_func(cmd_data);
164                 if (!func) {
165                         _E("task func is not defined - type[%d]",
166                                 ttd_cmd_get_type(cmd_data));
167
168                         ttd_cmd_free(cmd_data);
169                         return TRUE;
170                 }
171
172                 new_task = ttd_task_new(TTD_TASK_PRIORITY_NORMAL, func,
173                         cmd_data, (ttd_task_data_free_func)ttd_cmd_free);
174
175                 g_thread_pool_push(d_data->thread_pool, new_task, NULL);
176         }
177         return TRUE;
178 }
179
180 static int __say_hello_to_cloud(void *data)
181 {
182         int ret  = 0;
183         char *cmd = NULL;
184         long res_code = 0;
185
186         ret = ttd_http_get_cloud_cmd(__ttd_get_cloud_url(), &cmd, &res_code);
187         retvm_if(ret, -1, "failed to get cmd [%ld]", res_code);
188
189         if (cmd) {
190                 GList *cmd_list = NULL;
191                 GList *l = NULL;
192
193                 ttd_parse_json_to_cmd(cmd, &cmd_list);
194                 for (l = cmd_list; l != NULL; l = l->next) {
195                         ttd_cmd_data *cmd_data = NULL;
196
197                         cmd_data = (ttd_cmd_data *)l->data;
198                         if (cmd_data)
199                                 ttd_queue_push(TTD_QUEUE_TYPE_CMD,
200                                         cmd_data, (ttd_queue_item_free_func)ttd_cmd_free);
201                 }
202         } else
203                 _D("there is no cmd now");
204
205         return 0;
206 }
207
208 /*********** FIXME *************/
209 static gboolean __cloud_try_connect(gpointer data)
210 {
211         int ret = 0;
212         ttd_data *d_data = data;
213
214         if (!data) {
215                 /* Must not reach here */
216                 _E("data is NULL, daemon will be stop");
217                 abort();
218         }
219         ret = __say_hello_to_cloud(data);
220
221         if (!ret) {
222                 ttd_cloud_conn_state_set(TTD_CLOUD_CONN_STATE_CONNECTED);
223                 g_idle_add(__daemon_job_handler, d_data);
224         } else /* endless retry? */
225                 g_timeout_add_seconds(3, __cloud_try_connect, data);
226
227         return FALSE;
228 }
229
230 static gboolean __do_device_register(gpointer data)
231 {
232         int registered = 0;
233         ttd_data *d_data = data;
234
235         if (!d_data) {
236                 /* Must not reach here */
237                 _E("data is NULL, daemon will be stop");
238                 abort();
239         }
240
241         /*      TODO
242                 - check device ID
243                 - check token or auth key
244         */
245
246         if (!registered) {
247                 /* TODO : start easy setup procedure here !! */
248         }
249
250         ttd_cloud_conn_state_set(TTD_CLOUD_CONN_STATE_CONNECTABLE);
251         __cloud_try_connect(data); /* ???? */
252
253         return FALSE;
254 }
255
256 static void __time_changed(keynode_t *node, void *data)
257 {
258         ttd_data *d_data = data;
259         long long current_time;
260         _D("System time is changed");
261
262         current_time = common_get_epoch_time();
263
264         if (current_time > EPOCH_TIME_REF && !d_data->is_time_set) {
265                 /* Do something need correct time after here */
266                 _D("We assume that system time is correct, because current[%lld] is bigger than 2018-05-17", current_time);
267                 d_data->is_time_set = true;
268                 g_idle_add(__do_device_register, d_data);
269         }
270 }
271
272 int main(int argc, char* argv[])
273 {
274         ttd_data *d_data = NULL;
275         long long start = 0;
276
277         start = _get_monotonic_time();
278
279         d_data = calloc(1, sizeof(ttd_data));
280
281         log_type_set(LOG_TYPE_DLOG);
282
283         d_data->mainloop = g_main_loop_new(NULL, FALSE);
284
285         /* TODO : prepare to start daemon */
286         g_unix_signal_add(SIGINT, _handle_sigint, d_data);
287         g_unix_signal_add(SIGTERM, _handle_sigterm, d_data);
288
289         vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, __time_changed, d_data);
290
291         ttd_queue_init();
292         ttd_conn_mgr_init();
293         ttd_http_init();
294         ttd_cloud_conn_state_set(TTD_CLOUD_CONN_STATE_DISCONNECTED);
295         ttd_worker_interface_init(&(d_data->worker_itf_h));
296
297         d_data->thread_pool =
298                 g_thread_pool_new(__main_thread_pool_func, d_data, -1, FALSE, NULL);
299         g_thread_pool_set_sort_function(
300                 d_data->thread_pool, ttd_task_sort_func, NULL);
301
302         _D("[delay] start-to-ready - %.3lf(ms)",
303                 (double)(_get_monotonic_time() - start)/1000);
304         g_main_loop_run(d_data->mainloop);
305
306         g_main_loop_unref(d_data->mainloop);
307         g_thread_pool_free(d_data->thread_pool, FALSE, TRUE);
308
309         ttd_worker_interface_fini(d_data->worker_itf_h);
310
311         free(d_data);
312         d_data = NULL;
313
314         ttd_queue_fini();
315         ttd_conn_mgr_fini();
316         ttd_http_fini();
317
318         log_file_close();
319
320         return 0;
321 }