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