Give delay when client request shutting down
[platform/core/connectivity/smartcard-service.git] / client / SEService.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
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 /* standard library header */
18 #include <unistd.h>
19 #include <string.h>
20 #include <glib.h>
21 #include <glib-object.h>
22
23 /* SLP library header */
24
25 /* local header */
26 #include "Debug.h"
27 #include "SEService.h"
28 #include "Reader.h"
29 #ifdef USE_GDBUS
30 #include "ClientGDBus.h"
31 #else
32 #include "Message.h"
33 #include "ClientIPC.h"
34 #include "ClientDispatcher.h"
35 #endif
36
37 #ifndef EXTERN_API
38 #define EXTERN_API __attribute__((visibility("default")))
39 #endif
40
41 #define SHUTDOWN_DELAY          500000 /* us */
42
43 namespace smartcard_service_api
44 {
45         SEService::SEService() : SEServiceHelper(),
46                 handle(-1), context(NULL), handler(NULL), listener(NULL)
47         {
48 #ifdef USE_GDBUS
49                 proxy = NULL;
50 #endif
51         }
52
53         SEService::SEService(void *user_data, serviceConnected handler)
54                 throw(ErrorIO &, ErrorIllegalParameter &) :
55                 SEServiceHelper(), handle(-1),
56                 listener(NULL)
57         {
58                 initialize(user_data, handler);
59         }
60
61         SEService::SEService(void *user_data, SEServiceListener *listener)
62                 throw(ErrorIO &, ErrorIllegalParameter &) :
63                 SEServiceHelper(), handle(-1),
64                 handler(NULL)
65         {
66                 initialize(user_data, listener);
67         }
68
69         SEService::~SEService()
70         {
71                 uint32_t i;
72
73                 try
74                 {
75                         shutdownSync();
76                 }
77                 catch(ExceptionBase &e)
78                 {
79                         _ERR("EXCEPTION : %s", e.what());
80                 }
81                 catch(...)
82                 {
83                         _ERR("EXCEPTION!!!");
84                 }
85
86                 for (i = 0; i < readers.size(); i++)
87                 {
88                         delete (Reader *)readers[i];
89                 }
90                 readers.clear();
91         }
92
93         SEService *SEService::createInstance(void *user_data,
94                 SEServiceListener *listener)
95                 throw(ErrorIO &, ErrorIllegalParameter &)
96         {
97                 return new SEService(user_data, listener);
98         }
99
100         SEService *SEService::createInstance(void *user_data,
101                 serviceConnected handler)
102                 throw(ErrorIO &, ErrorIllegalParameter &)
103         {
104                 return new SEService(user_data, handler);
105         }
106
107 #ifdef USE_GDBUS
108         void SEService::reader_inserted(GObject *source_object,
109                 guint reader_id, gchar *reader_name, gpointer user_data)
110         {
111                 Reader *reader = NULL;
112                 SEService *service = (SEService *)user_data;
113
114                 _INFO("[MSG_NOTIFY_SE_INSERTED]");
115
116                 /* add readers */
117                 reader = new Reader(service->context,
118                         reader_name, GUINT_TO_POINTER(reader_id));
119                 if (reader != NULL)
120                 {
121                         service->readers.push_back(reader);
122                 }
123                 else
124                 {
125                         _ERR("alloc failed");
126                 }
127
128                 if (service->listener != NULL)
129                 {
130                         service->listener->eventHandler(service,
131                                 reader_name, 1, service->context);
132                 }
133                 else
134                 {
135                         _DBG("listener is null");
136                 }
137         }
138
139         void SEService::reader_removed(GObject *source_object,
140                 guint reader_id, gchar *reader_name, gpointer user_data)
141         {
142                 SEService *service = (SEService *)user_data;
143                 size_t i;
144
145                 _INFO("[MSG_NOTIFY_SE_REMOVED]");
146
147                 for (i = 0; i < service->readers.size(); i++)
148                 {
149                         if (((Reader *)service->readers[i])->handle ==
150                                 GUINT_TO_POINTER(reader_id))
151                         {
152                                 ((Reader *)service->readers[i])->unavailable();
153                                 break;
154                         }
155                 }
156
157                 if (service->listener != NULL)
158                 {
159                         service->listener->eventHandler(service,
160                                 reader_name, 2, service->context);
161                 }
162                 else
163                 {
164                         _DBG("listener is null");
165                 }
166         }
167
168         void SEService::se_service_shutdown_cb(GObject *source_object,
169                 GAsyncResult *res, gpointer user_data)
170         {
171                 SEService *service = (SEService *)user_data;
172                 gint result;
173                 GError *error = NULL;
174
175                 if (smartcard_service_se_service_call_shutdown_finish(
176                         SMARTCARD_SERVICE_SE_SERVICE(source_object),
177                         &result, res, &error) == true) {
178                         if (result == SCARD_ERROR_OK) {
179                                 service->connected = false;
180                         } else {
181                                 _ERR("smartcard_service_se_service_call_shutdown failed, [%d]", result);
182                         }
183                 } else {
184                         _ERR("smartcard_service_se_service_call_shutdown failed, [%s]", error->message);
185                         g_error_free(error);
186                 }
187         }
188
189         void SEService::se_service_cb(GObject *source_object,
190                 GAsyncResult *res, gpointer user_data)
191         {
192                 SEService *service = (SEService *)user_data;
193                 gint result;
194                 guint handle;
195                 GVariant *readers = NULL;
196                 GError *error = NULL;
197
198                 if (service == NULL) {
199                         _ERR("null parameter!!!");
200                         return;
201                 }
202
203                 if (smartcard_service_se_service_call_se_service_finish(
204                         SMARTCARD_SERVICE_SE_SERVICE(source_object),
205                         &result, &handle, &readers, res, &error) == true) {
206                         if (result == SCARD_ERROR_OK) {
207                                 service->connected = true;
208                                 service->handle = handle;
209                                 service->parseReaderInformation(readers);
210                         }
211                 } else {
212                         _ERR("smartcard_service_se_service_call_se_service failed, [%s]", error->message);
213                         g_error_free(error);
214
215                         result = SCARD_ERROR_IPC_FAILED;
216                 }
217
218                 if (service->handler != NULL) {
219                         service->handler(service, service->context);
220                 } else if (service->listener != NULL) {
221                         if (result == SCARD_ERROR_OK) {
222                                 service->listener->serviceConnected(service, service->context);
223                         } else {
224                                 service->listener->errorHandler(service, result, service->context);
225                         }
226                 }
227         }
228 #endif
229         void SEService::shutdown()
230         {
231                 shutdownSync();
232         }
233
234         void SEService::shutdownSync()
235         {
236                 if (connected == true)
237                 {
238                         uint32_t i;
239
240                         for (i = 0; i < readers.size(); i++)
241                         {
242                                 readers[i]->closeSessions();
243                         }
244 #ifdef USE_GDBUS
245                         gint result;
246                         GError *error = NULL;
247
248                         if (smartcard_service_se_service_call_shutdown_sync(
249                                 (SmartcardServiceSeService *)proxy,
250                                 handle,
251                                 &result,
252                                 NULL,
253                                 &error) == false) {
254                                 _ERR("smartcard_service_se_service_call_shutdown_sync failed, [%s]", error->message);
255
256                                 g_error_free(error);
257                         }
258
259                         /* wait at least 500ms */
260                         usleep(SHUTDOWN_DELAY);
261
262                         connected = false;
263 #else
264 #ifdef CLIENT_IPC_THREAD
265                         /* send message to load se */
266                         Message msg;
267
268                         msg.message = Message::MSG_REQUEST_SHUTDOWN;
269                         msg.param1 = (unsigned long)handle;
270                         msg.error = (unsigned long)this; /* using error to context */
271                         msg.caller = (void *)this;
272                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
273
274                         syncLock();
275                         if (ClientIPC::getInstance().sendMessage(msg) == true)
276                         {
277                                 int rv;
278
279                                 rv = waitTimedCondition(0);
280                                 if (rv == 0)
281                                 {
282                                         ClientDispatcher::getInstance().removeSEService(handle);
283
284                                         connected = false;
285                                 }
286                                 else
287                                 {
288                                         _ERR("time over");
289                                 }
290                         }
291                         else
292                         {
293                                 _ERR("sendMessage failed");
294                         }
295                         syncUnlock();
296 #endif
297 #endif
298                 }
299         }
300
301         bool SEService::_initialize() throw(ErrorIO &)
302         {
303                 bool result = false;
304 #ifndef USE_GDBUS
305                 ClientIPC *clientIPC;
306                 ClientDispatcher *clientDispatcher;
307 #endif
308                 _BEGIN();
309
310                 /* initialize client */
311                 if (!g_thread_supported())
312                 {
313                         g_thread_init(NULL);
314                 }
315
316                 g_type_init();
317
318 #ifdef USE_GDBUS
319                 /* init default context */
320                 GError *error = NULL;
321
322                 proxy = smartcard_service_se_service_proxy_new_for_bus_sync(
323                         G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
324                         "org.tizen.SmartcardService",
325                         "/org/tizen/SmartcardService/SeService",
326                         NULL, &error);
327                 if (proxy == NULL)
328                 {
329                         _ERR("Can not create proxy : %s", error->message);
330                         g_error_free(error);
331                         return false;
332                 }
333
334                 g_signal_connect(proxy, "reader-inserted",
335                                 G_CALLBACK(&SEService::reader_inserted), this);
336
337                 g_signal_connect(proxy, "reader-removed",
338                                 G_CALLBACK(&SEService::reader_removed), this);
339
340                 /* request reader */
341                 smartcard_service_se_service_call_se_service(
342                         (SmartcardServiceSeService *)proxy,
343                         NULL,
344                         &SEService::se_service_cb,
345                         this);
346 #else
347                 clientDispatcher = &ClientDispatcher::getInstance();
348                 clientIPC = &ClientIPC::getInstance();
349
350                 clientIPC->setDispatcher(clientDispatcher);
351
352 #ifndef CLIENT_IPC_THREAD
353                 if (clientDispatcher->runDispatcherThread() == false)
354                 {
355                         _ERR("clientDispatcher->runDispatcherThread() failed");
356
357                         return result;
358                 }
359 #endif
360
361                 if (clientIPC->createConnectSocket() == false)
362                 {
363                         _ERR("clientIPC->createConnectSocket() failed");
364
365                         return result;
366                 }
367
368                 {
369                         /* send message to load se */
370                         Message msg;
371
372                         msg.message = Message::MSG_REQUEST_READERS;
373                         msg.error = getpid(); /* using error to pid */
374                         msg.caller = (void *)this;
375                         msg.userParam = context;
376
377                         result = clientIPC->sendMessage(msg);
378                 }
379 #endif
380                 _END();
381
382                 return result;
383         }
384
385         bool SEService::initialize(void *context, serviceConnected handler)
386                 throw(ErrorIO &, ErrorIllegalParameter &)
387         {
388                 if (context == NULL)
389                 {
390                         throw ErrorIllegalParameter(SCARD_ERROR_ILLEGAL_PARAM);
391                 }
392
393                 this->context = context;
394                 this->handler = handler;
395
396                 return _initialize();
397         }
398
399         bool SEService::initialize(void *context, SEServiceListener *listener)
400                 throw(ErrorIO &, ErrorIllegalParameter &)
401         {
402                 if (context == NULL)
403                 {
404                         throw ErrorIllegalParameter(SCARD_ERROR_ILLEGAL_PARAM);
405                 }
406
407                 this->context = context;
408                 this->listener = listener;
409
410                 return _initialize();
411         }
412
413 #ifdef USE_GDBUS
414         bool SEService::parseReaderInformation(GVariant *variant)
415         {
416                 Reader *reader = NULL;
417
418                 GVariantIter *iter;
419                 gsize count;
420                 guint handle;
421                 gchar *name;
422
423                 g_variant_get(variant, "a(us)", &iter);
424
425                 count = g_variant_iter_n_children(iter);
426                 while (g_variant_iter_loop(iter, "(us)", &handle, &name) == true)
427                 {
428                         /* add readers */
429                         reader = new Reader((void *)this->handle, name, GUINT_TO_POINTER(handle));
430                         if (reader == NULL)
431                         {
432                                 _ERR("alloc failed");
433                                 continue;
434                         }
435
436                         readers.push_back(reader);
437                 }
438
439                 g_variant_iter_free(iter);
440
441                 return true;
442         }
443 #endif
444         bool SEService::parseReaderInformation(unsigned int count,
445                 const ByteArray &data)
446         {
447                 size_t i;
448                 unsigned int offset = 0;
449                 unsigned int len = 0;
450                 void *handle = NULL;
451                 Reader *reader = NULL;
452                 char name[100];
453
454                 for (i = 0; i < count && offset < data.size(); i++)
455                 {
456                         memset(name, 0, sizeof(name));
457
458                         memcpy(&len, data.getBuffer(offset), sizeof(len));
459                         offset += sizeof(len);
460
461                         memcpy(name, data.getBuffer(offset), len);
462                         offset += len;
463
464                         memcpy(&handle, data.getBuffer(offset), sizeof(handle));
465                         offset += sizeof(handle);
466
467                         /* add readers */
468                         reader = new Reader(context, name, handle);
469                         if (reader == NULL)
470                         {
471                                 _ERR("alloc failed");
472                                 continue;
473                         }
474
475                         readers.push_back(reader);
476                 }
477
478                 return true;
479         }
480
481 #ifndef USE_GDBUS
482         bool SEService::dispatcherCallback(void *message)
483         {
484                 Message *msg = (Message *)message;
485                 SEService *service;
486                 bool result = false;
487
488                 _BEGIN();
489
490                 if (msg == NULL)
491                 {
492                         _ERR("message is null");
493                         return result;
494                 }
495
496                 service = (SEService *)msg->caller;
497
498                 switch (msg->message)
499                 {
500                 case Message::MSG_REQUEST_READERS :
501                         _INFO("[MSG_REQUEST_READERS]");
502
503                         service->connected = true;
504                         service->handle = (unsigned int)msg->param2;
505
506                         ClientDispatcher::getInstance().addSEService(service->handle, service);
507
508                         /* parse message data */
509                         service->parseReaderInformation(msg->param1, msg->data);
510
511                         /* call callback function */
512                         if (service->listener != NULL)
513                         {
514                                 service->listener->serviceConnected(service, service->context);
515                         }
516                         else if (service->handler != NULL)
517                         {
518                                 service->handler(service, service->context);
519                         }
520                         break;
521
522                 case Message::MSG_REQUEST_SHUTDOWN :
523                         _INFO("[MSG_REQUEST_SHUTDOWN]");
524
525                         if (msg->isSynchronousCall() == true) /* synchronized call */
526                         {
527                                 /* sync call */
528                                 service->syncLock();
529
530                                 /* copy result */
531 //                              service->error = msg->error;
532                                 service->signalCondition();
533                                 service->syncUnlock();
534                         }
535                         else
536                         {
537                                 /* Do nothing... */
538                         }
539                         break;
540
541                 case Message::MSG_NOTIFY_SE_INSERTED :
542                         {
543                                 Reader *reader = NULL;
544
545                                 _INFO("[MSG_NOTIFY_SE_INSERTED]");
546
547                                 /* add readers */
548                                 reader = new Reader(service->context,
549                                         (char *)msg->data.getBuffer(), (void *)msg->param1);
550                                 if (reader != NULL)
551                                 {
552                                         service->readers.push_back(reader);
553                                 }
554                                 else
555                                 {
556                                         _ERR("alloc failed");
557                                 }
558
559                                 if (service->listener != NULL)
560                                 {
561                                         service->listener->eventHandler(service,
562                                                 (char *)msg->data.getBuffer(), 1, service->context);
563                                 }
564                                 else
565                                 {
566                                         _DBG("listener is null");
567                                 }
568                         }
569                         break;
570
571                 case Message::MSG_NOTIFY_SE_REMOVED :
572                         {
573                                 size_t i;
574
575                                 _INFO("[MSG_NOTIFY_SE_REMOVED]");
576
577                                 for (i = 0; i < service->readers.size(); i++)
578                                 {
579                                         if (((Reader *)service->readers[i])->handle == (void *)msg->param1)
580                                         {
581                                                 ((Reader *)service->readers[i])->present = false;
582                                                 break;
583                                         }
584                                 }
585
586                                 if (service->listener != NULL)
587                                 {
588                                         service->listener->eventHandler(service,
589                                                 (char *)msg->data.getBuffer(), 2, service->context);
590                                 }
591                                 else
592                                 {
593                                         _DBG("listener is null");
594                                 }
595                         }
596                         break;
597
598                 case Message::MSG_OPERATION_RELEASE_CLIENT :
599                         _INFO("[MSG_OPERATION_RELEASE_CLIENT]");
600
601                         if (service->listener != NULL)
602                         {
603                                 service->listener->errorHandler(service, msg->error, service->context);
604
605                                 ClientDispatcher::getInstance().removeSEService(service->handle);
606                                 service->connected = false;
607                         }
608                         else
609                         {
610                                 _ERR("service->listener is null");
611                         }
612                         break;
613
614                 default :
615                         _DBG("unknown message [%s]", msg->toString().c_str());
616                         break;
617                 }
618
619                 delete msg;
620
621                 _END();
622
623                 return result;
624         }
625 #endif
626 } /* namespace smartcard_service_api */
627
628 /* export C API */
629 #define SE_SERVICE_EXTERN_BEGIN \
630         if (handle != NULL) \
631         { \
632                 SEService *service = (SEService *)handle;
633
634 #define SE_SERVICE_EXTERN_END \
635         } \
636         else \
637         { \
638                 _ERR("Invalid param"); \
639         }
640
641 using namespace smartcard_service_api;
642
643 EXTERN_API se_service_h se_service_create_instance(void *user_data, se_service_connected_cb callback)
644 {
645         SEService *service;
646
647         try
648         {
649                 service = new SEService(user_data, (serviceConnected)callback);
650         }
651         catch (...)
652         {
653                 service = NULL;
654         }
655
656         return (se_service_h)service;
657 }
658
659 EXTERN_API se_service_h se_service_create_instance_with_event_callback(void *user_data,
660         se_service_connected_cb connected, se_service_event_cb event, se_sesrvice_error_cb error)
661 {
662         SEService *service;
663
664         try
665         {
666                 service = new SEService(user_data, (serviceConnected)connected);
667         }
668         catch (...)
669         {
670                 service = NULL;
671         }
672
673         return (se_service_h)service;
674 }
675
676 EXTERN_API int se_service_get_readers_count(se_service_h handle)
677 {
678         int count = 0;
679
680         SE_SERVICE_EXTERN_BEGIN;
681
682         vector<ReaderHelper *> temp_readers;
683
684         temp_readers = service->getReaders();
685         count = temp_readers.size();
686
687         SE_SERVICE_EXTERN_END;
688
689         return count;
690 }
691
692 EXTERN_API bool se_service_get_readers(se_service_h handle, reader_h *readers, int *count)
693 {
694         bool result = false;
695
696         SE_SERVICE_EXTERN_BEGIN;
697
698         vector<ReaderHelper *> temp_readers;
699         size_t i;
700         int temp = 0;
701
702         temp_readers = service->getReaders();
703
704         for (i = 0; i < temp_readers.size() && i < (size_t)*count; i++)
705         {
706                 if (temp_readers[i]->isSecureElementPresent())
707                 {
708                         readers[i] = (reader_h)temp_readers[i];
709                         temp++;
710                 }
711         }
712         *count = temp;
713
714         SE_SERVICE_EXTERN_END;
715
716         return result;
717 }
718
719 EXTERN_API bool se_service_is_connected(se_service_h handle)
720 {
721         bool result = false;
722
723         SE_SERVICE_EXTERN_BEGIN;
724
725         result = service->isConnected();
726
727         SE_SERVICE_EXTERN_END;
728
729         return result;
730 }
731
732 EXTERN_API void se_service_shutdown(se_service_h handle)
733 {
734         SE_SERVICE_EXTERN_BEGIN;
735
736         service->shutdownSync();
737
738         SE_SERVICE_EXTERN_END;
739 }
740
741 EXTERN_API void se_service_destroy_instance(se_service_h handle)
742 {
743         SE_SERVICE_EXTERN_BEGIN;
744
745         delete service;
746
747         SE_SERVICE_EXTERN_END;
748 }