48cf3eeb2510d58b642b2edf0599dc005ac76a5c
[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                 int gid, cookies_size;
164                 char *cookies;
165
166                 gid = security_server_get_gid("smartcard-service");
167                 if(gid == 0)
168                 {
169                         SCARD_DEBUG("get gid from security server is failed. this object is not allowed by security server");
170                         goto ERROR;
171                 }
172
173                 if((cookies_size = security_server_get_cookie_size()) != 0)
174                 {
175                         if((cookies = (char *)calloc(1, cookies_size)) == NULL)
176                         {
177                                 goto ERROR;
178                         }
179                 }
180 #endif
181
182                 SCARD_DEBUG("server ipc is initialized");
183
184                 return true;
185 ERROR :
186                 SCARD_DEBUG_ERR("error while initializing server ipc");
187
188                 destroyListenSocket();
189
190                 return false;
191         }
192
193 #ifdef CLIENT_IPC_THREAD
194         int IPCHelper::eventPoll()
195         {
196                 int result = -1;
197
198 #ifdef USE_IPC_EPOLL
199                 int events = 0;
200
201                 if ((events = epoll_wait(fdPoll, pollEvents, EPOLL_SIZE, -1)) > 0)
202                 {
203                         int i;
204
205                         for (i = 0; i < events; i++)
206                         {
207                                 SCARD_DEBUG("pollEvents[%d].events [%X]", i, pollEvents[i].events);
208
209                                 if ((pollEvents[i].events & EPOLLHUP) || (pollEvents[i].events & EPOLLERR))
210                                 {
211                                         SCARD_DEBUG_ERR("connection is closed");
212                                         result = 0;
213                                         break;
214                                 }
215                                 else if (pollEvents[i].events & EPOLLIN)
216                                 {
217                                         result = 1;
218                                         break;
219                                 }
220                         }
221                 }
222 #else
223                 if (select(ipcSocket + 1, &fdSetRead, NULL, NULL, NULL) > 0)
224                 {
225                         if (FD_ISSET(ipcSocket, &fdSetRead) == true)
226                         {
227                                 int val = -1;
228                                 unsigned int size = sizeof(val);
229
230                                 if (getsockopt(ipcSocket, SOL_SOCKET, SO_ERROR, (void *)&val, &size) == 0)
231                                 {
232                                         if (val == 0)
233                                         {
234                                                 SCARD_DEBUG("socket is readable");
235                                                 result = 1;
236                                         }
237                                         else
238                                         {
239                                                 SCARD_DEBUG("socket is not available. maybe disconnected");
240                                                 result = 0;
241                                         }
242                                 }
243                                 else
244                                 {
245                                         SCARD_DEBUG_ERR("getsockopt failed, errno [%d]", errno);
246                                         result = errno;
247                                 }
248                         }
249                         else
250                         {
251                                 SCARD_DEBUG_ERR("FD_ISSET false!!! what's wrong");
252                                 result = -1;
253                         }
254                 }
255                 else
256                 {
257                         SCARD_DEBUG_ERR("select failed [%d]", errno);
258                         result = errno;
259                 }
260 #endif
261                 return result;
262         }
263
264         void *IPCHelper::threadRead(void *data)
265         {
266 #ifdef IPC_USE_SIGTERM
267
268                 struct sigaction act;
269                 act.sa_handler = thread_sig_handler;
270                 sigaction(SIGTERM, &act, NULL);
271
272                 sigset_t newmask;
273                 sigemptyset(&newmask);
274                 sigaddset(&newmask, SIGTERM);
275                 pthread_sigmask(SIG_UNBLOCK, &newmask, NULL);
276                 SCARD_DEBUG("sighandler is registered");
277
278                 pthread_mutex_lock(&g_client_lock);
279                 pthread_cond_signal ((pthread_cond_t *) data);
280                 pthread_mutex_unlock(&g_client_lock);
281 #else
282                 IPCHelper *helper = (IPCHelper *)data;
283 #endif
284                 bool condition = true;
285                 int result = 0;
286
287                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
288
289                 while (condition == true)
290                 {
291                         if ((result = helper->eventPoll()) > 0)
292                         {
293                                 condition = (helper->handleIncomingCondition(NULL, G_IO_IN) == 0);
294                         }
295                         else if (result == 0)
296                         {
297                                 helper->handleIOErrorCondition(NULL, G_IO_ERR);
298                                 condition = false;
299                         }
300                         else
301                         {
302                                 helper->handleInvalidSocketCondition(NULL, G_IO_NVAL);
303                                 condition = false;
304                         }
305                 }
306
307                 SCARD_DEBUG("threadRead is terminated");
308
309                 return (void *)NULL;
310         }
311 #endif
312
313         bool IPCHelper::createConnectSocket()
314         {
315 #ifndef CLIENT_IPC_THREAD
316                 GIOCondition condition = (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_IN);
317 #endif
318                 int result = 0;
319                 char err[200] = { 0, };
320
321                 SCARD_BEGIN();
322
323                 if (ipcSocket >= 0)
324                         return true;
325
326                 pthread_mutex_lock(&ipcLock);
327
328                 struct sockaddr_un saddrun_rv;
329                 socklen_t len_saddr = 0;
330
331                 memset(&saddrun_rv, 0, sizeof(struct sockaddr_un));
332
333                 ipcSocket = socket(AF_UNIX, SOCK_STREAM, 0);
334                 if (ipcSocket == -1)
335                 {
336                         SCARD_DEBUG_ERR("get socket is failed [%d, %s]",
337                                 errno, strerror_r(errno, err, sizeof(err)));
338                         goto ERROR;
339                 }
340
341                 SCARD_DEBUG("socket is created");
342
343                 ::setNonBlockSocket(ipcSocket);
344
345                 saddrun_rv.sun_family = AF_UNIX;
346                 strncpy(saddrun_rv.sun_path, SCARD_SERVER_DOMAIN, sizeof(saddrun_rv.sun_path) - 1);
347
348                 len_saddr = sizeof(saddrun_rv.sun_family) + strlen(SCARD_SERVER_DOMAIN);
349
350                 if ((result = connect(ipcSocket, (struct sockaddr *)&saddrun_rv, len_saddr)) < 0)
351                 {
352                         SCARD_DEBUG_ERR("connect failed [%d, %s]",
353                                 errno, strerror_r(errno, err, sizeof(err)));
354                         goto ERROR;
355                 }
356
357 #ifdef CLIENT_IPC_THREAD
358 #ifdef USE_IPC_EPOLL
359                 if((fdPoll = epoll_create1(EPOLL_CLOEXEC)) == -1)
360                 {
361                         SCARD_DEBUG_ERR("epoll_create1 failed [%d, %s]",
362                                 errno, strerror_r(errno, err, sizeof(err)));
363                         goto ERROR;
364                 }
365
366                 pollEvents = (struct epoll_event *)calloc(EPOLL_SIZE, sizeof(struct epoll_event));
367                 if (pollEvents == NULL)
368                 {
369                         SCARD_DEBUG_ERR("alloc failed");
370                         goto ERROR;
371                 }
372
373                 struct epoll_event ev;
374
375                 ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
376                 ev.data.fd = ipcSocket;
377
378                 epoll_ctl(fdPoll, EPOLL_CTL_ADD, ipcSocket, &ev);
379 #else
380                 FD_ZERO(&fdSetRead);
381                 FD_SET(ipcSocket, &fdSetRead);
382 #endif
383 #ifdef IPC_USE_SIGTERM
384                 pthread_cond_t pcond = PTHREAD_COND_INITIALIZER;
385
386                 if (pthread_create(&readThread, NULL, &IPCHelper::threadRead, &pcond) != 0)
387 #else
388                 if (pthread_create(&readThread, NULL, &IPCHelper::threadRead, this) != 0)
389 #endif
390                 {
391                         SCARD_DEBUG_ERR("pthread_create is failed");
392                         goto ERROR;
393                 }
394
395 #ifdef IPC_USE_SIGTERM
396                 pthread_cond_wait (&pcond, &g_client_lock);
397 #endif
398
399 #else
400                 if ((ioChannel = g_io_channel_unix_new(ipcSocket)) != NULL)
401                 {
402                         if ((watchId = g_io_add_watch(ioChannel, condition, &IPCHelper::channelCallbackFunc, this)) < 1)
403                         {
404                                 SCARD_DEBUG_ERR(" g_io_add_watch is failed");
405                                 goto ERROR;
406                         }
407                 }
408                 else
409                 {
410                         SCARD_DEBUG_ERR(" g_io_channel_unix_new is failed");
411                         goto ERROR;
412                 }
413 #endif
414                 pthread_mutex_unlock(&ipcLock);
415
416                 SCARD_DEBUG("connecting success");
417
418                 SCARD_END();
419
420                 return true;
421
422 ERROR :
423                 SCARD_DEBUG_ERR("error while initializing client ipc");
424
425                 destroyConnectSocket();
426
427                 pthread_mutex_unlock(&ipcLock);
428
429                 SCARD_END();
430
431                 return false;
432         }
433
434         void IPCHelper::destroyListenSocket()
435         {
436                 if (watchId != (uint32_t)-1)
437                 {
438                         g_source_remove(watchId);
439                         watchId = -1;
440                 }
441
442                 if (ioChannel != NULL)
443                 {
444                         g_io_channel_unref(ioChannel);
445                         ioChannel = NULL;
446                 }
447
448                 if (ipcSocket != -1)
449                 {
450                         shutdown(ipcSocket, SHUT_RDWR);
451                         close(ipcSocket);
452
453                         ipcSocket = -1;
454                 }
455         }
456
457         void IPCHelper::destroyConnectSocket()
458         {
459 #ifdef CLIENT_IPC_THREAD
460                 /* kill thread */
461                 if (readThread > 0)
462                 {
463                         pthread_cancel(readThread);
464                         readThread = 0;
465                 }
466 #ifdef USE_IPC_EPOLL
467                 if(fdPoll != -1)
468                 {
469                         struct epoll_event ev;
470
471                         ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
472                         ev.data.fd = ipcSocket;
473                         epoll_ctl(fdPoll, EPOLL_CTL_DEL, ipcSocket, &ev);
474
475                         close(fdPoll);
476                         fdPoll = -1;
477
478                         if (pollEvents != NULL)
479                         {
480                                 free(pollEvents);
481                         }
482                 }
483 #else
484                 if (ipcSocket != -1)
485                 {
486                         FD_CLR(ipcSocket, &fdSetRead);
487                 }
488 #endif
489 #else
490                 if(watchId != 0)
491                 {
492                         g_source_remove(watchId);
493                         watchId = 0;
494                 }
495
496                 if(ioChannel != NULL)
497                 {
498                         g_io_channel_unref(ioChannel);
499                         ioChannel = NULL;
500                 }
501 #endif
502
503                 if (ipcSocket != -1)
504                 {
505                         shutdown(ipcSocket, SHUT_RDWR);
506                         close(ipcSocket);
507                         ipcSocket = -1;
508                 }
509         }
510
511         bool IPCHelper::sendMessage(int socket, Message *msg)
512         {
513                 ByteArray stream;
514                 unsigned int length = 0;
515
516                 stream = msg->serialize();
517                 length = stream.getLength();
518
519                 SCARD_DEBUG(">>>[SEND]>>> socket [%d], msg [%d], length [%d]",
520                         socket, msg->message, stream.getLength());
521
522                 return sendMessage(socket, stream);
523         }
524
525         bool IPCHelper::sendMessage(int socket, ByteArray &buffer)
526         {
527                 bool result = false;
528                 unsigned int length = 0;
529
530                 length = buffer.getLength();
531
532                 if (length > 0)
533                 {
534                         int sentBytes = 0;
535
536                         /* send 4 bytes (length) */
537                         pthread_mutex_lock(&ipcLock);
538                         sentBytes = send(socket, &length, sizeof(length), 0);
539                         pthread_mutex_unlock(&ipcLock);
540                         if (sentBytes == sizeof(length))
541                         {
542                                 unsigned int current = 0;
543
544                                 /* send message */
545                                 pthread_mutex_lock(&ipcLock);
546                                 do
547                                 {
548                                         sentBytes = send(socket, buffer.getBuffer(current), length - current, 0);
549                                         if (sentBytes > 0)
550                                                 current += sentBytes;
551                                 }
552                                 while (current < length);
553                                 pthread_mutex_unlock(&ipcLock);
554
555                                 result = true;
556                         }
557                         else
558                         {
559                                 SCARD_DEBUG_ERR("send failed, sentBytes [%d]", sentBytes);
560                         }
561                 }
562                 else
563                 {
564                         SCARD_DEBUG_ERR("stream length is zero");
565                 }
566
567                 return result;
568         }
569
570         Message *IPCHelper::retrieveMessage()
571         {
572                 return retrieveMessage(ipcSocket);
573         }
574
575         Message *IPCHelper::retrieveMessage(int socket)
576         {
577                 ByteArray buffer;
578                 Message *msg = NULL;
579
580                 SCARD_BEGIN();
581
582                 buffer = retrieveBuffer(socket);
583                 if (buffer.getLength() > 0)
584                 {
585                         msg = new Message();
586                         if (msg != NULL)
587                         {
588                                 msg->deserialize(buffer);
589                         }
590                         else
591                         {
592                                 SCARD_DEBUG_ERR("alloc failed");
593                         }
594                 }
595                 else
596                 {
597                         SCARD_DEBUG_ERR("retrieveBuffer failed ");
598                 }
599
600                 SCARD_END();
601
602                 return msg;
603         }
604
605         ByteArray IPCHelper::retrieveBuffer(int socket)
606         {
607                 ByteArray buffer;
608                 unsigned int length = 0;
609                 int readBytes = 0;
610
611                 SCARD_BEGIN();
612
613                 /* read 4 bytes (length) */
614                 pthread_mutex_lock(&ipcLock);
615                 readBytes = recv(socket, &length, sizeof(length), 0);
616                 pthread_mutex_unlock(&ipcLock);
617                 if (readBytes == sizeof(length))
618                 {
619                         if (length > 0)
620                         {
621                                 uint8_t *temp = NULL;
622
623                                 /* prepare buffer */
624                                 temp = new uint8_t[length];
625                                 if (temp != NULL)
626                                 {
627                                         int retry = 0;
628                                         unsigned int current = 0;
629
630                                         /* read message */
631                                         pthread_mutex_lock(&ipcLock);
632                                         do
633                                         {
634                                                 readBytes = recv(socket, temp + current, length - current, 0);
635                                                 if (readBytes > 0)
636                                                         current += readBytes;
637                                                 retry++;
638                                         }
639                                         while (current < length);
640                                         pthread_mutex_unlock(&ipcLock);
641
642                                         SCARD_DEBUG("<<<[RETRIEVE]<<< socket [%d], msg_length [%d]", socket, length);
643
644                                         buffer.setBuffer(temp, length);
645
646                                         delete []temp;
647                                 }
648                                 else
649                                 {
650                                         SCARD_DEBUG_ERR("allocation failed");
651                                 }
652                         }
653                         else
654                         {
655                                 SCARD_DEBUG_ERR("invalid length, socket = [%d], msg_length = [%d]", socket, length);
656                         }
657                 }
658                 else
659                 {
660                         SCARD_DEBUG_ERR("failed to recv length, socket = [%d], readBytes [%d]", socket, readBytes);
661                 }
662
663                 SCARD_END();
664
665                 return buffer;
666         }
667
668         void IPCHelper::setDispatcher(DispatcherHelper *dispatcher)
669         {
670                 this->dispatcher = dispatcher;
671         }
672
673 } /* namespace smartcard_service_api */