Fix socket exception handling
[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 <openssl/md5.h>
30 #include <gio/gio.h>
31 #include <pthread.h>
32 #include <glib-unix.h>
33 #include <poll.h>
34
35 #include "message_port_log.h"
36 #include "message_port.h"
37 #include "message_port_common.h"
38
39 #define MAX_PACKAGE_STR_SIZE 512
40 #define MAX_RETRY_CNT 10
41
42 static const int MAX_MESSAGE_SIZE = 16 * 1024;
43
44 int write_socket(int fd,
45                 const char *buffer,
46                 unsigned int nbytes,
47                 unsigned int *bytes_write,
48                 int *sequence)
49 {
50 #define SEND_TIMEOUT 500 /* milliseconds */
51
52         unsigned int left = nbytes;
53         ssize_t nb;
54         int retry_cnt = 0;
55         struct pollfd fds[1];
56         int ret;
57
58         *sequence += 1;
59         *bytes_write = 0;
60
61         fds[0].fd = fd;
62         fds[0].events = POLLOUT;
63         fds[0].revents = 0;
64
65         ret = poll(fds, 1, SEND_TIMEOUT);
66         if (ret == 0) {
67                 LOGE("write_socket: : fd %d poll timeout", fd);
68                 return MESSAGE_PORT_ERROR_RESOURCE_UNAVAILABLE;
69         }
70
71         while (left && (retry_cnt < MAX_RETRY_CNT)) {
72                 nb = write(fd, buffer, left);
73                 if (nb == -1) {
74                         if (errno == EINTR) {
75                                 LOGE("write_socket: EINTR error continue ...");
76                                 retry_cnt++;
77                                 continue;
78                         }
79                         LOGE("write_socket: ...error fd %d: errno %d\n", fd, errno);
80
81                         if (errno == EWOULDBLOCK || errno == EAGAIN)
82                                 return MESSAGE_PORT_ERROR_RESOURCE_UNAVAILABLE;
83
84                         return MESSAGE_PORT_ERROR_IO_ERROR;
85                 }
86
87                 left -= nb;
88                 buffer += nb;
89                 *bytes_write += nb;
90                 retry_cnt = 0;
91         }
92
93         if (left != 0) {
94                 _LOGE("error fd %d: retry_cnt %d", fd, retry_cnt);
95                 return MESSAGE_PORT_ERROR_IO_ERROR;
96         }
97
98         return MESSAGE_PORT_ERROR_NONE;
99 }
100
101 int write_string_to_socket(int fd,
102                 const char *buffer,
103                 int string_len,
104                 unsigned int *bytes_write,
105                 int *sequence)
106 {
107         int ret;
108
109         ret = write_socket(fd, (char *)&string_len, sizeof(string_len),
110                         bytes_write, sequence);
111         if (ret != MESSAGE_PORT_ERROR_NONE) {
112                 _LOGE("write string_len fail");
113                 return ret;
114         }
115
116         if (string_len > 0) {
117                 ret = write_socket(fd, buffer, string_len, bytes_write, sequence);
118                 if (ret != MESSAGE_PORT_ERROR_NONE) {
119                         _LOGE("wirte buffer fail");
120                         return ret;
121                 }
122         } else {
123                 *sequence += 1;
124         }
125
126         return MESSAGE_PORT_ERROR_NONE;
127 }
128
129 int read_socket(int fd,
130                 char *buffer,
131                 unsigned int nbytes,
132                 unsigned int *bytes_read)
133 {
134         unsigned int left = nbytes;
135         ssize_t nb;
136         int retry_cnt = 0;
137         const struct timespec TRY_SLEEP_TIME = { 0, 500 * 1000 * 1000 };
138
139         *bytes_read = 0;
140         while (left && (retry_cnt < MAX_RETRY_CNT)) {
141                 nb = read(fd, buffer, left);
142                 if (nb == 0) {
143                         LOGE("read_socket: ...read EOF, socket closed %d: nb %d\n", fd, nb);
144                         return MESSAGE_PORT_ERROR_IO_ERROR;
145                 } else if (nb == -1) {
146                         /*  wrt(nodejs) could change socket to none-blocking socket :-( */
147                         if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
148                                 LOGE("read_socket: %d errno, sleep and retry ...", errno);
149                                 retry_cnt++;
150                                 nanosleep(&TRY_SLEEP_TIME, 0);
151                                 continue;
152                         }
153                         LOGE("read_socket: ...error fd %d: errno %d\n", fd, errno);
154                         return MESSAGE_PORT_ERROR_IO_ERROR;
155                 }
156
157                 left -= nb;
158                 buffer += nb;
159                 *bytes_read += nb;
160                 retry_cnt = 0;
161         }
162
163         if (left != 0) {
164                 _LOGE("error fd %d: retry_cnt %d", fd, retry_cnt);
165                 return MESSAGE_PORT_ERROR_IO_ERROR;
166         }
167
168         return MESSAGE_PORT_ERROR_NONE;
169 }
170
171 int read_string_from_socket(int fd, char **buffer, int *string_len)
172 {
173         unsigned int nb;
174         if (read_socket(fd, (char *)string_len, sizeof(*string_len), &nb) != MESSAGE_PORT_ERROR_NONE) {
175                 LOGE("read socket fail");
176                 return MESSAGE_PORT_ERROR_IO_ERROR;
177         }
178         if (*string_len > 0 && *string_len < MAX_MESSAGE_SIZE) {
179                 *buffer = (char *)calloc(*string_len, sizeof(char));
180                 if (*buffer == NULL) {
181                         LOGE("Out of memory.");
182                         return MESSAGE_PORT_ERROR_IO_ERROR;
183                 }
184                 if (read_socket(fd, *buffer, *string_len, &nb) != MESSAGE_PORT_ERROR_NONE) {
185                         LOGE("read socket fail");
186                         return MESSAGE_PORT_ERROR_IO_ERROR;
187                 }
188         } else {
189                 LOGE("Invalid string len %d", *string_len);
190                 return MESSAGE_PORT_ERROR_IO_ERROR;
191         }
192         return MESSAGE_PORT_ERROR_NONE;
193 }
194
195 static int __dbus_init(void)
196 {
197         bool ret = false;
198         GError *error = NULL;
199
200         gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
201         if (gdbus_conn == NULL) {
202                 if (error != NULL) {
203                         _LOGE("Failed to get dbus [%s]", error->message);
204                         g_error_free(error);
205                 }
206                 goto out;
207         }
208
209         ret = true;
210
211 out:
212         if (!gdbus_conn)
213                 g_object_unref(gdbus_conn);
214
215         return ret;
216
217 }
218
219 bool initialize_common(void)
220 {
221
222 #if !GLIB_CHECK_VERSION(2, 35, 0)
223         g_type_init();
224 #endif
225
226         int pid = getpid();
227         int ret = 0;
228         char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
229
230         ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
231         retvm_if(ret != AUL_R_OK, false, "Failed to get the application ID: %d", ret);
232
233         app_id = strdup(buffer);
234         retvm_if(!app_id, false, "Malloc failed");
235         _LOGI("init : %s", app_id);
236
237         if (!__dbus_init())
238                 return false;
239         initialized_common = true;
240
241         return true;
242 }
243
244 bool is_preloaded(const char *local_appid, const char *remote_appid)
245 {
246         _LOGD("IsPreloaded");
247
248         bool preload_local = false;
249         bool preload_remote = false;
250
251         pkgmgrinfo_appinfo_h handle = NULL;
252         int ret = pkgmgrinfo_appinfo_get_usr_appinfo(local_appid, getuid(), &handle);
253         if (ret != PMINFO_R_OK) {
254                 _LOGE("Failed to get the appinfo. %d", ret);
255                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
256                 return false;
257         }
258         ret = pkgmgrinfo_appinfo_is_preload(handle, &preload_local);
259         if (ret != PMINFO_R_OK) {
260                 _LOGE("Failed to check the preloaded application. %d", ret);
261                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
262                 return false;
263         }
264         pkgmgrinfo_appinfo_destroy_appinfo(handle);
265
266         ret = pkgmgrinfo_appinfo_get_usr_appinfo(remote_appid, getuid(), &handle);
267         if (ret != PMINFO_R_OK) {
268                 _LOGE("Failed to get the appinfo. %d", ret);
269                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
270                 return false;
271         }
272         ret = pkgmgrinfo_appinfo_is_preload(handle, &preload_remote);
273         if (ret != PMINFO_R_OK) {
274                 _LOGE("Failed to check the preloaded application. %d", ret);
275                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
276                 return false;
277         }
278
279         if (preload_local && preload_remote) {
280                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
281                 return true;
282         }
283         pkgmgrinfo_appinfo_destroy_appinfo(handle);
284         return false;
285 }
286
287 int check_certificate(const char *local_appid, const char *remote_appid)
288 {
289         _LOGD("CheckCertificate");
290
291         pkgmgrinfo_cert_compare_result_type_e res;
292         int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(local_appid, remote_appid, getuid(), &res);
293         if (ret < 0) {
294                 _LOGE(":CheckCertificate() Failed");
295                 return MESSAGE_PORT_ERROR_IO_ERROR;
296         }
297         if (res != PMINFO_CERT_COMPARE_MATCH) {
298                 _LOGE("CheckCertificate() Failed : MESSAGE_PORT_ERROR_CERTIFICATE_NOT_MATCH");
299                 return MESSAGE_PORT_ERROR_CERTIFICATE_NOT_MATCH;
300         }
301
302         return MESSAGE_PORT_ERROR_NONE;
303 }
304
305 char *get_encoded_name(const char *remote_app_id, const char *port_name, bool is_trusted)
306 {
307
308         int prefix_len = strlen(MESSAGEPORT_BUS_NAME_PREFIX);
309         int postfix_len = 1;
310         char *postfix = is_trusted ? "1" : "0";
311
312         unsigned char c[MD5_DIGEST_LENGTH] = {0};
313         char *md5_interface = NULL;
314         char *temp;
315         int index = 0;
316         MD5_CTX mdContext;
317         int encoded_bus_name_len = prefix_len + postfix_len + (MD5_DIGEST_LENGTH * 2) + 2;
318         int bus_name_len = strlen(remote_app_id) + strlen(port_name) + 2;
319         char *bus_name = (char *)calloc(bus_name_len, sizeof(char));
320         if (bus_name == NULL) {
321                 _LOGE("bus_name calloc failed");
322                 return 0;
323         }
324
325         snprintf(bus_name, bus_name_len, "%s_%s", remote_app_id, port_name);
326
327         MD5_Init(&mdContext);
328         MD5_Update(&mdContext, bus_name, bus_name_len);
329         MD5_Final(c, &mdContext);
330
331         md5_interface = (char *)calloc(encoded_bus_name_len , sizeof(char));
332         if (md5_interface == NULL) {
333                 if (bus_name)
334                         free(bus_name);
335
336                 _LOGE("md5_interface calloc failed!!");
337                 return 0;
338         }
339
340         snprintf(md5_interface, encoded_bus_name_len, "%s", MESSAGEPORT_BUS_NAME_PREFIX);
341         temp = md5_interface;
342         temp += prefix_len;
343
344         for (index = 0; index < MD5_DIGEST_LENGTH; index++) {
345                 snprintf(temp, 3, "%02x", c[index]);
346                 temp += 2;
347         }
348
349         if (postfix && postfix_len > 0)
350                 snprintf(temp, encoded_bus_name_len - (temp - md5_interface), "%s", postfix);
351         if (bus_name)
352                 free(bus_name);
353
354         _LOGD("encoded_bus_name : %s ", md5_interface);
355
356         return md5_interface;
357 }