Minor change
[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, const 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.size(),
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(const 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(const 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(),
486                                                 msg->data.size(),
487                                                 msg->error,
488                                                 msg->userParam);
489                                 }
490                         }
491                         break;
492
493                 case Message::MSG_REQUEST_CLOSE_CHANNEL :
494                         {
495                                 _INFO("MSG_REQUEST_CLOSE_CHANNEL");
496
497                                 if (msg->isSynchronousCall() == true) /* synchronized call */
498                                 {
499                                         /* sync call */
500                                         channel->syncLock();
501
502                                         channel->error = msg->error;
503
504                                         channel->signalCondition();
505                                         channel->syncUnlock();
506                                 }
507                                 else if (msg->callback != NULL)
508                                 {
509                                         closeChannelCallback cb = (closeChannelCallback)msg->callback;
510
511                                         /* async call */
512                                         cb(msg->error, msg->userParam);
513                                 }
514                         }
515                         break;
516
517                 default:
518                         _DBG("Unknown message : %s", msg->toString().c_str());
519                         break;
520                 }
521
522                 delete msg;
523
524                 return result;
525         }
526 #endif /* USE_GDBUS */
527 } /* namespace smartcard_service_api */
528
529 /* export C API */
530 #define CHANNEL_EXTERN_BEGIN \
531         if (handle != NULL) \
532         { \
533                 ClientChannel *channel = (ClientChannel *)handle;
534
535 #define CHANNEL_EXTERN_END \
536         } \
537         else \
538         { \
539                 _ERR("Invalid param"); \
540         }
541
542 using namespace smartcard_service_api;
543
544 EXTERN_API int channel_close(channel_h handle, channel_close_cb callback, void *userParam)
545 {
546         int result = -1;
547
548         CHANNEL_EXTERN_BEGIN;
549         result = channel->close((closeChannelCallback)callback, userParam);
550         CHANNEL_EXTERN_END;
551
552         return result;
553 }
554
555 EXTERN_API int channel_transmit(channel_h handle, unsigned char *command,
556         unsigned int length, channel_transmit_cb callback, void *userParam)
557 {
558         int result = -1;
559
560         CHANNEL_EXTERN_BEGIN;
561         ByteArray temp;
562
563         temp.assign(command, length);
564         result = channel->transmit(temp, (transmitCallback)callback, userParam);
565         CHANNEL_EXTERN_END;
566
567         return result;
568 }
569
570 EXTERN_API void channel_close_sync(channel_h handle)
571 {
572 #ifdef CLIENT_IPC_THREAD
573         CHANNEL_EXTERN_BEGIN;
574         try
575         {
576                 channel->closeSync();
577         }
578         catch (...)
579         {
580         }
581         CHANNEL_EXTERN_END;
582 #endif
583 }
584
585 EXTERN_API int channel_transmit_sync(channel_h handle, unsigned char *command,
586         unsigned int cmd_len, unsigned char **response, unsigned int *resp_len)
587 {
588         int result = -1;
589
590 #ifdef CLIENT_IPC_THREAD
591         if (command == NULL || cmd_len == 0 || response == NULL || resp_len == NULL)
592                 return result;
593
594         CHANNEL_EXTERN_BEGIN;
595         ByteArray temp, resp;
596
597         temp.assign(command, cmd_len);
598
599         try
600         {
601                 result = channel->transmitSync(temp, resp);
602                 if (resp.size() > 0)
603                 {
604                         *resp_len = resp.size();
605                         *response = (unsigned char *)calloc(1, *resp_len);
606                         memcpy(*response, resp.getBuffer(), *resp_len);
607                 }
608         }
609         catch (...)
610         {
611                 result = -1;
612         }
613         CHANNEL_EXTERN_END;
614 #endif
615
616         return result;
617 }
618
619 EXTERN_API bool channel_is_basic_channel(channel_h handle)
620 {
621         bool result = false;
622
623         CHANNEL_EXTERN_BEGIN;
624         result = channel->isBasicChannel();
625         CHANNEL_EXTERN_END;
626
627         return result;
628 }
629
630 EXTERN_API bool channel_is_closed(channel_h handle)
631 {
632         bool result = false;
633
634         CHANNEL_EXTERN_BEGIN;
635         result = channel->isClosed();
636         CHANNEL_EXTERN_END;
637
638         return result;
639 }
640
641 EXTERN_API unsigned int channel_get_select_response_length(channel_h handle)
642 {
643         unsigned int result = 0;
644
645         CHANNEL_EXTERN_BEGIN;
646         result = channel->getSelectResponse().size();
647         CHANNEL_EXTERN_END;
648
649         return result;
650 }
651
652 EXTERN_API bool channel_get_select_response(channel_h handle,
653         unsigned char *buffer, unsigned int length)
654 {
655         bool result = false;
656
657         if (buffer == NULL || length == 0)
658         {
659                 return result;
660         }
661
662         CHANNEL_EXTERN_BEGIN;
663         ByteArray response;
664
665         response = channel->getSelectResponse();
666         if (response.size() > 0)
667         {
668                 memcpy(buffer, response.getBuffer(), MIN(length, response.size()));
669                 result = true;
670         }
671         CHANNEL_EXTERN_END;
672
673         return result;
674 }
675
676 EXTERN_API session_h channel_get_session(channel_h handle)
677 {
678         session_h session = NULL;
679
680         CHANNEL_EXTERN_BEGIN;
681         session = channel->getSession();
682         CHANNEL_EXTERN_END;
683
684         return session;
685 }
686
687 EXTERN_API void channel_destroy_instance(channel_h handle)
688 {
689         /* do nothing */
690 }