197a8defec49b1d769f7a3b40db0ddd6db15810e
[platform/core/multimedia/mmsvc-core.git] / client / src / muse_client.c
1 /*
2  * muse-client
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@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
22 #include "muse_client.h"
23 #include "muse_core_internal.h"
24
25 #ifdef LOG_TAG
26 #undef LOG_TAG
27 #endif
28 #define LOG_TAG "MUSED_CLIENT"
29
30 static GMutex mc_mutex;
31 static GHashTable *mc_table;
32 static int mc_table_id;
33
34 static const char *UDS_files[MUSE_CHANNEL_MAX] = {MUSE_MSG_SOCK, MUSE_DATA_SOCK};
35
36 #ifdef MUSE_USE_CLIENT_SIGHANDLER
37 /* signal handler */
38 static struct sigaction mc_int_old_action;
39 static struct sigaction mc_abrt_old_action;
40 static struct sigaction mc_segv_old_action;
41 static struct sigaction mc_term_old_action;
42 static struct sigaction mc_sys_old_action;
43
44 static gboolean _mc_table_remove_func(gpointer key, gpointer value, gpointer user_data);
45 static void _mc_sigaction(int signo, siginfo_t *siginfo, void *context);
46 static void _mc_constructor(void) __attribute__((constructor));
47 #endif
48
49 static int _mc_new(muse_channel_e channel);
50 static void _mc_table_new(void);
51 static gpointer _mc_get_fd_ptr(int sock_fd);
52
53 static int _muse_client_new(muse_channel_e channel);
54
55 #ifdef MUSE_USE_CLIENT_SIGHANDLER
56 static gboolean _mc_table_remove_func(gpointer key, gpointer value, gpointer user_data)
57 {
58         int sock_fd = GPOINTER_TO_INT(key);
59
60         LOGW("close muse connection fd %d", sock_fd);
61
62         muse_core_connection_close(sock_fd);
63
64         return TRUE;
65 }
66
67 static void _mc_sigaction(int signo, siginfo_t *siginfo, void *context)
68 {
69         struct sigaction *old_action = NULL;
70         pid_t my_pid = getpid();
71
72         LOGE("Enter - signo [%d], pid [%d]", signo, my_pid);
73
74         /* close all opened fds */
75         g_mutex_lock(&mc_mutex);
76
77         if (mc_table)
78                 g_hash_table_foreach_remove(mc_table, _mc_table_remove_func, NULL);
79
80         g_mutex_unlock(&mc_mutex);
81
82         /* call old signal handler */
83         switch (signo) {
84         case SIGINT:
85                 old_action = &mc_int_old_action;
86                 break;
87         case SIGABRT:
88                 old_action = &mc_abrt_old_action;
89                 break;
90         case SIGSEGV:
91                 old_action = &mc_segv_old_action;
92                 break;
93         case SIGTERM:
94                 old_action = &mc_term_old_action;
95                 break;
96         case SIGSYS:
97                 old_action = &mc_sys_old_action;
98                 break;
99         default:
100                 LOGE("unhandled signal %d", signo);
101                 return;
102         }
103
104         if (old_action->sa_sigaction)
105                 old_action->sa_sigaction(signo, siginfo, context);
106         else
107                 sigaction(signo, old_action, NULL);
108
109         raise(signo);
110
111         LOGE("Leave");
112
113         return;
114 }
115
116 static void _mc_constructor(void)
117 {
118         struct sigaction mc_action;
119         mc_action.sa_sigaction = _mc_sigaction;
120         mc_action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
121
122         LOGI("Enter");
123
124         sigemptyset(&mc_action.sa_mask);
125
126         sigaction(SIGINT, &mc_action, &mc_int_old_action);
127         sigaction(SIGABRT, &mc_action, &mc_abrt_old_action);
128         sigaction(SIGSEGV, &mc_action, &mc_segv_old_action);
129         sigaction(SIGTERM, &mc_action, &mc_term_old_action);
130         sigaction(SIGSYS, &mc_action, &mc_sys_old_action);
131
132         LOGI("Leave");
133
134         return;
135 }
136 #endif
137
138 static int _mc_new(muse_channel_e channel)
139 {
140         struct sockaddr_un address;
141         int len, ret = MUSE_ERR;
142         int sock_fd;
143         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
144
145         LOGI("Enter");
146         muse_return_val_if_fail(channel < MUSE_CHANNEL_MAX, MM_ERROR_INVALID_ARGUMENT);
147
148         /* create socket */
149         sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
150         if (!muse_core_fd_is_valid(sock_fd)) {
151                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
152                 LOGE("[socket failure] %d socket %s", errno, err_msg);
153                 muse_core_dump_fd_state(sock_fd);
154                 return ret;
155         }
156         LOGI("sockfd: %d", sock_fd);
157
158         if (fcntl(sock_fd, F_SETFD, FD_CLOEXEC) < 0) {
159                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
160                 LOGE("unable to set on ctrl socket fd %d: %s", sock_fd, err_msg);
161                 close(sock_fd);
162                 return ret;
163         }
164         LOGD("fcntl");
165
166         memset(&address, 0, sizeof(address));
167         address.sun_family = AF_UNIX;
168         strncpy(address.sun_path, UDS_files[channel], sizeof(address.sun_path) - 1);
169         len = sizeof(address);
170
171         if (muse_core_set_nonblocking(sock_fd, false) != MM_ERROR_NONE)
172                 LOGE("Error - fd (%d) set blocking", sock_fd);
173
174         if ((ret = connect(sock_fd, (struct sockaddr *)&address, len)) < 0) {
175                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
176                 LOGE("[Critical Error : %d] connect failure : %s", errno, err_msg);
177                 close(sock_fd);
178                 return ret;
179         }
180
181         LOGI("[%d] #%d guaranteed that connect was returned", sock_fd, mc_table_id);
182         g_mutex_lock(&mc_mutex);
183         g_hash_table_insert(mc_table, GINT_TO_POINTER(sock_fd), GINT_TO_POINTER(mc_table_id++));
184         g_mutex_unlock(&mc_mutex);
185
186         LOGI("Leave");
187         return sock_fd;
188 }
189
190 static void _mc_table_new(void)
191 {
192         g_mutex_lock(&mc_mutex);
193
194         if (!mc_table) {
195                 mc_table_id = 1;
196                 mc_table = g_hash_table_new(g_direct_hash, g_direct_equal);
197                 LOGD("client table : %p", mc_table);
198         }
199
200         g_mutex_unlock(&mc_mutex);
201
202         muse_core_create_fd_table();
203 }
204
205 static gpointer _mc_get_fd_ptr(int sock_fd)
206 {
207         muse_return_val_if_fail(mc_table, NULL);
208
209         return g_hash_table_lookup(mc_table, GINT_TO_POINTER(sock_fd));
210 }
211
212 static int _muse_client_new(muse_channel_e channel)
213 {
214         if (!muse_server_is_ready()) {
215                 LOGE("muse server is not ready");
216                 return MM_ERROR_UNKNOWN;
217         }
218
219         if (channel == MUSE_CHANNEL_MSG)
220                 _mc_table_new();
221
222         return _mc_new(channel);
223 }
224
225 int muse_client_new(void)
226 {
227         return _muse_client_new(MUSE_CHANNEL_MSG);
228 }
229
230 int muse_client_new_data_ch(void)
231 {
232         return _muse_client_new(MUSE_CHANNEL_DATA);
233 }
234
235 int muse_client_close(int sock_fd)
236 {
237         int ret = MM_ERROR_NONE;
238
239         ret = muse_core_connection_close(sock_fd);
240         if (ret != MM_ERROR_NONE) {
241                 LOGE("close connection failed 0x%x", ret);
242                 return ret;
243         }
244
245         /* remove fd from table */
246         g_mutex_lock(&mc_mutex);
247
248         if (g_hash_table_remove(mc_table, GINT_TO_POINTER(sock_fd)))
249                 LOGD("success : remove fd %d from table", sock_fd);
250         else
251                 LOGW("fail : remove fd %d from table[%p]", sock_fd, mc_table);
252
253         g_mutex_unlock(&mc_mutex);
254
255 #ifdef MUSE_GCOV_TEST
256         muse_core_gcov_flush();
257 #endif
258
259         return MM_ERROR_NONE;
260 }
261
262 int muse_client_ipc_push_data(int sock_fd, const char *data, int size, uint64_t data_id)
263 {
264         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
265         muse_recv_data_head_t header;
266         int sended_len = 0;
267
268         muse_return_val_if_fail(data, MM_ERROR_INVALID_ARGUMENT);
269         muse_return_val_if_fail(muse_core_fd_is_valid(sock_fd), MM_ERROR_INVALID_ARGUMENT);
270
271         header.marker = MUSE_DATA_HEAD;
272         header.size = size;
273         header.id = data_id;
274
275         LOGD("[%d] header.marker : %x header.size : %d header.id : %"G_GUINT64_FORMAT"",
276                         sock_fd, header.marker, header.size, header.id);
277
278         if ((sended_len = send(sock_fd, &header, sizeof(muse_recv_data_head_t), 0)) < 0) {
279                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
280                 LOGE("[%d] fail to send msg (%s) %d", sock_fd, err_msg, errno);
281         }
282
283         if ((sended_len += send(sock_fd, data, size, 0)) < 0) {
284                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
285                 LOGE("[%d] fail to send msg (%s) %d", sock_fd, err_msg, errno);
286         }
287
288         return sended_len;
289 }
290
291 int muse_client_get_fd_id_value(int sock_fd)
292 {
293         gpointer sock_id_ptr = _mc_get_fd_ptr(sock_fd);
294
295         muse_return_val_if_fail(sock_id_ptr, MUSE_ERR);
296
297         return GPOINTER_TO_INT(sock_id_ptr);
298 }
299
300 bool muse_client_check_fd_id_value(int sock_fd, int sock_id)
301 {
302         gpointer sock_id_ptr = _mc_get_fd_ptr(sock_fd);
303
304         muse_return_val_if_fail(sock_id_ptr, false);
305
306         if (sock_id == GPOINTER_TO_INT(sock_id_ptr))
307                 return true;
308         else
309                 return false;
310 }
311
312 int muse_client_get_module_index(const char *module_name, int *module_index)
313 {
314         int idx = 0;
315         const char *str;
316         char *hosts;
317         char *host;
318         char *ptr = NULL;
319         bool module_name_matched = false;
320         dictionary *mc_dict;
321
322         muse_return_val_if_fail(module_name, MM_ERROR_INVALID_ARGUMENT);
323         muse_return_val_if_fail(module_index, MM_ERROR_INVALID_ARGUMENT);
324
325         LOGD("Enter");
326
327         mc_dict = iniparser_load(CONFFILE);
328         muse_return_val_if_fail(mc_dict, PARSE_ERROR);
329
330         str = (const char *)iniparser_getstring(mc_dict, MUSE_HOST, NULL);
331         if (!str) {
332                 LOGE("Error - iniparser_getstring (%s)", MUSE_HOST);
333                 iniparser_freedict(mc_dict);
334                 return PARSE_ERROR;
335         }
336
337         hosts = strdup(str);
338         if (!hosts) {
339                 LOGE("Error - hosts allocation");
340                 iniparser_freedict(mc_dict);
341                 return PARSE_ERROR;
342         }
343
344         host = strtok_r(hosts, INI_PARSER_COMMA, &ptr);
345
346         while (host) {
347                 g_strstrip(host);
348                 if (strncmp(module_name, host, strlen(module_name) + 1) == 0) {
349                         module_name_matched = true;
350                         *module_index = idx;
351                         break;
352                 }
353
354                 host = strtok_r(NULL, INI_PARSER_COMMA, &ptr);
355                 idx++;
356         }
357
358         free(hosts);
359
360         iniparser_freedict(mc_dict);
361
362         if (module_name_matched) {
363                 LOGD("Leave");
364                 return MM_ERROR_NONE;
365         } else {
366                 LOGE("You have to check if [%s] of [%s] is exact", module_name, CONFFILE);
367                 *module_index = MUSE_ERR;
368                 LOGD("Leave");
369                 return MM_ERROR_INVALID_ARGUMENT;
370         }
371 }