Dongle feature enable in ivi profile
[platform/core/telephony/telephony-daemon.git] / src / main.c
1 /*
2  * telephony-daemon
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Contact: Ja-young Gu <jygu@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #ifdef TIZEN_DEBUG_ENABLE
22 #include "monitor.h"
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <dlfcn.h>
30 #include <getopt.h>
31 #include <sys/stat.h>
32 #include <sys/sysinfo.h>
33
34 #include <glib.h>
35 #include <dlog.h>
36 #include <vconf.h>
37
38 #include <tcore.h>
39 #include <plugin.h>
40 #include <server.h>
41
42 #ifndef DAEMON_VERSION
43 #define DAEMON_VERSION "unknown"
44 #endif
45
46 #ifndef DEFAULT_PLUGINS_PATH
47 #define DEFAULT_PLUGINS_PATH "/usr/lib/telephony/plugins/"
48 #endif
49
50 #define NOTUSED(var) (var = var)
51 #define BUFFER_SIZE 1024
52
53 static Server *_server = NULL;
54
55 static void __usage_info(const char *exec)
56 {
57         info("Usage: %s [OPTION]... [PLUGIN_PATH]\n", exec);
58         info("\n");
59         info("  -T, --testload\t run with plugin load test mode and exit\n");
60         info("  -h, --help\t\t display this help and exit\n");
61         info("\n");
62 }
63
64 void tcore_log(enum tcore_log_type type, enum tcore_log_priority priority, const char *tag, const char *fmt, ...)
65 {
66         va_list ap;
67         char buf[BUFFER_SIZE];
68         int log_id = LOG_ID_RADIO;
69 #ifdef TIZEN_PROFILE_TV
70         log_id = LOG_ID_MAIN;
71 #endif
72
73         switch (type) {
74         case TCORE_LOG_TYPE_RADIO: {
75                 if (priority >= TCORE_LOG_INFO) {
76                         va_start(ap, fmt);
77                         vsnprintf(buf, BUFFER_SIZE-1, fmt, ap);
78                         va_end(ap);
79                         __dlog_print(log_id, priority, tag, buf);
80                 } else {
81                 #ifdef TIZEN_DEBUG_ENABLE
82                         va_start(ap, fmt);
83                         vsnprintf(buf, BUFFER_SIZE-1, fmt, ap);
84                         va_end(ap);
85                         __dlog_print(log_id, priority, tag, buf);
86                 #endif
87                 }
88         } break;
89
90         case TCORE_LOG_TYPE_TIME_CHECK: {
91         #ifdef TIZEN_DEBUG_ENABLE /* User Mode should not log performance data */
92                 float a = 0.00, b = 0.00;
93                 int next = 0;
94                 FILE *fp = fopen("/proc/uptime", "r");
95                 if (NULL == fp) {
96                         err("fopen() failed");
97                         return;
98                 }
99                 if (fscanf(fp, "%f %f", &a, &b) != 1)
100                         next = snprintf(buf, BUFFER_SIZE, "[UPTIME] [Not Set] ");
101                 else
102                         next = snprintf(buf, BUFFER_SIZE, "[UPTIME] %f ", a);
103                 fclose(fp);
104                 if (next < 0)
105                         return;
106
107                 va_start(ap, fmt);
108                 vsnprintf(buf + next, (BUFFER_SIZE-1) - next, fmt, ap);
109                 va_end(ap);
110                 __dlog_print(log_id, priority, tag, buf);
111         #endif
112         } break;
113
114         default:
115         break;
116         }
117 }
118
119 static void glib_log(const gchar *log_domain, GLogLevelFlags log_level,
120                 const gchar *msg, gpointer user_data)
121 {
122         NOTUSED(log_domain);
123         NOTUSED(log_level);
124         NOTUSED(user_data);
125
126         __dlog_print (LOG_ID_RADIO, DLOG_ERROR, "GLIB", msg);
127 }
128
129 #ifdef TIZEN_DEBUG_ENABLE
130 static void telephony_signal_handler(int signo)
131 {
132         if (!_server)
133                 return;
134
135         switch (signo) {
136         case SIGUSR1: {
137                 monitor_server_state(_server);
138         } break;
139
140         case SIGTERM: {
141                 tcore_server_exit(_server);
142         } break;
143
144 #if defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
145         case SIGHUP: {
146                 warn("*~*~*~* Ignore Signal: [SIGHUP] *~*~*~*");
147         } break;
148 #endif
149
150         default: {
151                 warn("*~*~*~* Unhandled Signal: [%d] *~*~*~*", signo);
152         } break;
153         } /* end switch */
154
155         return;
156 }
157 #elif defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
158 static void telephony_signal_handler(int signo)
159 {
160         if (!_server)
161                 return;
162
163         switch (signo) {
164         case SIGHUP: {
165                 warn("*~*~*~* Ignore Signal: [SIGHUP] *~*~*~*");
166         } break;
167
168         default: {
169                 warn("*~*~*~* Unhandled Signal: [%d] *~*~*~*", signo);
170         } break;
171         } /* end switch */
172
173         return;
174 }
175 #endif
176
177 static void __log_uptime()
178 {
179         float a = 0.00, b = 0.00;
180         FILE *fp = fopen("/proc/uptime", "r");
181
182         if (NULL == fp) {
183                 err("fopen() failed");
184                 return;
185         }
186         info("scanned %d items", fscanf(fp, "%f %f", &a, &b));
187         info("proc uptime = %f idletime = %f\n", a, b);
188         fclose(fp);
189 }
190
191 static gboolean __init_plugin(TcorePlugin *plugin)
192 {
193         const struct tcore_plugin_define_desc *desc = tcore_plugin_get_description(plugin);
194
195         if (!desc || !desc->init)
196                 return FALSE;
197
198         if (!desc->init(plugin)) { /* TODO: Remove plugin from server */
199                 char *plugin_name = tcore_plugin_get_filename(plugin);
200                 if (NULL != plugin_name) {
201                         err("plugin(%s) init failed.", plugin_name);
202                         free(plugin_name);
203                 }
204                 return FALSE;
205         }
206
207         return TRUE;
208 }
209
210 static gboolean init_plugins(Server *s)
211 {
212         GSList *list = tcore_server_ref_plugins(s);
213
214         while (list != NULL) {
215                 if (G_UNLIKELY(FALSE == __init_plugin(list->data))) {
216                         list = g_slist_next(list);
217                         continue;
218                 }
219                 list = g_slist_next(list);
220         }
221
222         return TRUE;
223 }
224
225 static void *__load_plugin(const gchar *filename, struct tcore_plugin_define_desc **desc_out)
226 {
227         void *handle = NULL;
228         struct tcore_plugin_define_desc *desc = NULL;
229         struct stat stat_buf;
230         char file_date[27];
231
232         handle = dlopen(filename, RTLD_LAZY);
233         if (NULL == handle) {
234                 err("dlopen() failed:[%s]", filename);
235                 return NULL;
236         }
237
238         desc = dlsym(handle, "plugin_define_desc");
239         if (NULL == desc) {
240                 err("dlsym() failed:[%s]", "plugin_define_desc");
241                 dlclose(handle);
242                 return NULL;
243         }
244
245         dbg("%s plugin", desc->name);
246         dbg(" - path = %s", filename);
247         dbg(" - version = %d", desc->version);
248         dbg(" - priority = %d", desc->priority);
249
250         memset(&stat_buf, 0x00, sizeof(stat_buf));
251         memset(&file_date, '\0', sizeof(file_date));
252
253         if (0 == stat(filename, &stat_buf)) {
254                 if (NULL != ctime_r(&stat_buf.st_mtime, file_date)) {
255                         if (1 < strlen(file_date))
256                                 file_date[strlen(file_date)-1] = '\0';
257                         dbg(" - date = %s", file_date);
258                 }
259         }
260
261         if (G_LIKELY(desc->load)) {
262                 if (G_UNLIKELY(FALSE == desc->load())) {
263                         warn("false return from load(). skip this plugin");
264                         dlclose(handle);
265                         return NULL;
266                 }
267         }
268
269         if (NULL != desc_out)
270                 *desc_out = desc;
271
272         return handle;
273 }
274
275 static gboolean load_plugins(Server *s, const char *path, gboolean flag_test_load)
276 {
277         const gchar *file = NULL;
278         gchar *filename = NULL;
279         GDir *dir = NULL;
280         void *handle = NULL;
281         struct tcore_plugin_define_desc *desc = NULL;
282
283         if (!path || !s)
284                 return FALSE;
285
286         dir = g_dir_open(path, 0, NULL);
287         if (!dir)
288                 return FALSE;
289
290         while ((file = g_dir_read_name(dir)) != NULL) {
291                 if (g_str_has_prefix(file, "lib") == TRUE
292                         || g_str_has_suffix(file, ".so") == FALSE)
293                         continue;
294
295                 filename = g_build_filename(path, file, NULL);
296
297                 /* Load a plugin */
298                 handle = __load_plugin(filename, &desc);
299                 if (NULL == handle) {
300                         g_free(filename);
301                         continue;
302                 }
303
304                 /* Don't add to server if flag_test_load */
305                 if (flag_test_load) {
306                         dbg("success to load '%s'", filename);
307                         dlclose(handle);
308                         g_free(filename);
309                         continue;
310                 }
311
312                 tcore_server_add_plugin(s, tcore_plugin_new(s, desc, filename, handle));
313
314                 dbg("%s added", desc->name);
315                 g_free(filename);
316         }
317         g_dir_close(dir);
318
319         return TRUE;
320 }
321
322 int main(int argc, char *argv[])
323 {
324 #if defined(TIZEN_DEBUG_ENABLE) || defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
325         struct sigaction sigact;
326 #endif
327         Server *s = NULL;
328         gboolean flag_test_load = FALSE;
329         int opt = 0, opt_index = 0, ret_code = EXIT_SUCCESS;
330         int daemon_load_count = 0;
331         struct option options[] = {
332                 { "help", 0, 0, 0 },
333                 { "testload", 0, &flag_test_load, 1 },
334                 { 0, 0, 0, 0 }
335         };
336         const char *plugin_path = DEFAULT_PLUGINS_PATH;
337         char *tcore_ver = NULL;
338         struct sysinfo sys_info;
339
340         TIME_CHECK("Starting Telephony");
341
342         /* System Uptime */
343         if (0 == sysinfo(&sys_info))
344                 info("uptime: %ld secs", sys_info.uptime);
345         __log_uptime();
346
347         /* Version Info */
348         tcore_ver = tcore_util_get_version();
349         info("daemon version: %s", DAEMON_VERSION);
350         info("libtcore version: %s", tcore_ver);
351         free(tcore_ver);
352         info("glib version: %u.%u.%u", glib_major_version, glib_minor_version, glib_micro_version);
353
354         /* Telephony reset handling*/
355         vconf_get_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT, &daemon_load_count);
356         daemon_load_count++;
357         vconf_set_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT, daemon_load_count);
358         dbg("daemon load count = [%d]", daemon_load_count);
359
360 #ifdef TIZEN_DEBUG_ENABLE
361         /* Signal Registration */
362         sigact.sa_handler = telephony_signal_handler;
363         sigemptyset(&sigact.sa_mask);
364         sigact.sa_flags = 0;
365         if (sigaction(SIGTERM, &sigact, NULL) < 0)
366                 warn("sigaction(SIGTERM) failed.");
367         if (sigaction(SIGUSR1, &sigact, NULL) < 0)
368                 warn("sigaction(SIGUSR1) failed.");
369 #if defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
370         /* SIGHUP should be ignored because cellular dongle ejection makes this signal */
371         if (sigaction(SIGHUP, &sigact, NULL) < 0)
372                 warn("sigaction(SIGHUP) failed.");
373 #endif
374 #elif defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
375         /* Signal Registration */
376         sigact.sa_handler = telephony_signal_handler;
377         sigemptyset(&sigact.sa_mask);
378         sigact.sa_flags = 0;
379         /* SIGHUP should be ignored because cellular dongle ejection makes this signal */
380         if (sigaction(SIGHUP, &sigact, NULL) < 0)
381                 warn("sigaction(SIGHUP) failed.");
382 #endif
383
384         if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
385                 err("Child process won't be auto reaped: [%d]", errno);
386
387         /* Commandline option parser TODO: Replace with GOptionContext */
388         while (TRUE) {
389                 opt = getopt_long(argc, argv, "hT", options, &opt_index);
390
391                 if (-1 == opt)
392                         break;
393
394                 switch (opt) {
395                 case 0: {
396                         switch (opt_index) {
397                         case 0: {
398                                 __usage_info(argv[0]);
399                                 return 0;
400                         } break;
401                         default: {
402                                 warn("unhandled opt_index.");
403                         } break;
404                         } /* end switch */
405                 } break;
406
407                 case 'h': {
408                         __usage_info(argv[0]);
409                         return 0;
410                 } break;
411
412                 case 'T': {
413                         flag_test_load = TRUE;
414                 } break;
415                 default: {
416                         warn("unhandled opt case.");
417                 } break;
418                 } /* end switch */
419         }
420
421         if (optind < argc)
422                 plugin_path = argv[optind];
423
424         info("plugin_path: [%s]", plugin_path);
425
426 #if !GLIB_CHECK_VERSION(2, 35, 0)
427         g_type_init();
428 #endif
429 #if !GLIB_CHECK_VERSION(2, 31, 0)
430         g_thread_init(NULL);
431 #endif
432
433         s = tcore_server_new();
434         if (G_UNLIKELY(NULL == s)) {
435                 err("server_new failed.");
436                 ret_code = EXIT_FAILURE;
437                 goto END;
438         }
439         _server = s;
440
441         g_log_set_default_handler(glib_log, s);
442
443         /* Load Plugins */
444         if (G_UNLIKELY(FALSE == load_plugins(s, (const char *)plugin_path, flag_test_load))) {
445                 err("load_plugins failed.");
446                 ret_code = EXIT_FAILURE;
447                 goto END;
448         }
449
450         TIME_CHECK("Loading Plugins Complete");
451
452         if (flag_test_load) {
453                 ret_code = EXIT_SUCCESS;
454                 goto END;
455         }
456
457         /* Initialize Plugins */
458         if (G_UNLIKELY(FALSE == init_plugins(s))) {
459                 err("init_plugins failed.");
460                 ret_code = EXIT_FAILURE;
461                 goto END;
462         }
463
464         info("server mainloop start");
465         TIME_CHECK("Initializing Plugins Complete. Starting Daemon");
466
467         if (G_UNLIKELY(TCORE_RETURN_SUCCESS != tcore_server_run(s))) {
468                 err("server_run failed.");
469                 ret_code = EXIT_FAILURE;
470         }
471
472 END:
473         tcore_server_free(s); _server = NULL;
474         return ret_code;
475 }