Fix problems
[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                                         ClientGDBus::getCookie(),
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                                         ClientGDBus::getCookie(),
276                                         GPOINTER_TO_UINT(context),
277                                         GPOINTER_TO_UINT(handle), NULL,
278                                         &ClientChannel::channel_close_cb, param);
279 #else
280                                 Message msg;
281                                 channelNum = -1;
282
283                                 /* send message to server */
284                                 msg.message = Message::MSG_REQUEST_CLOSE_CHANNEL;
285                                 msg.param1 = (unsigned long)handle;
286                                 msg.error = (unsigned long)context; /* using error to context */
287                                 msg.caller = (void *)this;
288                                 msg.callback = (void *)callback;
289                                 msg.userParam = userParam;
290
291                                 if (ClientIPC::getInstance().sendMessage(msg) == false)
292                                 {
293                                         _ERR("sendMessage failed");
294                                         result = SCARD_ERROR_IPC_FAILED;
295                                 }
296 #endif
297                         }
298                         else
299                         {
300                                 _ERR("unavailable channel");
301                                 result = SCARD_ERROR_ILLEGAL_STATE;
302                         }
303                 }
304
305                 return result;
306         }
307
308         int ClientChannel::transmitSync(const ByteArray &command, ByteArray &result)
309                 throw(ExceptionBase &, ErrorIO &, ErrorIllegalState &,
310                         ErrorIllegalParameter &, ErrorSecurity &)
311         {
312                 int rv = SCARD_ERROR_OK;
313
314                 if (getSession()->getReader()->isSecureElementPresent() == true)
315                 {
316 #ifdef USE_GDBUS
317                         GVariant *var_command = NULL, *var_response = NULL;
318                         GError *error = NULL;
319
320                         var_command = GDBusHelper::convertByteArrayToVariant(command);
321
322                         if (smartcard_service_channel_call_transmit_sync(
323                                 (SmartcardServiceChannel *)proxy,
324                                 ClientGDBus::getCookie(),
325                                 GPOINTER_TO_UINT(context),
326                                 GPOINTER_TO_UINT(handle),
327                                 var_command, &rv, &var_response,
328                                 NULL, &error) == true) {
329
330                                 if (rv == SCARD_ERROR_OK) {
331                                         GDBusHelper::convertVariantToByteArray(var_response, result);
332                                 } else {
333                                         _ERR("smartcard_service_session_call_get_atr_sync failed, [%d]", rv);
334                                         THROW_ERROR(rv);
335                                 }
336                         } else {
337                                 _ERR("smartcard_service_session_call_get_atr_sync failed, [%s]", error->message);
338                                 g_error_free(error);
339
340                                 throw ErrorIO(SCARD_ERROR_IPC_FAILED);
341                         }
342 #else
343                         Message msg;
344 #ifdef CLIENT_IPC_THREAD
345                         /* send message to server */
346                         msg.message = Message::MSG_REQUEST_TRANSMIT;
347                         msg.param1 = (unsigned long)handle;
348                         msg.param2 = 0;
349                         msg.data = command;
350                         msg.error = (unsigned long)context; /* using error to context */
351                         msg.caller = (void *)this;
352                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
353
354                         syncLock();
355                         if (ClientIPC::getInstance().sendMessage(msg) == true)
356                         {
357                                 rv = waitTimedCondition(0);
358                                 if (rv >= 0)
359                                 {
360                                         result = response;
361                                         rv = SCARD_ERROR_OK;
362                                 }
363                                 else
364                                 {
365                                         _ERR("timeout [%d]", rv);
366                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
367                                 }
368                         }
369                         else
370                         {
371                                 _ERR("sendMessage failed");
372                         }
373                         syncUnlock();
374
375                         if (this->error != SCARD_ERROR_OK)
376                         {
377                                 ThrowError::throwError(this->error);
378                         }
379 #endif
380 #endif
381                 }
382                 else
383                 {
384                         _ERR("unavailable channel");
385                         throw ErrorIllegalState(SCARD_ERROR_UNAVAILABLE);
386                 }
387
388                 return rv;
389         }
390
391         int ClientChannel::transmit(const ByteArray &command, transmitCallback callback, void *userParam)
392         {
393                 int result;
394
395                 if (getSession()->getReader()->isSecureElementPresent() == true)
396                 {
397 #ifdef USE_GDBUS
398                         GVariant *var_command;
399                         CallbackParam *param = new CallbackParam();
400
401                         param->instance = this;
402                         param->callback = (void *)callback;
403                         param->user_param = userParam;
404
405                         var_command = GDBusHelper::convertByteArrayToVariant(command);
406
407                         smartcard_service_channel_call_transmit(
408                                 (SmartcardServiceChannel *)proxy,
409                                 ClientGDBus::getCookie(),
410                                 GPOINTER_TO_UINT(context),
411                                 GPOINTER_TO_UINT(handle),
412                                 var_command, NULL,
413                                 &ClientChannel::channel_transmit_cb, param);
414
415                         result = SCARD_ERROR_OK;
416 #else
417                         Message msg;
418
419                         /* send message to server */
420                         msg.message = Message::MSG_REQUEST_TRANSMIT;
421                         msg.param1 = (unsigned long)handle;
422                         msg.param2 = 0;
423                         msg.data = command;
424                         msg.error = (unsigned long)context; /* using error to context */
425                         msg.caller = (void *)this;
426                         msg.callback = (void *)callback;
427                         msg.userParam = userParam;
428
429                         if (ClientIPC::getInstance().sendMessage(msg) == true)
430                         {
431                                 result = SCARD_ERROR_OK;
432                         }
433                         else
434                         {
435                                 _ERR("sendMessage failed");
436                                 result = SCARD_ERROR_IPC_FAILED;
437                         }
438 #endif
439                 }
440                 else
441                 {
442                         _ERR("unavailable channel");
443                         result = SCARD_ERROR_ILLEGAL_STATE;
444                 }
445
446                 return result;
447         }
448
449 #ifndef USE_GDBUS
450         bool ClientChannel::dispatcherCallback(void *message)
451         {
452                 Message *msg = (Message *)message;
453                 ClientChannel *channel = NULL;
454                 bool result = false;
455
456                 if (msg == NULL)
457                 {
458                         _ERR("message is null");
459                         return result;
460                 }
461
462                 channel = (ClientChannel *)msg->caller;
463
464                 switch (msg->message)
465                 {
466                 case Message::MSG_REQUEST_TRANSMIT :
467                         {
468                                 /* transmit result */
469                                 _INFO("MSG_REQUEST_TRANSMIT");
470
471                                 if (msg->isSynchronousCall() == true) /* synchronized call */
472                                 {
473                                         /* sync call */
474                                         channel->syncLock();
475
476                                         /* copy result */
477                                         channel->error = msg->error;
478                                         channel->response = msg->data;
479
480                                         channel->signalCondition();
481                                         channel->syncUnlock();
482                                 }
483                                 else if (msg->callback != NULL)
484                                 {
485                                         transmitCallback cb = (transmitCallback)msg->callback;
486
487                                         /* async call */
488                                         cb(msg->data.getBuffer(),
489                                                 msg->data.size(),
490                                                 msg->error,
491                                                 msg->userParam);
492                                 }
493                         }
494                         break;
495
496                 case Message::MSG_REQUEST_CLOSE_CHANNEL :
497                         {
498                                 _INFO("MSG_REQUEST_CLOSE_CHANNEL");
499
500                                 if (msg->isSynchronousCall() == true) /* synchronized call */
501                                 {
502                                         /* sync call */
503                                         channel->syncLock();
504
505                                         channel->error = msg->error;
506
507                                         channel->signalCondition();
508                                         channel->syncUnlock();
509                                 }
510                                 else if (msg->callback != NULL)
511                                 {
512                                         closeChannelCallback cb = (closeChannelCallback)msg->callback;
513
514                                         /* async call */
515                                         cb(msg->error, msg->userParam);
516                                 }
517                         }
518                         break;
519
520                 default:
521                         _DBG("Unknown message : %s", msg->toString().c_str());
522                         break;
523                 }
524
525                 delete msg;
526
527                 return result;
528         }
529 #endif /* USE_GDBUS */
530 } /* namespace smartcard_service_api */
531
532 /* export C API */
533 #define CHANNEL_EXTERN_BEGIN \
534         if (handle != NULL) \
535         { \
536                 ClientChannel *channel = (ClientChannel *)handle;
537
538 #define CHANNEL_EXTERN_END \
539         } \
540         else \
541         { \
542                 _ERR("Invalid param"); \
543         }
544
545 using namespace smartcard_service_api;
546
547 EXTERN_API int channel_close(channel_h handle, channel_close_cb callback, void *userParam)
548 {
549         int result = -1;
550
551         CHANNEL_EXTERN_BEGIN;
552         result = channel->close((closeChannelCallback)callback, userParam);
553         CHANNEL_EXTERN_END;
554
555         return result;
556 }
557
558 EXTERN_API int channel_transmit(channel_h handle, unsigned char *command,
559         unsigned int length, channel_transmit_cb callback, void *userParam)
560 {
561         int result = -1;
562
563         CHANNEL_EXTERN_BEGIN;
564         ByteArray temp;
565
566         temp.assign(command, length);
567         result = channel->transmit(temp, (transmitCallback)callback, userParam);
568         CHANNEL_EXTERN_END;
569
570         return result;
571 }
572
573 EXTERN_API void channel_close_sync(channel_h handle)
574 {
575 #ifdef CLIENT_IPC_THREAD
576         CHANNEL_EXTERN_BEGIN;
577         try
578         {
579                 channel->closeSync();
580         }
581         catch (...)
582         {
583         }
584         CHANNEL_EXTERN_END;
585 #endif
586 }
587
588 EXTERN_API int channel_transmit_sync(channel_h handle, unsigned char *command,
589         unsigned int cmd_len, unsigned char **response, unsigned int *resp_len)
590 {
591         int result = -1;
592
593 #ifdef CLIENT_IPC_THREAD
594         if (command == NULL || cmd_len == 0 || response == NULL || resp_len == NULL)
595                 return result;
596
597         CHANNEL_EXTERN_BEGIN;
598         ByteArray temp, resp;
599
600         temp.assign(command, cmd_len);
601
602         try
603         {
604                 result = channel->transmitSync(temp, resp);
605                 if (resp.size() > 0)
606                 {
607                         *resp_len = resp.size();
608                         *response = (unsigned char *)calloc(1, *resp_len);
609                         memcpy(*response, resp.getBuffer(), *resp_len);
610                 }
611         }
612         catch (...)
613         {
614                 result = -1;
615         }
616         CHANNEL_EXTERN_END;
617 #endif
618
619         return result;
620 }
621
622 EXTERN_API bool channel_is_basic_channel(channel_h handle)
623 {
624         bool result = false;
625
626         CHANNEL_EXTERN_BEGIN;
627         result = channel->isBasicChannel();
628         CHANNEL_EXTERN_END;
629
630         return result;
631 }
632
633 EXTERN_API bool channel_is_closed(channel_h handle)
634 {
635         bool result = false;
636
637         CHANNEL_EXTERN_BEGIN;
638         result = channel->isClosed();
639         CHANNEL_EXTERN_END;
640
641         return result;
642 }
643
644 EXTERN_API unsigned int channel_get_select_response_length(channel_h handle)
645 {
646         unsigned int result = 0;
647
648         CHANNEL_EXTERN_BEGIN;
649         result = channel->getSelectResponse().size();
650         CHANNEL_EXTERN_END;
651
652         return result;
653 }
654
655 EXTERN_API bool channel_get_select_response(channel_h handle,
656         unsigned char *buffer, unsigned int length)
657 {
658         bool result = false;
659
660         if (buffer == NULL || length == 0)
661         {
662                 return result;
663         }
664
665         CHANNEL_EXTERN_BEGIN;
666         ByteArray response;
667
668         response = channel->getSelectResponse();
669         if (response.size() > 0)
670         {
671                 memcpy(buffer, response.getBuffer(), MIN(length, response.size()));
672                 result = true;
673         }
674         CHANNEL_EXTERN_END;
675
676         return result;
677 }
678
679 EXTERN_API session_h channel_get_session(channel_h handle)
680 {
681         session_h session = NULL;
682
683         CHANNEL_EXTERN_BEGIN;
684         session = channel->getSession();
685         CHANNEL_EXTERN_END;
686
687         return session;
688 }
689
690 EXTERN_API void channel_destroy_instance(channel_h handle)
691 {
692         /* do nothing */
693 }