2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 /* standard library header */
24 #include <sys/socket.h>
25 #ifdef USE_UNIX_DOMAIN
28 #else /* USE_UNIX_DOMAIN */
29 #include <netinet/in.h>
30 #endif /* USE_UNIX_DOMAIN */
33 #include <sys/epoll.h>
36 /* SLP library header */
40 #include "IPCHelper.h"
42 #ifdef USE_UNIX_DOMAIN
43 #define SCARD_SERVER_DOMAIN "/tmp/smartcard-server-domain"
44 #endif /* USE_UNIX_DOMAIN */
46 static void setNonBlockSocket(int socket)
50 flags = fcntl(socket, F_GETFL);
54 if (fcntl(socket, F_SETFL, flags) < 0)
56 /* _ERR("fcntl, executing nonblock error"); */
60 namespace smartcard_service_api
62 IPCHelper::IPCHelper() : fdPoll(-1)
67 memset(&ipcLock, 0, sizeof(ipcLock));
73 IPCHelper::~IPCHelper()
77 gboolean IPCHelper::channelCallbackFunc(GIOChannel* channel, GIOCondition condition, gpointer data)
79 IPCHelper *helper = (IPCHelper *)data;
80 gboolean result = FALSE;
82 _DBG("channel [%p], condition [%d], data [%p]", channel, condition, data);
86 _ERR("ipchelper is null");
90 if ((G_IO_ERR & condition) || (G_IO_HUP & condition))
92 result = helper->handleIOErrorCondition(channel, condition);
94 else if (G_IO_NVAL & condition)
96 result = helper->handleInvalidSocketCondition(channel, condition);
98 else if (G_IO_IN & condition)
100 result = helper->handleIncomingCondition(channel, condition);
106 bool IPCHelper::createListenSocket()
108 GIOCondition condition = (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_IN);
109 struct sockaddr_un saddrun_rv;
114 memset(&saddrun_rv, 0, sizeof(struct sockaddr_un));
116 unlink(SCARD_SERVER_DOMAIN);
118 ipcSocket = socket(AF_UNIX, SOCK_STREAM, 0);
121 _ERR("get socket is failed");
125 ::setNonBlockSocket(ipcSocket);
127 saddrun_rv.sun_family = AF_UNIX;
128 strncpy(saddrun_rv.sun_path, SCARD_SERVER_DOMAIN, sizeof(saddrun_rv.sun_path) - 1);
130 if (bind(ipcSocket, (struct sockaddr *)&saddrun_rv, sizeof(saddrun_rv)) < 0)
132 _ERR("bind is failed");
136 if (chmod(SCARD_SERVER_DOMAIN, 0777) < 0)
138 _ERR("can not change permission of UNIX DOMAIN file");
142 if (listen(ipcSocket, IPC_SERVER_MAX_CLIENT) < 0)
144 _ERR("listen is failed");
148 if ((ioChannel = g_io_channel_unix_new(ipcSocket)) != NULL)
150 if ((watchId = g_io_add_watch(ioChannel, condition, &IPCHelper::channelCallbackFunc, this)) < 1)
152 _ERR(" g_io_add_watch is failed");
158 _ERR(" g_io_channel_unix_new is failed");
162 #ifdef SECURITY_SERVER
163 int gid, cookies_size;
166 gid = security_server_get_gid("smartcard-service");
169 _DBG("get gid from security server is failed. this object is not allowed by security server");
173 if((cookies_size = security_server_get_cookie_size()) != 0)
175 if((cookies = (char *)calloc(1, cookies_size)) == NULL)
182 _INFO("server ipc is initialized");
186 _ERR("error while initializing server ipc");
188 destroyListenSocket();
193 #ifdef CLIENT_IPC_THREAD
194 int IPCHelper::eventPoll()
201 if ((events = epoll_wait(fdPoll, pollEvents, EPOLL_SIZE, -1)) > 0)
205 for (i = 0; i < events; i++)
207 _DBG("pollEvents[%d].events [%X]", i, pollEvents[i].events);
209 if ((pollEvents[i].events & EPOLLHUP) || (pollEvents[i].events & EPOLLERR))
211 _ERR("connection is closed");
215 else if (pollEvents[i].events & EPOLLIN)
222 else if (errno == EINTR)
224 _ERR("epoll_wait interrupted");
230 _ERR("epoll_wait failed, errno [%d], %s", errno, strerror_r(errno, buffer, sizeof(buffer)));
233 if (select(ipcSocket + 1, &fdSetRead, NULL, NULL, NULL) > 0)
235 if (FD_ISSET(ipcSocket, &fdSetRead) == true)
238 unsigned int size = sizeof(val);
240 if (getsockopt(ipcSocket, SOL_SOCKET, SO_ERROR, (void *)&val, &size) == 0)
244 _DBG("socket is readable");
249 _DBG("socket is not available. maybe disconnected");
255 _ERR("getsockopt failed, errno [%d]", errno);
261 _ERR("FD_ISSET false!!! what's wrong");
267 _ERR("select failed [%d]", errno);
274 void *IPCHelper::threadRead(void *data)
276 #ifdef IPC_USE_SIGTERM
278 struct sigaction act;
279 act.sa_handler = thread_sig_handler;
280 sigaction(SIGTERM, &act, NULL);
283 sigemptyset(&newmask);
284 sigaddset(&newmask, SIGTERM);
285 pthread_sigmask(SIG_UNBLOCK, &newmask, NULL);
286 _DBG("sighandler is registered");
288 pthread_mutex_lock(&g_client_lock);
289 pthread_cond_signal ((pthread_cond_t *) data);
290 pthread_mutex_unlock(&g_client_lock);
292 IPCHelper *helper = (IPCHelper *)data;
294 bool condition = true;
297 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
299 while (condition == true)
301 if ((result = helper->eventPoll()) > 0)
303 condition = (helper->handleIncomingCondition(NULL, G_IO_IN) == 0);
305 else if (result == 0)
307 helper->handleIOErrorCondition(NULL, G_IO_ERR);
312 /* skip other error case */
316 _INFO("threadRead is terminated");
322 bool IPCHelper::createConnectSocket()
324 #ifndef CLIENT_IPC_THREAD
325 GIOCondition condition = (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_IN);
328 char err[200] = { 0, };
335 pthread_mutex_lock(&ipcLock);
337 struct sockaddr_un saddrun_rv;
338 socklen_t len_saddr = 0;
340 memset(&saddrun_rv, 0, sizeof(struct sockaddr_un));
342 ipcSocket = socket(AF_UNIX, SOCK_STREAM, 0);
345 _ERR("get socket is failed [%d, %s]",
346 errno, strerror_r(errno, err, sizeof(err)));
350 _DBG("socket is created");
352 ::setNonBlockSocket(ipcSocket);
354 saddrun_rv.sun_family = AF_UNIX;
355 strncpy(saddrun_rv.sun_path, SCARD_SERVER_DOMAIN, sizeof(saddrun_rv.sun_path) - 1);
357 len_saddr = sizeof(saddrun_rv.sun_family) + strlen(SCARD_SERVER_DOMAIN);
359 if ((result = connect(ipcSocket, (struct sockaddr *)&saddrun_rv, len_saddr)) < 0)
361 _ERR("connect failed [%d, %s]",
362 errno, strerror_r(errno, err, sizeof(err)));
366 #ifdef CLIENT_IPC_THREAD
368 if((fdPoll = epoll_create1(EPOLL_CLOEXEC)) == -1)
370 _ERR("epoll_create1 failed [%d, %s]",
371 errno, strerror_r(errno, err, sizeof(err)));
375 pollEvents = (struct epoll_event *)calloc(EPOLL_SIZE, sizeof(struct epoll_event));
376 if (pollEvents == NULL)
378 _ERR("alloc failed");
382 struct epoll_event ev;
384 ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
385 ev.data.fd = ipcSocket;
387 epoll_ctl(fdPoll, EPOLL_CTL_ADD, ipcSocket, &ev);
390 FD_SET(ipcSocket, &fdSetRead);
392 #ifdef IPC_USE_SIGTERM
393 pthread_cond_t pcond = PTHREAD_COND_INITIALIZER;
395 if (pthread_create(&readThread, NULL, &IPCHelper::threadRead, &pcond) != 0)
397 if (pthread_create(&readThread, NULL, &IPCHelper::threadRead, this) != 0)
400 _ERR("pthread_create is failed");
404 #ifdef IPC_USE_SIGTERM
405 pthread_cond_wait (&pcond, &g_client_lock);
409 if ((ioChannel = g_io_channel_unix_new(ipcSocket)) != NULL)
411 if ((watchId = g_io_add_watch(ioChannel, condition, &IPCHelper::channelCallbackFunc, this)) < 1)
413 _ERR(" g_io_add_watch is failed");
419 _ERR(" g_io_channel_unix_new is failed");
423 pthread_mutex_unlock(&ipcLock);
425 _INFO("connecting success");
432 _ERR("error while initializing client ipc");
434 destroyConnectSocket();
436 pthread_mutex_unlock(&ipcLock);
443 void IPCHelper::destroyListenSocket()
445 if (watchId != (uint32_t)-1)
447 g_source_remove(watchId);
451 if (ioChannel != NULL)
453 g_io_channel_unref(ioChannel);
459 shutdown(ipcSocket, SHUT_RDWR);
466 void IPCHelper::destroyConnectSocket()
468 #ifdef CLIENT_IPC_THREAD
472 pthread_cancel(readThread);
478 struct epoll_event ev;
480 ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
481 ev.data.fd = ipcSocket;
482 epoll_ctl(fdPoll, EPOLL_CTL_DEL, ipcSocket, &ev);
487 if (pollEvents != NULL)
495 FD_CLR(ipcSocket, &fdSetRead);
501 g_source_remove(watchId);
505 if(ioChannel != NULL)
507 g_io_channel_unref(ioChannel);
514 shutdown(ipcSocket, SHUT_RDWR);
520 bool IPCHelper::sendMessage(int socket, const Message &msg)
523 unsigned int length = 0;
525 stream = msg.serialize();
526 length = stream.size();
528 _DBG(">>>[SEND]>>> socket [%d], msg [%d], length [%d]",
529 socket, msg.message, stream.size());
531 return sendMessage(socket, stream);
534 bool IPCHelper::sendMessage(int socket, const ByteArray &buffer)
537 unsigned int length = 0;
539 length = buffer.size();
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))
551 unsigned int current = 0;
554 pthread_mutex_lock(&ipcLock);
557 sentBytes = send(socket, buffer.getBuffer(current), length - current, 0);
559 current += sentBytes;
561 while (current < length);
562 pthread_mutex_unlock(&ipcLock);
568 _ERR("send failed, sentBytes [%d]", sentBytes);
573 _ERR("stream length is zero");
579 Message *IPCHelper::retrieveMessage()
581 return retrieveMessage(ipcSocket);
584 Message *IPCHelper::retrieveMessage(int socket)
591 buffer = retrieveBuffer(socket);
592 if (buffer.size() > 0)
597 msg->deserialize(buffer);
601 _ERR("alloc failed");
606 _ERR("retrieveBuffer failed ");
614 const ByteArray IPCHelper::retrieveBuffer(int socket)
617 unsigned int length = 0;
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))
630 uint8_t *temp = NULL;
633 temp = new uint8_t[length];
637 unsigned int current = 0;
640 pthread_mutex_lock(&ipcLock);
643 readBytes = recv(socket, temp + current, length - current, 0);
645 current += readBytes;
648 while (current < length);
649 pthread_mutex_unlock(&ipcLock);
651 _DBG("<<<[RETRIEVE]<<< socket [%d], msg_length [%d]", socket, length);
653 buffer.assign(temp, length);
659 _ERR("allocation failed");
664 _ERR("invalid length, socket = [%d], msg_length = [%d]", socket, length);
669 _ERR("failed to recv length, socket = [%d], readBytes [%d]", socket, readBytes);
677 void IPCHelper::setDispatcher(DispatcherHelper *dispatcher)
679 this->dispatcher = dispatcher;
682 } /* namespace smartcard_service_api */