tizen beta release
[framework/messaging/email-service.git] / ipc / socket / ipc-socket.cpp
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 "ipc-socket.h"
24 #include "ipc-library-build.h"
25 #include "emf-dbglog.h"
26 #include "emf-types.h"
27
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
34 #include <errno.h>
35 #include <unistd.h>
36 #include <errno.h>
37
38 /*  Constructor */
39 ipcEmailSocket::ipcEmailSocket() : maxfd(-1)
40 {
41         m_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
42
43         EM_DEBUG_LOG("fd = %d", m_sockfd);
44
45         if (m_sockfd < 0)  {
46                 EM_DEBUG_LOG("socket creation fails!!!: %s", strerror(errno));
47         }
48
49         FD_ZERO(&fds);
50 }
51
52 /*  Destructor */
53 ipcEmailSocket::~ipcEmailSocket()
54 {
55         FD_ZERO(&fds);
56         mapFds.clear();
57         EM_DEBUG_LOG("socket object is destoryed");
58 }
59
60 /*  Close */
61 void ipcEmailSocket::Close()
62 {
63         close(m_sockfd);
64         m_sockfd = 0;
65         m_bConnect = false;
66         EM_DEBUG_LOG("sockfd = [%d] is closed", m_sockfd);
67 }
68
69 void ipcEmailSocket::Close(int fd)
70 {
71         EM_DEBUG_FUNC_BEGIN("fd [%d]",fd);
72
73         if (fd == -1)  {
74                 EM_DEBUG_LOG("server_socket not init");
75                 return;
76         }
77         
78         EM_DEBUG_LOG("%d to be removed", fd);
79         FD_CLR(fd, &fds);
80
81         std::map<int, int>::iterator it = mapFds.find(fd);
82         if(it == mapFds.end()) {
83                 EM_DEBUG_LOG("No matching socket fd [%d]", fd);
84                 return;
85         } else
86                 mapFds.erase(it);
87
88         if ( fd == maxfd ) {
89                 int newmax = 0;
90                 for( it = mapFds.begin() ; it != mapFds.end() ; it++ )
91                         newmax = (it->second > newmax )? it->second : newmax; 
92                 maxfd = newmax;
93         }
94         EM_DEBUG_LOG("fd %d removal done", fd);
95         ::close(fd);
96         EM_DEBUG_FUNC_END();
97 }
98
99 bool ipcEmailSocket::IsConnected()
100 {
101         return m_bConnect;
102 }
103
104 int ipcEmailSocket::writen (int fd, const char *buf, int len)
105 {
106         int nleft, nwrite;
107
108         nleft = len;
109         while( nleft > 0 )  {
110                 nwrite = ::send(fd, (const void*) buf, nleft, MSG_NOSIGNAL);
111 /*              nwrite = ::write(fd, (const void*) buf, nleft); */
112                 if( nwrite == -1 )  {
113                         EM_DEBUG_LOG("write: %s", EM_STRERROR(errno));
114                         if (errno == EINTR) continue;
115                         return nwrite;
116                 } else if ( nwrite == 0 ) 
117                         break;
118                 
119                 nleft -= nwrite;
120                 buf += nwrite;
121         }
122         return (len-nleft);
123 }
124
125 int ipcEmailSocket::Send(int fd, char* buffer, int buf_len)
126 {
127         EM_DEBUG_FUNC_BEGIN("fd [%d], buffer [%p], buf_len [%d]", fd, buffer, buf_len);
128
129         if( !buffer ) {
130                 EM_DEBUG_EXCEPTION("No data to send");
131                 return 0;
132         }
133
134         /*
135         if(!IsConnected()) {
136                 EM_DEBUG_EXCEPTION("Socket is not connected.");
137                 return FAILURE;
138         }
139         */
140
141         int send_bytes = sizeof(int)+buf_len;
142         char buf[send_bytes];
143         memcpy(buf, (char*) &buf_len, sizeof(int)); /*  write buffer lenth */
144         memcpy(buf + sizeof(int), buffer, buf_len); /*  write buffer */
145
146         EM_DEBUG_LOG("Sending %dB data to [fd = %d] ", send_bytes, fd);
147     int nRet = writen(fd, buf, send_bytes);
148
149         EM_DEBUG_FUNC_END();    
150     return nRet;
151 /*
152         EM_DEBUG_LOG("Sending %dB data to [fd = %d] ", buf_len, fd);
153         int n = writen(fd, buffer, buf_len);
154
155         if( n != buf_len ) {
156                 EM_DEBUG_LOG("WARNING: write buf_size[%d] != send_len [%d]", n, buf_len);
157                 return FAILURE;
158         }
159         EM_DEBUG_FUNC_END();            
160         return n;
161 */
162 }
163
164
165 int ipcEmailSocket::readn( int fd, char *buf, int len )
166 {
167         int nleft, nread;
168
169         nleft = len;
170         while( nleft > 0 ) {
171                 nread = ::read(fd, (void*)buf, nleft);
172                 if( nread < 0 ) {
173                         EM_DEBUG_EXCEPTION("read: %s", strerror(errno));
174                         if (errno == EINTR) continue;
175                         return nread;
176                 } else if( nread == 0 )
177                         break;
178                 
179                 nleft -= nread;
180                 buf += nread;
181         }
182         return (len-nleft);
183 }
184
185 int ipcEmailSocket::Recv(int fd, char** buffer)
186 {
187         EM_DEBUG_FUNC_BEGIN();
188         if ( !buffer ) {
189                 EM_DEBUG_LOG("buffer MUST NOT NULL");
190                 return FAILURE;
191         }
192
193         /*  read the data size first and store it to len */
194         int n, len = 0;
195         
196         EM_DEBUG_LOG("[IPC Socket] Receiving header begins");
197         n = readn(fd, (char*) &len, sizeof(int));
198         EM_DEBUG_LOG("[IPC Socket] Receiving header %dB data", len);
199         
200         if ( n == 0 ) /*  if service gets down, it signals to all IPC clients */
201                 return n; else if ( n != sizeof(int) ) {
202                 EM_DEBUG_LOG("WARNING: read header_size[%d] not matched [%d]", n, sizeof(int));
203                 return FAILURE;
204         }
205 /*      if( ioctl(fd, FIONREAD, &len) == -1 )  {
206         EM_DEBUG_LOG("FIONREAD %s", EM_STRERROR(errno));
207         return FAILURE;
208     }
209 */
210         /*  alloc buffer and read data */
211         *buffer = new char[len];
212
213         EM_DEBUG_LOG("[IPC Socket] Receiving Body begins for [%d] bytes", len);
214         n = readn(fd, *buffer, len);
215         if ( n !=  len ) {
216                 delete[] *buffer;
217                 *buffer = NULL;
218                 EM_DEBUG_LOG("WARNING: read buf_size [%d] != read_len[%d]", n, len);
219                 return FAILURE;
220         }
221
222         EM_DEBUG_LOG("[IPC Socket] Receiving [%d] bytes Completed", len);
223
224         return n;
225 }
226
227 int ipcEmailSocket::GetSocketID()
228 {
229         return m_sockfd;
230 }
231
232
233 int ipcEmailSocket::accept()
234 {
235         EM_DEBUG_FUNC_BEGIN();
236
237         if (m_sockfd == -1)  {
238                 EM_DEBUG_LOG("server_socket not init");
239                 return FAILURE;
240         }
241         
242         struct sockaddr_un remote;
243
244         int t = sizeof(remote);
245         int fd = ::accept(m_sockfd, (struct sockaddr *)&remote, (socklen_t*) &t);
246         if (fd == -1)  {
247                 EM_DEBUG_LOG("accept: %s", EM_STRERROR(errno));
248                 return FAILURE;
249         }
250
251         addfd(fd);
252         EM_DEBUG_LOG("%d is added", fd);
253
254         EM_DEBUG_FUNC_END();
255         return fd;
256 }
257
258 int ipcEmailSocket::open(const char* path)
259 {
260         EM_DEBUG_FUNC_BEGIN("path [%s]", path);
261
262         if (!path || strlen(path) > 108) {
263                 EM_DEBUG_LOG("path is null");
264                 return FAILURE;
265         }
266         
267         if ( m_sockfd <= 0 ) {
268                 EM_DEBUG_LOG("Server_socket not created %d", m_sockfd);
269                 return FAILURE;
270         }
271
272         struct sockaddr_un local;
273         
274         local.sun_family = AF_UNIX;
275         strcpy(local.sun_path, path);
276         unlink(local.sun_path);
277         
278         int len = strlen(local.sun_path) + sizeof(local.sun_family);
279         
280         if (bind(m_sockfd, (struct sockaddr *)&local, len) == -1)  {
281                 EM_DEBUG_LOG("bind: %s", strerror(errno));
282                 return FAILURE;
283         }
284
285         /**
286          * determine permission of socket file
287          *
288          *  - S_IRWXU : for user, allow read and write and execute
289          *  - S_IRWXG : for group, allow read and write and execute
290          *  - S_IRWXO : for other, allow read and write and execute
291          *
292          *  - S_IRUSR, S_IWUSR, S_IXUSR : for user, allow only read, write, execute respectively
293          *  - S_IRGRP, S_IWGRP, S_IXGRP : for group, allow only read, write, execute respectively
294          *  - S_IROTH, S_IWOTH, S_IXOTH : for other, allow only read, write, execute respectively
295          */
296         mode_t sock_mode = (S_IRWXU | S_IRWXG | S_IRWXO); /*  has 777 permission */
297
298         if (chmod(path, sock_mode) == -1) {
299                 EM_DEBUG_LOG("chmod: %s", strerror(errno));
300                 return FAILURE;
301         }
302
303         if (listen(m_sockfd, 10) == -1) {
304                 EM_DEBUG_LOG("listen: %s", strerror(errno));
305                 return FAILURE;
306         }
307
308         addfd(m_sockfd);
309
310         EM_DEBUG_FUNC_END();
311         return 0;
312 }
313
314
315 int ipcEmailSocket::Connect()
316 {
317         EM_DEBUG_FUNC_BEGIN();
318         
319         struct sockaddr_un serverSA;
320         serverSA.sun_family = AF_UNIX;
321         strcpy(serverSA.sun_path, EM_SOCKET_PATH); /*  "./socket" */
322         
323         int len = strlen(serverSA.sun_path) + sizeof(serverSA.sun_family);
324         
325         if (::connect(m_sockfd, (struct sockaddr *)&serverSA, len) == -1)  {
326                 EM_DEBUG_LOG("cannot connect server %s", strerror(errno));
327                 return FAILURE;
328         }
329
330         /* add fd for select() */
331         addfd(m_sockfd);
332         m_bConnect = true;
333
334         return 0;
335 }
336
337 void ipcEmailSocket::addfd(int fd)
338 {
339         EM_DEBUG_LOG("%d added", fd);
340         FD_SET(fd, &fds);
341
342         std::map<int, int>::iterator it = mapFds.find(fd);
343         if(it != mapFds.end()) {
344                 EM_DEBUG_LOG("Duplicate FD %d", fd);
345                 return;
346         } else
347                 mapFds[fd] = fd;
348         
349         if ( fd > maxfd )
350                 maxfd = fd;
351 }
352
353