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