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