Tizen 2.0 Release
[platform/core/messaging/email-service.git] / email-ipc / email-socket / email-ipc-socket.c
1 /*
2 *  email-service
3 *
4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5 *
6 * Contact: Kyuho Jo <kyuho.jo@samsung.com>, Sunghyun Kwon <sh0701.kwon@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
23 #include "email-ipc-socket.h"
24 #include "email-ipc-build.h"
25
26 #include "email-debug-log.h"
27 #include "email-types.h"
28
29 #include <glib.h>
30
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <malloc.h>
37
38 #include <errno.h>
39 #include <unistd.h>
40
41 #include <systemd/sd-daemon.h>
42
43 EXPORT_API bool emipc_init_email_socket(int *fd)
44 {
45         bool ret = true;
46
47         *fd = socket(AF_UNIX, SOCK_STREAM, 0);
48
49         if (*fd < 0) {
50                 EM_DEBUG_EXCEPTION("socket creation fails!!!: %s", strerror(errno));
51                 ret = false;
52         }
53
54         EM_DEBUG_LOG("Socket fd = %d", *fd);
55
56         return ret;
57 }
58
59 /*  Close */
60 EXPORT_API void emipc_close_email_socket(int* fd)
61 {
62         EM_DEBUG_LOG("fd %d removal done", *fd);
63         close(*fd);
64         *fd = 0;
65 }
66
67 /* returns positive write length,
68  * 0, when connection is closed
69  * -1, when send error */
70 static int emipc_writen(int fd, const char *buf, int len)
71 {
72         int length = len;
73         int passed_len = 0;
74
75         while (length > 0) {
76                 passed_len = send(fd, (const void *)buf, length, MSG_NOSIGNAL);
77                 if (passed_len == -1) {
78                         EM_DEBUG_LOG("write : %s", EM_STRERROR(errno));
79                         if (errno == EINTR) continue;
80                         else if (errno == EPIPE) return 0; /* connection closed */
81                         else return passed_len; /* -1 */
82                 } else if (passed_len == 0)
83                         break;
84                 length -= passed_len;
85                 buf += passed_len;
86         }
87         return (len - length);
88 }
89
90 /* returns positive value, when write success,
91  * 0, when socket connection is broken,
92  * EMAIL_ERROR_IPC_SOCKET_FAILURE, when write failure,
93  * EMAIL_ERROR_INVALID_PARAM, when wrong parameter */
94 EXPORT_API int emipc_send_email_socket(int fd, unsigned char *buf, int len)
95 {
96         EM_DEBUG_FUNC_BEGIN("fd [%d], buffer [%p], buf_len [%d]", fd, buf, len);
97
98         if (!buf || len <= 0) {
99                 EM_DEBUG_EXCEPTION("No data to send %p, %d", buf, len);
100                 return EMAIL_ERROR_INVALID_PARAM;
101         }
102
103         EM_DEBUG_LOG("Sending %dB data to [fd = %d]", len, fd);
104
105         int write_len = emipc_writen(fd, (char*) buf, len);
106         if ( write_len != len) {
107                 if ( write_len == 0 ) return 0;
108                 EM_DEBUG_LOG("WARNING: buf_size [%d] != write_len[%d]", len, write_len);
109                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
110         }
111         EM_DEBUG_FUNC_END();
112         return write_len;
113 }
114
115 static int emipc_readn(int fd, char *buf, int len)
116 {
117         int length = len;
118         int read_len = 0;
119
120         while (length > 0) {
121                 read_len = read(fd, (void *)buf, length);
122                 if (read_len < 0) {
123                         EM_DEBUG_EXCEPTION("Read : %s", EM_STRERROR(errno));
124                         if (errno == EINTR) continue;
125                         return read_len;
126                 } else if (read_len == 0)
127                         break;
128
129                 length -= read_len;
130                 buf += read_len;
131         }
132         return (len-length);
133 }
134
135 /* returns positive value when read success,
136  * 0, when socket is closed
137  * EMAIL_ERROR_IPC_SOCKET_FAILURE, when read failed
138  * EMAIL_ERROR_INVALID_PARAM when wrong parameter */
139 EXPORT_API int emipc_recv_email_socket(int fd, char **buf)
140 {
141         EM_DEBUG_FUNC_BEGIN();
142
143         if (!buf) {
144                 EM_DEBUG_LOG("Buffer must not null");
145                 return EMAIL_ERROR_INVALID_PARAM;
146         }
147
148         int read_len = 0;
149         /* read the size of message. note that ioctl is non-blocking */
150         if (ioctl(fd, FIONREAD, &read_len)) {
151                 EM_DEBUG_EXCEPTION("ioctl: %s", strerror(errno));
152                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
153         }
154         /* when server or client closed socket */
155         if ( read_len == 0 ) {
156                 EM_DEBUG_LOG("[IPC Socket] connection is closed");
157                 return 0;
158         }
159
160         *buf = (char *) malloc(read_len);
161         if (*buf == NULL) {
162                 EM_DEBUG_EXCEPTION("Malloc failed");
163                 return EMAIL_ERROR_OUT_OF_MEMORY;
164         }
165         memset(*buf, 0x00, read_len);
166
167         EM_DEBUG_LOG("[IPC Socket] Receiving [%d] bytes", read_len);
168         int len = emipc_readn(fd, *buf, read_len);
169         if (read_len != len) {
170                 EM_SAFE_FREE(*buf);
171                 EM_DEBUG_LOG("WARNING: buf_size [%d] != read_len[%d]", read_len, len);
172                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
173         }
174
175         EM_DEBUG_LOG("[IPC Socket] Receiving [%d] bytes Completed", len);
176
177         return len;
178 }
179
180 EXPORT_API int emipc_accept_email_socket(int fd)
181 {
182         EM_DEBUG_FUNC_BEGIN();
183
184         if (fd == -1) {
185                 EM_DEBUG_LOG("Server_socket not init");
186                 return EMAIL_ERROR_INVALID_PARAM;
187         }
188
189         struct sockaddr_un remote;
190         int remote_len = sizeof(remote);
191         int client_fd = accept(fd, (struct sockaddr *)&remote, (socklen_t*) &remote_len);
192         if (client_fd == -1) {
193                 EM_DEBUG_LOG("accept: %s", EM_STRERROR(errno));
194                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
195         }
196
197         EM_DEBUG_LOG("%d is added", client_fd);
198
199         EM_DEBUG_FUNC_END();
200         return client_fd;
201 }
202
203 EXPORT_API int emipc_open_email_socket(int fd, const char *path)
204 {
205         EM_DEBUG_FUNC_BEGIN("path [%s]", path);
206         int sock_fd = 0;
207
208         if (strcmp(path, EM_SOCKET_PATH) == 0 &&
209                 sd_listen_fds(1) == 1 &&
210                 sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, -1, EM_SOCKET_PATH, 0) > 0) {
211                 close(fd);
212                 sock_fd = SD_LISTEN_FDS_START + 0;
213                 return sock_fd;
214         }
215
216         if (!path || EM_SAFE_STRLEN(path) > 108) {
217                 EM_DEBUG_LOG("Path is null");
218                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
219         }
220
221         if (fd <= 0) {
222                 EM_DEBUG_LOG("Socket not created %d", fd);
223                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
224         }
225
226         struct sockaddr_un local;
227         local.sun_family = AF_UNIX;
228         strcpy(local.sun_path, path);
229         unlink(local.sun_path);
230
231         int len = EM_SAFE_STRLEN(local.sun_path) + sizeof(local.sun_family);
232
233         if (bind(fd, (struct sockaddr *)&local, len) == -1) {
234                 EM_DEBUG_LOG("bind: %s", EM_STRERROR(errno));
235                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
236         }
237
238         /**
239          * determine permission of socket file
240          *
241          *  - S_IRWXU : for user, allow read and write and execute
242          *  - S_IRWXG : for group, allow read and write and execute
243          *  - S_IRWXO : for other, allow read and write and execute
244          *
245          *  - S_IRUSR, S_IWUSR, S_IXUSR : for user, allow only read, write, execute respectively
246          *  - S_IRGRP, S_IWGRP, S_IXGRP : for group, allow only read, write, execute respectively
247          *  - S_IROTH, S_IWOTH, S_IXOTH : for other, allow only read, write, execute respectively
248          */
249         mode_t sock_mode = (S_IRWXU | S_IRWXG | S_IRWXO); /*  has 777 permission */
250
251         if (chmod(path, sock_mode) == -1) {
252                 EM_DEBUG_LOG("chmod: %s", EM_STRERROR(errno));
253                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
254         }
255
256         if (listen(fd, 10) == -1) {
257                 EM_DEBUG_LOG("listen: %s", EM_STRERROR(errno));
258                 return EMAIL_ERROR_IPC_SOCKET_FAILURE;
259         }
260
261         EM_DEBUG_FUNC_END();
262         return fd;
263 }
264
265 EXPORT_API bool emipc_connect_email_socket(int fd)
266 {
267         EM_DEBUG_FUNC_BEGIN();
268         struct sockaddr_un server;
269         server.sun_family = AF_UNIX;
270         strcpy(server.sun_path, EM_SOCKET_PATH);
271
272         int len = EM_SAFE_STRLEN(server.sun_path) + sizeof(server.sun_family);
273
274         if (connect(fd, (struct sockaddr *)&server, len) == -1) {
275                 EM_DEBUG_LOG("Cannot connect server %s", EM_STRERROR(errno));
276                 return false;
277         }
278
279         return true;
280 }
281