Fix thread safe issue
[platform/core/appfw/message-port.git] / src / message_port_common.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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 #define _GNU_SOURCE
18
19 #include <bundle.h>
20 #include <bundle_internal.h>
21 #include <pkgmgr-info.h>
22 #include <aul.h>
23
24 #include <sys/socket.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <glib.h>
28 #include <gio/gio.h>
29 #include <gio/gio.h>
30 #include <pthread.h>
31 #include <glib-unix.h>
32 #include <poll.h>
33
34 #include "message_port_log.h"
35 #include "message_port.h"
36 #include "message_port_common.h"
37
38 #define MAX_PACKAGE_STR_SIZE 512
39 #define MAX_RETRY_CNT 10
40
41 bool initialized_common;
42 GDBusConnection *gdbus_conn;
43 char *app_id;
44
45 static const int MAX_MESSAGE_SIZE = 16 * 1024;
46 static GRecMutex __rec_mutex;
47
48 #define MESSAGE_PORT_CTOR __attribute__((constructor))
49 #define MESSAGE_PORT_DTOR __attribute__((destructor))
50
51 int write_socket(int fd,
52                 const char *buffer,
53                 unsigned int nbytes,
54                 unsigned int *bytes_write,
55                 int *sequence)
56 {
57         unsigned int left = nbytes;
58         ssize_t nb;
59         int retry_cnt = 0;
60         int tmp_errno;
61
62         *sequence += 1;
63         *bytes_write = 0;
64
65         while (left && (retry_cnt < MAX_RETRY_CNT)) {
66                 nb = write(fd, buffer, left);
67                 if (nb == -1) {
68 /* LCOV_EXCL_START */
69                         if (errno == EINTR) {
70                                 LOGW("write_socket: EINTR continue ...");
71                                 retry_cnt++;
72                                 continue;
73                         }
74                         tmp_errno = errno;
75                         LOGE("write_socket: ...error fd %d: errno %d\n", fd, tmp_errno);
76
77                         if (tmp_errno == EWOULDBLOCK || tmp_errno == EAGAIN)
78                                 return MESSAGE_PORT_ERROR_RESOURCE_UNAVAILABLE;
79
80                         return MESSAGE_PORT_ERROR_IO_ERROR;
81                 }
82 /* LCOV_EXCL_STOP */
83                 left -= nb;
84                 buffer += nb;
85                 *bytes_write += nb;
86                 retry_cnt = 0;
87         }
88
89         if (left != 0) {
90                 _LOGE("error fd %d: retry_cnt %d", fd, retry_cnt);
91                 return MESSAGE_PORT_ERROR_IO_ERROR;
92         }
93
94         return MESSAGE_PORT_ERROR_NONE;
95 }
96
97 int write_string_to_socket(int fd,
98                 const char *buffer,
99                 int string_len,
100                 unsigned int *bytes_write,
101                 int *sequence)
102 {
103         int ret;
104
105         ret = write_socket(fd, (char *)&string_len, sizeof(string_len),
106                         bytes_write, sequence);
107         if (ret != MESSAGE_PORT_ERROR_NONE) {
108                 _LOGE("write string_len fail");
109                 return ret;
110         }
111
112         if (string_len > 0) {
113                 ret = write_socket(fd, buffer, string_len, bytes_write, sequence);
114                 if (ret != MESSAGE_PORT_ERROR_NONE) {
115                         _LOGE("wirte buffer fail");
116                         return ret;
117                 }
118         } else {
119                 *sequence += 1;
120         }
121
122         return MESSAGE_PORT_ERROR_NONE;
123 }
124
125 int read_socket(int fd,
126                 char *buffer,
127                 unsigned int nbytes,
128                 unsigned int *bytes_read)
129 {
130         unsigned int left = nbytes;
131         ssize_t nb;
132         int retry_cnt = 0;
133         struct timespec TRY_SLEEP_TIME = { 0, 5 * 1000 * 1000 };
134
135         *bytes_read = 0;
136         while (left && (retry_cnt < MAX_RETRY_CNT)) {
137                 nb = read(fd, buffer, left);
138                 if (nb == 0) {
139                         LOGE("read_socket: ...read EOF, socket closed %d: nb %zd\n", fd, nb);
140                         return MESSAGE_PORT_ERROR_IO_ERROR;
141                 } else if (nb == -1) {
142 /* LCOV_EXCL_START */
143                         /*  wrt(nodejs) could change socket to none-blocking socket :-( */
144                         if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
145                                 LOGW("read_socket: %d , sleep and retry ...", errno);
146                                 retry_cnt++;
147                                 nanosleep(&TRY_SLEEP_TIME, 0);
148                                 TRY_SLEEP_TIME.tv_nsec *= 2;
149                                 continue;
150                         }
151                         LOGE("read_socket: ...error fd %d: errno %d\n", fd, errno);
152                         return MESSAGE_PORT_ERROR_IO_ERROR;
153 /* LCOV_EXCL_STOP */
154                 }
155
156                 left -= nb;
157                 buffer += nb;
158                 *bytes_read += nb;
159                 retry_cnt = 0;
160         }
161
162         if (left != 0) {
163                 _LOGE("error fd %d: retry_cnt %d", fd, retry_cnt);
164                 return MESSAGE_PORT_ERROR_IO_ERROR;
165         }
166
167         return MESSAGE_PORT_ERROR_NONE;
168 }
169
170 int read_string_from_socket(int fd, char **buffer, int *string_len)
171 {
172         unsigned int nb;
173         if (read_socket(fd, (char *)string_len, sizeof(*string_len), &nb) != MESSAGE_PORT_ERROR_NONE) {
174                 LOGE("read socket fail");
175                 return MESSAGE_PORT_ERROR_IO_ERROR;
176         }
177         if (*string_len > 0 && *string_len < MAX_MESSAGE_SIZE) {
178                 *buffer = (char *)calloc(*string_len, sizeof(char));
179                 if (*buffer == NULL) {
180 /* LCOV_EXCL_START */
181                         LOGE("Out of memory.");
182                         return MESSAGE_PORT_ERROR_IO_ERROR;
183 /* LCOV_EXCL_STOP */
184                 }
185                 if (read_socket(fd, *buffer, *string_len, &nb) != MESSAGE_PORT_ERROR_NONE) {
186                         LOGE("read socket fail");
187                         return MESSAGE_PORT_ERROR_IO_ERROR;
188                 }
189         } else {
190                 LOGE("Invalid string len %d", *string_len);
191                 return MESSAGE_PORT_ERROR_IO_ERROR;
192         }
193         return MESSAGE_PORT_ERROR_NONE;
194 }
195
196 static int __dbus_init(void)
197 {
198         bool ret = true;
199         GError *error = NULL;
200
201         gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
202         if (gdbus_conn == NULL) {
203                 if (error != NULL) {
204                         _LOGE("Failed to get dbus [%s]", error->message);
205                         g_error_free(error);
206                 }
207                 ret = false;
208         }
209
210         return ret;
211 }
212
213 bool initialize_common(void)
214 {
215
216 #if !GLIB_CHECK_VERSION(2, 35, 0)
217         g_type_init();
218 #endif
219
220         int pid = getpid();
221         int ret = 0;
222         char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
223
224         ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
225         retvm_if(ret != AUL_R_OK, false, "Failed to get the application ID: %d", ret);
226
227         app_id = strdup(buffer);
228         retvm_if(!app_id, false, "Malloc failed");
229         _LOGI("init : %s", app_id);
230
231         if (!__dbus_init())
232                 return false;
233         initialized_common = true;
234
235         return true;
236 }
237
238 bool is_preloaded(const char *local_appid, const char *remote_appid)
239 {
240         _LOGD("IsPreloaded");
241
242         bool preload_local = false;
243         bool preload_remote = false;
244
245         pkgmgrinfo_appinfo_h handle = NULL;
246         int ret = pkgmgrinfo_appinfo_get_usr_appinfo(local_appid, getuid(), &handle);
247         if (ret != PMINFO_R_OK) {
248                 _LOGE("Failed to get the appinfo. %d", ret);
249                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
250                 return false;
251         }
252         ret = pkgmgrinfo_appinfo_is_preload(handle, &preload_local);
253         if (ret != PMINFO_R_OK) {
254                 _LOGE("Failed to check the preloaded application. %d", ret);
255                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
256                 return false;
257         }
258         pkgmgrinfo_appinfo_destroy_appinfo(handle);
259
260         ret = pkgmgrinfo_appinfo_get_usr_appinfo(remote_appid, getuid(), &handle);
261         if (ret != PMINFO_R_OK) {
262                 _LOGE("Failed to get the appinfo. %d", ret);
263                 return false;
264         }
265         ret = pkgmgrinfo_appinfo_is_preload(handle, &preload_remote);
266         if (ret != PMINFO_R_OK) {
267                 _LOGE("Failed to check the preloaded application. %d", ret);
268                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
269                 return false;
270         }
271
272         if (preload_local && preload_remote) {
273                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
274                 return true;
275         }
276         pkgmgrinfo_appinfo_destroy_appinfo(handle);
277         return false;
278 }
279
280 int check_certificate(const char *local_appid, const char *remote_appid)
281 {
282         _LOGD("CheckCertificate");
283
284         pkgmgrinfo_cert_compare_result_type_e res;
285         int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(local_appid, remote_appid, getuid(), &res);
286         if (ret < 0) {
287                 _LOGE(":CheckCertificate() Failed");
288                 return MESSAGE_PORT_ERROR_IO_ERROR;
289         }
290         if (res != PMINFO_CERT_COMPARE_MATCH) {
291                 _LOGE("CheckCertificate() Failed : MESSAGE_PORT_ERROR_CERTIFICATE_NOT_MATCH");
292                 return MESSAGE_PORT_ERROR_CERTIFICATE_NOT_MATCH;
293         }
294
295         return MESSAGE_PORT_ERROR_NONE;
296 }
297
298 char *get_encoded_name(const char *remote_app_id, const char *port_name, bool is_trusted)
299 {
300
301         size_t prefix_len = strlen(MESSAGEPORT_BUS_NAME_PREFIX);
302         int postfix_len = 1;
303         char *postfix = is_trusted ? "1" : "0";
304
305         gchar *encoded_bus_name;
306         size_t md5_digest_len = 0;
307         gssize bus_name_len = strlen(remote_app_id) + strlen(port_name) + 2;
308         char *bus_name = (char *)calloc(bus_name_len, sizeof(char));
309         if (bus_name == NULL) {
310 /* LCOV_EXCL_START */
311                 _LOGE("bus_name calloc failed");
312                 return NULL;
313 /* LCOV_EXCL_STOP */
314         }
315
316         snprintf(bus_name, bus_name_len, "%s_%s", remote_app_id, port_name);
317
318         encoded_bus_name = g_compute_checksum_for_string(G_CHECKSUM_MD5,
319                         bus_name, bus_name_len);
320
321         free(bus_name);
322
323         if (encoded_bus_name == NULL) {
324 /* LCOV_EXCL_START */
325                 _LOGE("g_compute_checksum_for_string failed");
326                 return NULL;
327 /* LCOV_EXCL_STOP */
328         }
329
330         // MD5_Final
331         md5_digest_len = prefix_len + postfix_len + strlen(encoded_bus_name) + 1;
332         char *md5_digest = (char *)calloc(md5_digest_len, sizeof(char));
333         if (md5_digest == NULL) {
334 /* LCOV_EXCL_START */
335                 g_free(encoded_bus_name);
336
337                 _LOGE("calloc failed!!");
338                 return NULL;
339 /* LCOV_EXCL_STOP */
340         }
341
342         snprintf(md5_digest, md5_digest_len, "%s%s%s",
343                         MESSAGEPORT_BUS_NAME_PREFIX, encoded_bus_name, postfix);
344
345         _LOGD("md5_encoded_bus_name : %s ", md5_digest);
346         g_free(encoded_bus_name);
347
348         return md5_digest;
349 }
350
351 MESSAGE_PORT_CTOR static void __message_port_init(void)
352 {
353         g_rec_mutex_init(&__rec_mutex);
354 }
355
356 MESSAGE_PORT_DTOR static void __message_port_fini(void)
357 {
358         if (g_rec_mutex_trylock(&__rec_mutex))
359                 g_rec_mutex_unlock(&__rec_mutex);
360         else
361                 _LOGE("rec_mutex is locked by another thread.");
362
363         g_rec_mutex_clear(&__rec_mutex);
364 }
365
366 void message_port_lock_mutex()
367 {
368         g_rec_mutex_lock(&__rec_mutex);
369 }
370
371 void message_port_unlock_mutex()
372 {
373         g_rec_mutex_unlock(&__rec_mutex);
374 }