ce8cfd764ed9ba2ebbeead7f69fddd84eebd7d77
[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
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 /* Internal vconf to maintain telephony load info (Number of times telephony daemon is loaded) */
51 #define VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT "memory/private/telephony/daemon_load_count"
52
53 #define NOTUSED(var) (var = var)
54
55 static Server *_server = NULL;
56
57 static void __usage_info(const char *exec)
58 {
59         printf("Usage: %s [OPTION]... [PLUGIN_PATH]\n", exec);
60         printf("\n");
61         printf("  -T, --testload\t run with plugin load test mode and exit\n");
62         printf("  -h, --help\t\t display this help and exit\n");
63         printf("\n");
64 }
65
66 void tcore_log(enum tcore_log_type type, enum tcore_log_priority priority, const char *tag, const char *fmt, ...)
67 {
68         va_list ap;
69         char buf[1024];
70
71         switch (type) {
72         case TCORE_LOG_TYPE_RADIO: {
73                 if (priority >= TCORE_LOG_INFO) {
74                         va_start(ap, fmt);
75                         vsnprintf(buf, 1023, fmt, ap);
76                         va_end(ap);
77                         __dlog_print(LOG_ID_RADIO, priority, tag, buf);
78                 } else {
79                 #ifdef TIZEN_DEBUG_ENABLE
80                         va_start(ap, fmt);
81                         vsnprintf(buf, 1023, fmt, ap);
82                         va_end(ap);
83                         __dlog_print(LOG_ID_RADIO, priority, tag, buf);
84                 #endif
85                 }
86         } break;
87
88         case TCORE_LOG_TYPE_TIME_CHECK: {
89         #ifdef TIZEN_DEBUG_ENABLE /* User Mode should not log performance data */
90                 float a = 0.00, b = 0.00;
91                 int next = 0;
92                 FILE *fp = fopen("/proc/uptime", "r");
93                 g_return_if_fail(NULL != fp);
94
95                 if(fscanf(fp, "%f %f", &a, &b)){};
96                 fclose(fp);
97                 next = sprintf(buf, "[UPTIME] %f ", a);
98                 if (next < 0)
99                         return;
100
101                 va_start(ap, fmt);
102                 vsnprintf(buf + next, 1023 - next, fmt, ap);
103                 va_end(ap);
104                 __dlog_print(LOG_ID_RADIO, priority, tag, buf);
105         #endif
106         } break;
107
108         default:
109         break;
110         }
111 }
112
113 static void glib_log(const gchar *log_domain, GLogLevelFlags log_level,
114                 const gchar *msg, gpointer user_data)
115 {
116         NOTUSED(log_domain);
117         NOTUSED(log_level);
118         NOTUSED(user_data);
119
120         __dlog_print (LOG_ID_RADIO, DLOG_ERROR, "GLIB", msg);
121 }
122
123 #ifdef TIZEN_DEBUG_ENABLE
124 static void telephony_signal_handler(int signo)
125 {
126         if (!_server)
127                 return;
128
129         switch (signo) {
130         case SIGUSR1: {
131                 monitor_server_state(_server);
132         } break;
133
134         case SIGTERM: {
135                 tcore_server_exit(_server);
136         } break;
137
138         default: {
139                 warn("*~*~*~* Unhandled Signal: [%d] *~*~*~*", signo);
140         } break;
141         } /* end switch */
142
143         return;
144 }
145 #endif
146
147 static void __log_uptime()
148 {
149         float a = 0.00, b = 0.00;
150         FILE *fp = fopen("/proc/uptime", "r");
151         g_return_if_fail(NULL != fp);
152         info("scanned %d items", fscanf(fp, "%f %f", &a, &b));
153         info("proc uptime = %f idletime = %f\n", a, b);
154         fclose(fp);
155 }
156
157 static gboolean __init_plugin(TcorePlugin *plugin)
158 {
159         const struct tcore_plugin_define_desc *desc = tcore_plugin_get_description(plugin);
160
161         if (!desc || !desc->init)
162                 return FALSE;
163
164         if (!desc->init(plugin)) { /* TODO: Remove plugin from server */
165                 char *plugin_name = tcore_plugin_get_filename(plugin);
166                 if (NULL != plugin_name) {
167                         err("plugin(%s) init failed.", plugin_name);
168                         free(plugin_name);
169                 }
170                 return FALSE;
171         }
172
173         return TRUE;
174 }
175
176 static gboolean init_plugins(Server *s)
177 {
178         GSList *list = tcore_server_ref_plugins(s);
179
180         while (list != NULL) {
181                 if (G_UNLIKELY(FALSE == __init_plugin(list->data))) {
182                         list = g_slist_next(list);
183                         continue;
184                 }
185                 list = g_slist_next(list);
186         }
187
188         return TRUE;
189 }
190
191 static void *__load_plugin(const gchar *filename, struct tcore_plugin_define_desc **desc_out)
192 {
193         void *handle = NULL;
194         struct tcore_plugin_define_desc *desc = NULL;
195         struct stat stat_buf;
196         char file_date[27];
197
198         handle = dlopen(filename, RTLD_LAZY);
199         if (G_UNLIKELY(NULL == handle)) {
200                 err("fail to load '%s': %s", filename, dlerror());
201                 return NULL;
202         }
203
204         desc = dlsym(handle, "plugin_define_desc");
205         if (G_UNLIKELY(NULL == desc)) {
206                 err("fail to load symbol: %s", dlerror());
207                 dlclose(handle);
208                 return NULL;
209         }
210
211         dbg("%s plugin", desc->name);
212         dbg(" - path = %s", filename);
213         dbg(" - version = %d", desc->version);
214         dbg(" - priority = %d", desc->priority);
215
216         memset(&stat_buf, 0x00, sizeof(stat_buf));
217         memset(&file_date, '\0', sizeof(file_date));
218
219         if (0 == stat(filename, &stat_buf)) {
220                 if (NULL != ctime_r(&stat_buf.st_mtime, file_date)) {
221                         if (1 < strlen(file_date))
222                                 file_date[strlen(file_date)-1] = '\0';
223                         dbg(" - date = %s", file_date);
224                 }
225         }
226
227         if (G_LIKELY(desc->load)) {
228                 if (G_UNLIKELY(FALSE == desc->load())) {
229                         warn("false return from load(). skip this plugin");
230                         dlclose(handle);
231                         return NULL;
232                 }
233         }
234
235         if (NULL != desc_out)
236                 *desc_out = desc;
237
238         return handle;
239 }
240
241 static gboolean load_plugins(Server *s, const char *path, gboolean flag_test_load)
242 {
243         const gchar *file = NULL;
244         gchar *filename = NULL;
245         GDir *dir = NULL;
246         void *handle = NULL;
247         struct tcore_plugin_define_desc *desc = NULL;
248
249         if (!path || !s)
250                 return FALSE;
251
252         dir = g_dir_open(path, 0, NULL);
253         if (!dir)
254                 return FALSE;
255
256         while ((file = g_dir_read_name(dir)) != NULL) {
257                 if (g_str_has_prefix(file, "lib") == TRUE
258                         || g_str_has_suffix(file, ".so") == FALSE)
259                         continue;
260
261                 filename = g_build_filename(path, file, NULL);
262
263                 /* Load a plugin */
264                 if (G_UNLIKELY((handle = __load_plugin(filename, &desc)) == NULL)) {
265                         g_free(filename);
266                         continue;
267                 }
268
269                 /* Don't add to server if flag_test_load */
270                 if (flag_test_load) {
271                         dbg("success to load '%s'", filename);
272                         dlclose(handle);
273                         g_free(filename);
274                         continue;
275                 }
276
277                 tcore_server_add_plugin(s, tcore_plugin_new(s, desc, filename, handle));
278
279                 dbg("%s added", desc->name);
280                 g_free(filename);
281         }
282         g_dir_close(dir);
283
284         return TRUE;
285 }
286
287 int main(int argc, char *argv[])
288 {
289 #ifdef TIZEN_DEBUG_ENABLE
290         struct sigaction sigact;
291 #endif
292         Server *s = NULL;
293         gboolean flag_test_load = FALSE;
294         int opt = 0, opt_index = 0, ret_code = EXIT_SUCCESS;
295         int daemon_load_count = 0;
296         struct option options[] = {
297                 { "help", 0, 0, 0 },
298                 { "testload", 0, &flag_test_load, 1 },
299                 { 0, 0, 0, 0 }
300         };
301         const char *plugin_path = DEFAULT_PLUGINS_PATH;
302         char *tcore_ver = NULL;
303         struct sysinfo sys_info;
304
305         TIME_CHECK("Starting Telephony");
306
307         /* System Uptime */
308         if (0 == sysinfo(&sys_info))
309                 info("uptime: %ld secs", sys_info.uptime);
310         __log_uptime();
311
312         /* Version Info */
313         tcore_ver = tcore_util_get_version();
314         info("daemon version: %s", DAEMON_VERSION);
315         info("libtcore version: %s", tcore_ver);
316         free(tcore_ver);
317         info("glib version: %u.%u.%u", glib_major_version, glib_minor_version, glib_micro_version);
318
319         /* Telephony reset handling*/
320         vconf_get_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT,&daemon_load_count);
321         daemon_load_count++;
322         vconf_set_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT,daemon_load_count);
323         dbg("daemon load count = [%d]", daemon_load_count);
324
325 #ifdef TIZEN_DEBUG_ENABLE
326         /* Signal Registration */
327         sigact.sa_handler = telephony_signal_handler;
328         sigemptyset(&sigact.sa_mask);
329         sigact.sa_flags = 0;
330         if (sigaction(SIGTERM, &sigact, NULL) < 0)
331                 warn("sigaction(SIGTERM) failed.");
332         if (sigaction(SIGUSR1, &sigact, NULL) < 0)
333                 warn("sigaction(SIGUSR1) failed.");
334 #endif
335
336         /* Commandline option parser TODO: Replace with GOptionContext */
337         while (TRUE) {
338                 opt = getopt_long(argc, argv, "hT", options, &opt_index);
339
340                 if (-1 == opt)
341                         break;
342
343                 switch (opt) {
344                 case 0: {
345                         switch (opt_index) {
346                         case 0: {
347                                 __usage_info(argv[0]);
348                                 return 0;
349                         } break;
350                         default: {
351                                 warn("unhandled opt_index.");
352                         } break;
353                         } /* end switch */
354                 } break;
355
356                 case 'h': {
357                         __usage_info(argv[0]);
358                         return 0;
359                 } break;
360
361                 case 'T': {
362                         flag_test_load = TRUE;
363                 } break;
364                 default: {
365                         warn("unhandled opt case.");
366                 } break;
367                 } /* end switch */
368         }
369
370         if (optind < argc)
371                 plugin_path = argv[optind];
372
373         info("plugin_path: [%s]", plugin_path);
374
375 #if !GLIB_CHECK_VERSION(2, 35, 0)
376         g_type_init();
377 #endif
378 #if !GLIB_CHECK_VERSION(2, 31, 0)
379         g_thread_init(NULL);
380 #endif
381
382         s = tcore_server_new();
383         if (G_UNLIKELY(NULL == s)) {
384                 err("server_new failed.");
385                 ret_code = EXIT_FAILURE;
386                 goto END;
387         }
388         _server = s;
389
390         g_log_set_default_handler(glib_log, s);
391
392         /* Load Plugins */
393         if (G_UNLIKELY(FALSE == load_plugins(s, (const char *)plugin_path, flag_test_load))) {
394                 err("load_plugins failed.");
395                 ret_code = EXIT_FAILURE;
396                 goto END;
397         }
398
399         TIME_CHECK("Loading Plugins Complete");
400
401         if (flag_test_load) {
402                 ret_code = EXIT_SUCCESS;
403                 goto END;
404         }
405
406         /* Initialize Plugins */
407         if (G_UNLIKELY(FALSE == init_plugins(s))) {
408                 err("init_plugins failed.");
409                 ret_code = EXIT_FAILURE;
410                 goto END;
411         }
412
413         info("server mainloop start");
414         TIME_CHECK("Initializing Plugins Complete. Starting Daemon");
415
416         if (G_UNLIKELY(TCORE_RETURN_SUCCESS != tcore_server_run(s))) {
417                 err("server_run failed.");
418                 ret_code = EXIT_FAILURE;
419         }
420
421 END:
422         tcore_server_free(s); _server = NULL;
423         return ret_code;
424 }