use gdbus
[platform/core/connectivity/smartcard-service.git] / client / ClientChannel.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 /* standard library header */
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #ifdef USE_GDBUS
22 #include <glib.h>
23 #endif
24
25 /* SLP library header */
26
27 /* local header */
28 #include "Debug.h"
29 #include "ClientChannel.h"
30 #include "ReaderHelper.h"
31 #include "APDUHelper.h"
32 #ifdef USE_GDBUS
33 #include "smartcard-service-gdbus.h"
34 #include "GDBusHelper.h"
35 #else
36 #include "Message.h"
37 #include "ClientIPC.h"
38 #endif
39
40 #ifndef EXTERN_API
41 #define EXTERN_API __attribute__((visibility("default")))
42 #endif
43
44 namespace smartcard_service_api
45 {
46         ClientChannel::ClientChannel(void *context, Session *session,
47                 int channelNum, ByteArray selectResponse, void *handle)
48                 : Channel(session)
49         {
50                 this->channelNum = -1;
51                 this->handle = NULL;
52                 this->context = NULL;
53
54                 if (handle == NULL)
55                 {
56                         _ERR("ClientIPC::getInstance() failed");
57
58                         return;
59                 }
60
61                 this->channelNum = channelNum;
62                 this->handle = handle;
63                 this->selectResponse = selectResponse;
64                 this->context = context;
65 #ifdef USE_GDBUS
66                 /* initialize client */
67                 if (!g_thread_supported())
68                 {
69                         g_thread_init(NULL);
70                 }
71
72                 g_type_init();
73
74                 /* init default context */
75                 GError *error = NULL;
76
77                 proxy = smartcard_service_channel_proxy_new_for_bus_sync(
78                         G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
79                         "org.tizen.SmartcardService",
80                         "/org/tizen/SmartcardService/Channel",
81                         NULL, &error);
82                 if (proxy == NULL)
83                 {
84                         _ERR("Can not create proxy : %s", error->message);
85                         g_error_free(error);
86                         return;
87                 }
88 #endif
89         }
90
91         ClientChannel::~ClientChannel()
92         {
93                 closeSync();
94         }
95
96 #ifdef USE_GDBUS
97         void ClientChannel::channel_transmit_cb(GObject *source_object,
98                 GAsyncResult *res, gpointer user_data)
99         {
100                 CallbackParam *param = (CallbackParam *)user_data;
101                 transmitCallback callback;
102                 gint result;
103                 GVariant *var_response;
104                 GError *error = NULL;
105                 ByteArray response;
106
107                 _INFO("MSG_REQUEST_TRANSMIT");
108
109                 if (param == NULL) {
110                         _ERR("null parameter!!!");
111                         return;
112                 }
113
114                 callback = (transmitCallback)param->callback;
115
116                 if (smartcard_service_channel_call_transmit_finish(
117                         SMARTCARD_SERVICE_CHANNEL(source_object),
118                         &result, &var_response, res, &error) == true) {
119                         if (result == SCARD_ERROR_OK) {
120                                 GDBusHelper::convertVariantToByteArray(var_response, response);
121                         } else {
122                                 _ERR("smartcard_service_channel_call_transmit failed, [%d]", result);
123                         }
124                 } else {
125                         _ERR("smartcard_service_channel_call_transmit failed, [%s]", error->message);
126                         g_error_free(error);
127
128                         result = SCARD_ERROR_IPC_FAILED;
129                 }
130
131                 if (callback != NULL) {
132                         callback(response.getBuffer(),
133                                 response.getLength(),
134                                 result, param->user_param);
135                 }
136
137                 delete param;
138         }
139
140         void ClientChannel::channel_close_cb(GObject *source_object,
141                 GAsyncResult *res, gpointer user_data)
142         {
143                 CallbackParam *param = (CallbackParam *)user_data;
144                 ClientChannel *channel;
145                 closeChannelCallback callback;
146                 gint result;
147                 GError *error = NULL;
148
149                 _INFO("MSG_REQUEST_CLOSE_CHANNEL");
150
151                 if (param == NULL) {
152                         _ERR("null parameter!!!");
153                         return;
154                 }
155
156                 channel = (ClientChannel *)param->instance;
157                 callback = (closeChannelCallback)param->callback;
158
159                 if (smartcard_service_channel_call_close_channel_finish(
160                         SMARTCARD_SERVICE_CHANNEL(source_object),
161                         &result, res, &error) == true) {
162                         if (result == SCARD_ERROR_OK) {
163                                 channel->channelNum = -1;
164                         } else {
165                                 _ERR("smartcard_service_channel_call_close_channel failed, [%d]", result);
166                         }
167                 } else {
168                         _ERR("smartcard_service_channel_call_close_channel failed, [%s]", error->message);
169                         g_error_free(error);
170
171                         result = SCARD_ERROR_IPC_FAILED;
172                 }
173
174                 if (callback != NULL) {
175                         callback(result, param->user_param);
176                 }
177
178                 delete param;
179         }
180 #endif
181         void ClientChannel::closeSync()
182                 throw(ExceptionBase &, ErrorIO &, ErrorSecurity &,
183                         ErrorIllegalState &, ErrorIllegalParameter &)
184         {
185                 if (isClosed() == false)
186                 {
187                         if (getSession()->getReader()->isSecureElementPresent() == true)
188                         {
189 #ifdef USE_GDBUS
190                                 gint ret;
191                                 GError *error = NULL;
192
193                                 if (proxy == NULL) {
194                                         _ERR("dbus proxy is not initialized yet");
195                                         throw ErrorIllegalState(SCARD_ERROR_NOT_INITIALIZED);
196                                 }
197
198                                 if (smartcard_service_channel_call_close_channel_sync(
199                                         (SmartcardServiceChannel *)proxy,
200                                         GPOINTER_TO_UINT(context),
201                                         GPOINTER_TO_UINT(handle),
202                                         &ret, NULL, &error) == true) {
203                                         if (ret != SCARD_ERROR_OK) {
204                                                 _ERR("smartcard_service_channel_call_close_channel_sync failed, [%d]", ret);
205                                                 THROW_ERROR(ret);
206                                         }
207                                 } else {
208                                         _ERR("smartcard_service_channel_call_close_channel_sync failed, [%s]", error->message);
209                                         g_error_free(error);
210
211                                         throw ErrorIO(SCARD_ERROR_IPC_FAILED);
212                                 }
213 #else
214                                 Message msg;
215                                 int rv;
216
217 #ifdef CLIENT_IPC_THREAD
218                                 /* send message to server */
219                                 msg.message = Message::MSG_REQUEST_CLOSE_CHANNEL;
220                                 msg.param1 = (unsigned long)handle;
221                                 msg.error = (unsigned long)context; /* using error to context */
222                                 msg.caller = (void *)this;
223                                 msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
224
225                                 syncLock();
226                                 if (ClientIPC::getInstance().sendMessage(&msg) == true)
227                                 {
228                                         rv = waitTimedCondition(0);
229                                         if (rv < 0)
230                                         {
231                                                 _ERR("timeout [%d]", rv);
232                                                 this->error = SCARD_ERROR_OPERATION_TIMEOUT;
233                                         }
234                                 }
235                                 else
236                                 {
237                                         _ERR("sendMessage failed");
238                                         this->error = SCARD_ERROR_IPC_FAILED;
239                                 }
240                                 syncUnlock();
241
242                                 channelNum = -1;
243
244                                 if (this->error != SCARD_ERROR_OK)
245                                 {
246                                         ThrowError::throwError(this->error);
247                                 }
248 #endif
249 #endif
250                         }
251                         else
252                         {
253                                 _INFO("unavailable channel");
254                         }
255                 }
256         }
257
258         int ClientChannel::close(closeChannelCallback callback, void *userParam)
259         {
260                 int result = SCARD_ERROR_OK;
261
262                 if (isClosed() == false)
263                 {
264                         if (getSession()->getReader()->isSecureElementPresent() == true)
265                         {
266 #ifdef USE_GDBUS
267                                 CallbackParam *param = new CallbackParam();
268
269                                 param->instance = this;
270                                 param->callback = (void *)callback;
271                                 param->user_param = userParam;
272
273                                 smartcard_service_channel_call_close_channel(
274                                         (SmartcardServiceChannel *)proxy,
275                                         GPOINTER_TO_UINT(context),
276                                         GPOINTER_TO_UINT(handle), NULL,
277                                         &ClientChannel::channel_close_cb, param);
278 #else
279                                 Message msg;
280                                 channelNum = -1;
281
282                                 /* send message to server */
283                                 msg.message = Message::MSG_REQUEST_CLOSE_CHANNEL;
284                                 msg.param1 = (unsigned long)handle;
285                                 msg.error = (unsigned long)context; /* using error to context */
286                                 msg.caller = (void *)this;
287                                 msg.callback = (void *)callback;
288                                 msg.userParam = userParam;
289
290                                 if (ClientIPC::getInstance().sendMessage(&msg) == false)
291                                 {
292                                         _ERR("sendMessage failed");
293                                         result = SCARD_ERROR_IPC_FAILED;
294                                 }
295 #endif
296                         }
297                         else
298                         {
299                                 _ERR("unavailable channel");
300                                 result = SCARD_ERROR_ILLEGAL_STATE;
301                         }
302                 }
303
304                 return result;
305         }
306
307         int ClientChannel::transmitSync(ByteArray command, ByteArray &result)
308                 throw(ExceptionBase &, ErrorIO &, ErrorIllegalState &,
309                         ErrorIllegalParameter &, ErrorSecurity &)
310         {
311                 int rv = SCARD_ERROR_OK;
312
313                 if (getSession()->getReader()->isSecureElementPresent() == true)
314                 {
315 #ifdef USE_GDBUS
316                         GVariant *var_command = NULL, *var_response = NULL;
317                         GError *error = NULL;
318
319                         var_command = GDBusHelper::convertByteArrayToVariant(command);
320
321                         if (smartcard_service_channel_call_transmit_sync(
322                                 (SmartcardServiceChannel *)proxy,
323                                 GPOINTER_TO_UINT(context),
324                                 GPOINTER_TO_UINT(handle),
325                                 var_command, &rv, &var_response,
326                                 NULL, &error) == true) {
327
328                                 if (rv == SCARD_ERROR_OK) {
329                                         GDBusHelper::convertVariantToByteArray(var_response, result);
330                                 } else {
331                                         _ERR("smartcard_service_session_call_get_atr_sync failed, [%d]", rv);
332                                         THROW_ERROR(rv);
333                                 }
334                         } else {
335                                 _ERR("smartcard_service_session_call_get_atr_sync failed, [%s]", error->message);
336                                 g_error_free(error);
337
338                                 throw ErrorIO(SCARD_ERROR_IPC_FAILED);
339                         }
340 #else
341                         Message msg;
342 #ifdef CLIENT_IPC_THREAD
343                         /* send message to server */
344                         msg.message = Message::MSG_REQUEST_TRANSMIT;
345                         msg.param1 = (unsigned long)handle;
346                         msg.param2 = 0;
347                         msg.data = command;
348                         msg.error = (unsigned long)context; /* using error to context */
349                         msg.caller = (void *)this;
350                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
351
352                         syncLock();
353                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
354                         {
355                                 rv = waitTimedCondition(0);
356                                 if (rv >= 0)
357                                 {
358                                         result = response;
359                                         rv = SCARD_ERROR_OK;
360                                 }
361                                 else
362                                 {
363                                         _ERR("timeout [%d]", rv);
364                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
365                                 }
366                         }
367                         else
368                         {
369                                 _ERR("sendMessage failed");
370                         }
371                         syncUnlock();
372
373                         if (this->error != SCARD_ERROR_OK)
374                         {
375                                 ThrowError::throwError(this->error);
376                         }
377 #endif
378 #endif
379                 }
380                 else
381                 {
382                         _ERR("unavailable channel");
383                         throw ErrorIllegalState(SCARD_ERROR_UNAVAILABLE);
384                 }
385
386                 return rv;
387         }
388
389         int ClientChannel::transmit(ByteArray command, transmitCallback callback, void *userParam)
390         {
391                 int result;
392
393                 if (getSession()->getReader()->isSecureElementPresent() == true)
394                 {
395 #ifdef USE_GDBUS
396                         GVariant *var_command;
397                         CallbackParam *param = new CallbackParam();
398
399                         param->instance = this;
400                         param->callback = (void *)callback;
401                         param->user_param = userParam;
402
403                         var_command = GDBusHelper::convertByteArrayToVariant(command);
404
405                         smartcard_service_channel_call_transmit(
406                                 (SmartcardServiceChannel *)proxy,
407                                 GPOINTER_TO_UINT(context),
408                                 GPOINTER_TO_UINT(handle),
409                                 var_command, NULL,
410                                 &ClientChannel::channel_close_cb, param);
411
412                         result = SCARD_ERROR_OK;
413 #else
414                         Message msg;
415
416                         /* send message to server */
417                         msg.message = Message::MSG_REQUEST_TRANSMIT;
418                         msg.param1 = (unsigned long)handle;
419                         msg.param2 = 0;
420                         msg.data = command;
421                         msg.error = (unsigned long)context; /* using error to context */
422                         msg.caller = (void *)this;
423                         msg.callback = (void *)callback;
424                         msg.userParam = userParam;
425
426                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
427                         {
428                                 result = SCARD_ERROR_OK;
429                         }
430                         else
431                         {
432                                 _ERR("sendMessage failed");
433                                 result = SCARD_ERROR_IPC_FAILED;
434                         }
435 #endif
436                 }
437                 else
438                 {
439                         _ERR("unavailable channel");
440                         result = SCARD_ERROR_ILLEGAL_STATE;
441                 }
442
443                 return result;
444         }
445
446 #ifndef USE_GDBUS
447         bool ClientChannel::dispatcherCallback(void *message)
448         {
449                 Message *msg = (Message *)message;
450                 ClientChannel *channel = NULL;
451                 bool result = false;
452
453                 if (msg == NULL)
454                 {
455                         _ERR("message is null");
456                         return result;
457                 }
458
459                 channel = (ClientChannel *)msg->caller;
460
461                 switch (msg->message)
462                 {
463                 case Message::MSG_REQUEST_TRANSMIT :
464                         {
465                                 /* transmit result */
466                                 _INFO("MSG_REQUEST_TRANSMIT");
467
468                                 if (msg->isSynchronousCall() == true) /* synchronized call */
469                                 {
470                                         /* sync call */
471                                         channel->syncLock();
472
473                                         /* copy result */
474                                         channel->error = msg->error;
475                                         channel->response = msg->data;
476
477                                         channel->signalCondition();
478                                         channel->syncUnlock();
479                                 }
480                                 else if (msg->callback != NULL)
481                                 {
482                                         transmitCallback cb = (transmitCallback)msg->callback;
483
484                                         /* async call */
485                                         cb(msg->data.getBuffer(), msg->data.getLength(), msg->error, msg->userParam);
486                                 }
487                         }
488                         break;
489
490                 case Message::MSG_REQUEST_CLOSE_CHANNEL :
491                         {
492                                 _INFO("MSG_REQUEST_CLOSE_CHANNEL");
493
494                                 if (msg->isSynchronousCall() == true) /* synchronized call */
495                                 {
496                                         /* sync call */
497                                         channel->syncLock();
498
499                                         channel->error = msg->error;
500
501                                         channel->signalCondition();
502                                         channel->syncUnlock();
503                                 }
504                                 else if (msg->callback != NULL)
505                                 {
506                                         closeChannelCallback cb = (closeChannelCallback)msg->callback;
507
508                                         /* async call */
509                                         cb(msg->error, msg->userParam);
510                                 }
511                         }
512                         break;
513
514                 default:
515                         _DBG("Unknown message : %s", msg->toString());
516                         break;
517                 }
518
519                 delete msg;
520
521                 return result;
522         }
523 #endif /* USE_GDBUS */
524 } /* namespace smartcard_service_api */
525
526 /* export C API */
527 #define CHANNEL_EXTERN_BEGIN \
528         if (handle != NULL) \
529         { \
530                 ClientChannel *channel = (ClientChannel *)handle;
531
532 #define CHANNEL_EXTERN_END \
533         } \
534         else \
535         { \
536                 _ERR("Invalid param"); \
537         }
538
539 using namespace smartcard_service_api;
540
541 EXTERN_API int channel_close(channel_h handle, channel_close_cb callback, void *userParam)
542 {
543         int result = -1;
544
545         CHANNEL_EXTERN_BEGIN;
546         result = channel->close((closeChannelCallback)callback, userParam);
547         CHANNEL_EXTERN_END;
548
549         return result;
550 }
551
552 EXTERN_API int channel_transmit(channel_h handle, unsigned char *command,
553         unsigned int length, channel_transmit_cb callback, void *userParam)
554 {
555         int result = -1;
556
557         CHANNEL_EXTERN_BEGIN;
558         ByteArray temp;
559
560         temp.setBuffer(command, length);
561         result = channel->transmit(temp, (transmitCallback)callback, userParam);
562         CHANNEL_EXTERN_END;
563
564         return result;
565 }
566
567 EXTERN_API void channel_close_sync(channel_h handle)
568 {
569 #ifdef CLIENT_IPC_THREAD
570         CHANNEL_EXTERN_BEGIN;
571         try
572         {
573                 channel->closeSync();
574         }
575         catch (...)
576         {
577         }
578         CHANNEL_EXTERN_END;
579 #endif
580 }
581
582 EXTERN_API int channel_transmit_sync(channel_h handle, unsigned char *command,
583         unsigned int cmd_len, unsigned char **response, unsigned int *resp_len)
584 {
585         int result = -1;
586
587 #ifdef CLIENT_IPC_THREAD
588         if (command == NULL || cmd_len == 0 || response == NULL || resp_len == NULL)
589                 return result;
590
591         CHANNEL_EXTERN_BEGIN;
592         ByteArray temp, resp;
593
594         temp.setBuffer(command, cmd_len);
595
596         try
597         {
598                 result = channel->transmitSync(temp, resp);
599                 if (resp.getLength() > 0)
600                 {
601                         *resp_len = resp.getLength();
602                         *response = (unsigned char *)calloc(1, *resp_len);
603                         memcpy(*response, resp.getBuffer(), *resp_len);
604                 }
605         }
606         catch (...)
607         {
608                 result = -1;
609         }
610         CHANNEL_EXTERN_END;
611 #endif
612
613         return result;
614 }
615
616 EXTERN_API bool channel_is_basic_channel(channel_h handle)
617 {
618         bool result = false;
619
620         CHANNEL_EXTERN_BEGIN;
621         result = channel->isBasicChannel();
622         CHANNEL_EXTERN_END;
623
624         return result;
625 }
626
627 EXTERN_API bool channel_is_closed(channel_h handle)
628 {
629         bool result = false;
630
631         CHANNEL_EXTERN_BEGIN;
632         result = channel->isClosed();
633         CHANNEL_EXTERN_END;
634
635         return result;
636 }
637
638 EXTERN_API unsigned int channel_get_select_response_length(channel_h handle)
639 {
640         unsigned int result = 0;
641
642         CHANNEL_EXTERN_BEGIN;
643         result = channel->getSelectResponse().getLength();
644         CHANNEL_EXTERN_END;
645
646         return result;
647 }
648
649 EXTERN_API bool channel_get_select_response(channel_h handle,
650         unsigned char *buffer, unsigned int length)
651 {
652         bool result = false;
653
654         if (buffer == NULL || length == 0)
655         {
656                 return result;
657         }
658
659         CHANNEL_EXTERN_BEGIN;
660         ByteArray response;
661
662         response = channel->getSelectResponse();
663         if (response.getLength() > 0)
664         {
665                 memcpy(buffer, response.getBuffer(), MIN(length, response.getLength()));
666                 result = true;
667         }
668         CHANNEL_EXTERN_END;
669
670         return result;
671 }
672
673 EXTERN_API session_h channel_get_session(channel_h handle)
674 {
675         session_h session = NULL;
676
677         CHANNEL_EXTERN_BEGIN;
678         session = channel->getSession();
679         CHANNEL_EXTERN_END;
680
681         return session;
682 }
683
684 EXTERN_API void channel_destroy_instance(channel_h handle)
685 {
686         /* do nothing */
687 }