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