Tizen 2.1 base
[platform/core/connectivity/smartcard-service.git] / common / IPCHelper.cpp
1 /*
2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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
18 /* standard library header */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/socket.h>
25 #ifdef USE_UNIX_DOMAIN
26 #include <sys/un.h>
27 #include <sys/stat.h>
28 #else /* USE_UNIX_DOMAIN */
29 #include <netinet/in.h>
30 #endif /* USE_UNIX_DOMAIN */
31 #include <fcntl.h>
32 #ifdef USE_IPC_EPOLL
33 #include <sys/epoll.h>
34 #endif
35
36 /* SLP library header */
37
38 /* local header */
39 #include "Debug.h"
40 #include "IPCHelper.h"
41
42 #ifdef USE_UNIX_DOMAIN
43 #define SCARD_SERVER_DOMAIN "/tmp/omapi-server-domain"
44 #endif /* USE_UNIX_DOMAIN */
45
46 static void setNonBlockSocket(int socket)
47 {
48         int flags;
49
50         flags = fcntl(socket, F_GETFL);
51
52         flags |= O_NONBLOCK;
53
54         if (fcntl(socket, F_SETFL, flags) < 0)
55         {
56                 /* SCARD_DEBUG_ERR("fcntl, executing nonblock error"); */
57         }
58 }
59
60 namespace smartcard_service_api
61 {
62         IPCHelper::IPCHelper() : fdPoll(-1)
63         {
64                 ipcSocket = -1;
65                 ioChannel = NULL;
66                 watchId = 0;
67                 memset(&ipcLock, 0, sizeof(ipcLock));
68                 dispatcher = NULL;
69                 pollEvents = NULL;
70                 readThread = 0;
71         }
72
73         IPCHelper::~IPCHelper()
74         {
75         }
76
77         gboolean IPCHelper::channelCallbackFunc(GIOChannel* channel, GIOCondition condition, gpointer data)
78         {
79                 IPCHelper *helper = (IPCHelper *)data;
80                 gboolean result = FALSE;
81
82                 SCARD_DEBUG("channel [%p], condition [%d], data [%p]", channel, condition, data);
83
84                 if (helper == NULL)
85                 {
86                         SCARD_DEBUG_ERR("ipchelper is null");
87                         return result;
88                 }
89
90                 if ((G_IO_ERR & condition) || (G_IO_HUP & condition))
91                 {
92                         result = helper->handleIOErrorCondition(channel, condition);
93                 }
94                 else if (G_IO_NVAL & condition)
95                 {
96                         result = helper->handleInvalidSocketCondition(channel, condition);
97                 }
98                 else if (G_IO_IN & condition)
99                 {
100                         result = helper->handleIncomingCondition(channel, condition);
101                 }
102
103                 return result;
104         }
105
106         bool IPCHelper::createListenSocket()
107         {
108                 GIOCondition condition = (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_IN);
109                 struct sockaddr_un saddrun_rv;
110
111                 if (ipcSocket >= 0)
112                         return true;
113
114                 memset(&saddrun_rv, 0, sizeof(struct sockaddr_un));
115
116                 unlink(SCARD_SERVER_DOMAIN);
117
118                 ipcSocket = socket(AF_UNIX, SOCK_STREAM, 0);
119                 if (ipcSocket == -1)
120                 {
121                         SCARD_DEBUG_ERR("get socket is failed");
122                         return false;
123                 }
124
125                 ::setNonBlockSocket(ipcSocket);
126
127                 saddrun_rv.sun_family = AF_UNIX;
128                 strncpy(saddrun_rv.sun_path, SCARD_SERVER_DOMAIN, sizeof(saddrun_rv.sun_path) - 1);
129
130                 if (bind(ipcSocket, (struct sockaddr *)&saddrun_rv, sizeof(saddrun_rv)) < 0)
131                 {
132                         SCARD_DEBUG_ERR("bind is failed \n");
133                         goto ERROR;
134                 }
135
136                 if (chmod(SCARD_SERVER_DOMAIN, 0777) < 0)
137                 {
138                         SCARD_DEBUG_ERR("can not change permission of UNIX DOMAIN file");
139                         goto ERROR;
140                 }
141
142                 if (listen(ipcSocket, IPC_SERVER_MAX_CLIENT) < 0)
143                 {
144                         SCARD_DEBUG_ERR("listen is failed \n");
145                         goto ERROR;
146                 }
147
148                 if ((ioChannel = g_io_channel_unix_new(ipcSocket)) != NULL)
149                 {
150                         if ((watchId = g_io_add_watch(ioChannel, condition, &IPCHelper::channelCallbackFunc, this)) < 1)
151                         {
152                                 SCARD_DEBUG_ERR(" g_io_add_watch is failed \n");
153                                 goto ERROR;
154                         }
155                 }
156                 else
157                 {
158                         SCARD_DEBUG_ERR(" g_io_channel_unix_new is failed \n");
159                         goto ERROR;
160                 }
161
162 #ifdef SECURITY_SERVER
163                 gid = security_server_get_gid(NET_NFC_MANAGER_OBJECT);
164                 if(gid == 0)
165                 {
166                         SCARD_DEBUG("get gid from security server is failed. this object is not allowed by security server");
167                         goto ERROR;
168                 }
169
170                 if((cookies_size = security_server_get_cookie_size()) != 0)
171                 {
172                         if((cookies = (char *)calloc(1, cookies_size)) == NULL)
173                         {
174                                 goto ERROR;
175                         }
176                 }
177 #endif
178
179                 SCARD_DEBUG("server ipc is initialized");
180
181                 return true;
182 ERROR :
183                 SCARD_DEBUG_ERR("error while initializing server ipc");
184
185                 destroyListenSocket();
186
187                 return false;
188         }
189
190 #ifdef CLIENT_IPC_THREAD
191         int IPCHelper::eventPoll()
192         {
193                 int result = -1;
194
195 #ifdef USE_IPC_EPOLL
196                 int events = 0;
197
198                 if ((events = epoll_wait(fdPoll, pollEvents, EPOLL_SIZE, -1)) > 0)
199                 {
200                         int i;
201
202                         for (i = 0; i < events; i++)
203                         {
204                                 SCARD_DEBUG("pollEvents[%d].events [%X]", i, pollEvents[i].events);
205
206                                 if ((pollEvents[i].events & EPOLLHUP) || (pollEvents[i].events & EPOLLERR))
207                                 {
208                                         SCARD_DEBUG_ERR("connection is closed");
209                                         result = 0;
210                                         break;
211                                 }
212                                 else if (pollEvents[i].events & EPOLLIN)
213                                 {
214                                         result = 1;
215                                         break;
216                                 }
217                         }
218                 }
219 #else
220                 if (select(ipcSocket + 1, &fdSetRead, NULL, NULL, NULL) > 0)
221                 {
222                         if (FD_ISSET(ipcSocket, &fdSetRead) == true)
223                         {
224                                 int val = -1;
225                                 unsigned int size = sizeof(val);
226
227                                 if (getsockopt(ipcSocket, SOL_SOCKET, SO_ERROR, (void *)&val, &size) == 0)
228                                 {
229                                         if (val == 0)
230                                         {
231                                                 SCARD_DEBUG("socket is readable");
232                                                 result = 1;
233                                         }
234                                         else
235                                         {
236                                                 SCARD_DEBUG("socket is not available. maybe disconnected");
237                                                 result = 0;
238                                         }
239                                 }
240                                 else
241                                 {
242                                         SCARD_DEBUG_ERR("getsockopt failed, errno [%d]", errno);
243                                         result = errno;
244                                 }
245                         }
246                         else
247                         {
248                                 SCARD_DEBUG_ERR("FD_ISSET false!!! what's wrong");
249                                 result = -1;
250                         }
251                 }
252                 else
253                 {
254                         SCARD_DEBUG_ERR("select failed [%d]", errno);
255                         result = errno;
256                 }
257 #endif
258                 return result;
259         }
260
261         void *IPCHelper::threadRead(void *data)
262         {
263 #ifdef IPC_USE_SIGTERM
264
265                 struct sigaction act;
266                 act.sa_handler = thread_sig_handler;
267                 sigaction(SIGTERM, &act, NULL);
268
269                 sigset_t newmask;
270                 sigemptyset(&newmask);
271                 sigaddset(&newmask, SIGTERM);
272                 pthread_sigmask(SIG_UNBLOCK, &newmask, NULL);
273                 SCARD_DEBUG("sighandler is registered");
274
275                 pthread_mutex_lock(&g_client_lock);
276                 pthread_cond_signal ((pthread_cond_t *) data);
277                 pthread_mutex_unlock(&g_client_lock);
278 #else
279                 IPCHelper *helper = (IPCHelper *)data;
280 #endif
281                 bool condition = true;
282                 int result = 0;
283
284                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
285
286                 while (condition == true)
287                 {
288                         if ((result = helper->eventPoll()) > 0)
289                         {
290                                 condition = (helper->handleIncomingCondition(NULL, G_IO_IN) == 0);
291                         }
292                         else if (result == 0)
293                         {
294                                 helper->handleIOErrorCondition(NULL, G_IO_ERR);
295                                 condition = false;
296                         }
297                         else
298                         {
299                                 helper->handleInvalidSocketCondition(NULL, G_IO_NVAL);
300                                 condition = false;
301                         }
302                 }
303
304                 SCARD_DEBUG("threadRead is terminated");
305
306                 return (void *)NULL;
307         }
308 #endif
309
310         bool IPCHelper::createConnectSocket()
311         {
312 #ifndef CLIENT_IPC_THREAD
313                 GIOCondition condition = (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_IN);
314 #endif
315                 int result = 0;
316
317                 SCARD_BEGIN();
318
319                 if (ipcSocket >= 0)
320                         return true;
321
322                 pthread_mutex_lock(&ipcLock);
323
324                 struct sockaddr_un saddrun_rv;
325                 socklen_t len_saddr = 0;
326
327                 memset(&saddrun_rv, 0, sizeof(struct sockaddr_un));
328
329                 ipcSocket = socket(AF_UNIX, SOCK_STREAM, 0);
330                 if (ipcSocket == -1)
331                 {
332                         SCARD_DEBUG_ERR("get socket is failed");
333                         goto ERROR;
334                 }
335
336                 SCARD_DEBUG("socket is created");
337
338                 ::setNonBlockSocket(ipcSocket);
339
340                 saddrun_rv.sun_family = AF_UNIX;
341                 strncpy(saddrun_rv.sun_path, SCARD_SERVER_DOMAIN, sizeof(saddrun_rv.sun_path) - 1);
342
343                 len_saddr = sizeof(saddrun_rv.sun_family) + strlen(SCARD_SERVER_DOMAIN);
344
345                 if ((result = connect(ipcSocket, (struct sockaddr *)&saddrun_rv, len_saddr)) < 0)
346                 {
347                         SCARD_DEBUG_ERR("connect failed [%d]", result);
348                         goto ERROR;
349                 }
350
351 #ifdef CLIENT_IPC_THREAD
352 #ifdef USE_IPC_EPOLL
353                 if((fdPoll = epoll_create1(EPOLL_CLOEXEC)) == -1)
354                 {
355                         SCARD_DEBUG_ERR("epoll_create1 failed");
356                         goto ERROR;
357                 }
358
359                 pollEvents = (struct epoll_event *)calloc(EPOLL_SIZE, sizeof(struct epoll_event));
360                 if (pollEvents == NULL)
361                 {
362                         SCARD_DEBUG_ERR("alloc failed");
363                         goto ERROR;
364                 }
365
366                 struct epoll_event ev;
367
368                 ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
369                 ev.data.fd = ipcSocket;
370
371                 epoll_ctl(fdPoll, EPOLL_CTL_ADD, ipcSocket, &ev);
372 #else
373                 FD_ZERO(&fdSetRead);
374                 FD_SET(ipcSocket, &fdSetRead);
375 #endif
376 #ifdef IPC_USE_SIGTERM
377                 pthread_cond_t pcond = PTHREAD_COND_INITIALIZER;
378
379                 if (pthread_create(&readThread, NULL, &IPCHelper::threadRead, &pcond) != 0)
380 #else
381                 if (pthread_create(&readThread, NULL, &IPCHelper::threadRead, this) != 0)
382 #endif
383                 {
384                         SCARD_DEBUG_ERR("pthread_create is failed");
385                         goto ERROR;
386                 }
387
388 #ifdef IPC_USE_SIGTERM
389                 pthread_cond_wait (&pcond, &g_client_lock);
390 #endif
391
392 #else
393                 if ((ioChannel = g_io_channel_unix_new(ipcSocket)) != NULL)
394                 {
395                         if ((watchId = g_io_add_watch(ioChannel, condition, &IPCHelper::channelCallbackFunc, this)) < 1)
396                         {
397                                 SCARD_DEBUG_ERR(" g_io_add_watch is failed");
398                                 goto ERROR;
399                         }
400                 }
401                 else
402                 {
403                         SCARD_DEBUG_ERR(" g_io_channel_unix_new is failed");
404                         goto ERROR;
405                 }
406 #endif
407                 pthread_mutex_unlock(&ipcLock);
408
409                 SCARD_DEBUG("connecting success");
410
411                 SCARD_END();
412
413                 return true;
414
415 ERROR :
416                 SCARD_DEBUG_ERR("error while initializing client ipc");
417
418                 destroyConnectSocket();
419
420                 pthread_mutex_unlock(&ipcLock);
421
422                 SCARD_END();
423
424                 return false;
425         }
426
427         void IPCHelper::destroyListenSocket()
428         {
429                 if (watchId != (uint32_t)-1)
430                 {
431                         g_source_remove(watchId);
432                         watchId = -1;
433                 }
434
435                 if (ioChannel != NULL)
436                 {
437                         g_io_channel_unref(ioChannel);
438                         ioChannel = NULL;
439                 }
440
441                 if (ipcSocket != -1)
442                 {
443                         shutdown(ipcSocket, SHUT_RDWR);
444                         close(ipcSocket);
445
446                         ipcSocket = -1;
447                 }
448         }
449
450         void IPCHelper::destroyConnectSocket()
451         {
452 #ifdef CLIENT_IPC_THREAD
453                 /* kill thread */
454                 if (readThread > 0)
455                 {
456                         pthread_cancel(readThread);
457                         readThread = 0;
458                 }
459 #ifdef USE_IPC_EPOLL
460                 if(fdPoll != -1)
461                 {
462                         struct epoll_event ev;
463
464                         ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
465                         ev.data.fd = ipcSocket;
466                         epoll_ctl(fdPoll, EPOLL_CTL_DEL, ipcSocket, &ev);
467
468                         close(fdPoll);
469                         fdPoll = -1;
470
471                         if (pollEvents != NULL)
472                         {
473                                 free(pollEvents);
474                         }
475                 }
476 #else
477                 if (ipcSocket != -1)
478                 {
479                         FD_CLR(ipcSocket, &fdSetRead);
480                 }
481 #endif
482 #else
483                 if(watchId != 0)
484                 {
485                         g_source_remove(watchId);
486                         watchId = 0;
487                 }
488
489                 if(ioChannel != NULL)
490                 {
491                         g_io_channel_unref(ioChannel);
492                         ioChannel = NULL;
493                 }
494 #endif
495
496                 if (ipcSocket != -1)
497                 {
498                         shutdown(ipcSocket, SHUT_RDWR);
499                         close(ipcSocket);
500                         ipcSocket = -1;
501                 }
502         }
503
504         bool IPCHelper::sendMessage(int socket, Message *msg)
505         {
506                 ByteArray stream;
507                 unsigned int length = 0;
508
509                 stream = msg->serialize();
510                 length = stream.getLength();
511
512                 SCARD_DEBUG(">>>[SEND]>>> socket [%d], msg [%d], length [%d]", socket, msg->message, stream.getLength());
513
514                 return sendMessage(socket, stream);
515         }
516
517         bool IPCHelper::sendMessage(int socket, ByteArray &buffer)
518         {
519                 bool result = false;
520                 unsigned int length = 0;
521
522                 length = buffer.getLength();
523
524                 if (length > 0)
525                 {
526                         int sentBytes = 0;
527
528                         /* send 4 bytes (length) */
529                         pthread_mutex_lock(&ipcLock);
530                         sentBytes = send(socket, &length, sizeof(length), 0);
531                         pthread_mutex_unlock(&ipcLock);
532                         if (sentBytes == sizeof(length))
533                         {
534                                 unsigned int current = 0;
535
536                                 /* send message */
537                                 pthread_mutex_lock(&ipcLock);
538                                 do
539                                 {
540                                         sentBytes = send(socket, buffer.getBuffer(current), length - current, 0);
541                                         if (sentBytes > 0)
542                                                 current += sentBytes;
543                                 }
544                                 while (current < length);
545                                 pthread_mutex_unlock(&ipcLock);
546
547                                 result = true;
548                         }
549                         else
550                         {
551                                 SCARD_DEBUG_ERR("send failed, sentBytes [%d]", sentBytes);
552                         }
553                 }
554                 else
555                 {
556                         SCARD_DEBUG_ERR("stream length is zero");
557                 }
558
559                 return result;
560         }
561
562         Message *IPCHelper::retrieveMessage()
563         {
564                 return retrieveMessage(ipcSocket);
565         }
566
567         Message *IPCHelper::retrieveMessage(int socket)
568         {
569                 ByteArray buffer;
570                 Message *msg = NULL;
571
572                 SCARD_BEGIN();
573
574                 buffer = retrieveBuffer(socket);
575                 if (buffer.getLength() > 0)
576                 {
577                         msg = new Message();
578                         if (msg != NULL)
579                         {
580                                 msg->deserialize(buffer);
581                         }
582                         else
583                         {
584                                 SCARD_DEBUG_ERR("alloc failed");
585                         }
586                 }
587                 else
588                 {
589                         SCARD_DEBUG_ERR("retrieveBuffer failed ");
590                 }
591
592                 SCARD_END();
593
594                 return msg;
595         }
596
597         ByteArray IPCHelper::retrieveBuffer(int socket)
598         {
599                 ByteArray buffer;
600                 unsigned int length = 0;
601                 int readBytes = 0;
602
603                 SCARD_BEGIN();
604
605                 /* read 4 bytes (length) */
606                 pthread_mutex_lock(&ipcLock);
607                 readBytes = recv(socket, &length, sizeof(length), 0);
608                 pthread_mutex_unlock(&ipcLock);
609                 if (readBytes == sizeof(length))
610                 {
611                         if (length > 0)
612                         {
613                                 uint8_t *temp = NULL;
614
615                                 /* prepare buffer */
616                                 temp = new uint8_t[length];
617                                 if (temp != NULL)
618                                 {
619                                         int retry = 0;
620                                         unsigned int current = 0;
621
622                                         /* read message */
623                                         pthread_mutex_lock(&ipcLock);
624                                         do
625                                         {
626                                                 readBytes = recv(socket, temp + current, length - current, 0);
627                                                 if (readBytes > 0)
628                                                         current += readBytes;
629                                                 retry++;
630                                         }
631                                         while (current < length);
632                                         pthread_mutex_unlock(&ipcLock);
633
634                                         SCARD_DEBUG("<<<[RETRIEVE]<<< socket [%d], msg_length [%d]", socket, length);
635
636                                         buffer.setBuffer(temp, length);
637
638                                         delete []temp;
639                                 }
640                                 else
641                                 {
642                                         SCARD_DEBUG_ERR("allocation failed");
643                                 }
644                         }
645                         else
646                         {
647                                 SCARD_DEBUG_ERR("invalid length, socket = [%d], msg_length = [%d]", socket, length);
648                         }
649                 }
650                 else
651                 {
652                         SCARD_DEBUG_ERR("failed to recv length, socket = [%d], readBytes [%d]", socket, readBytes);
653                 }
654
655                 SCARD_END();
656
657                 return buffer;
658         }
659
660         void IPCHelper::setDispatcher(DispatcherHelper *dispatcher)
661         {
662                 this->dispatcher = dispatcher;
663         }
664
665 } /* namespace smartcard_service_api */