Fix error handling
[platform/core/connectivity/smartcard-service.git] / client / Session.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* standard library header */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22
23 /* SLP library header */
24
25 /* local header */
26 #include "Debug.h"
27 #include "Session.h"
28 #include "Reader.h"
29 #include "ClientChannel.h"
30 #include "ClientIPC.h"
31
32 #ifndef EXTERN_API
33 #define EXTERN_API __attribute__((visibility("default")))
34 #endif
35
36 namespace smartcard_service_api
37 {
38         Session::Session(void *context, Reader *reader, void *handle) :
39                 SessionHelper(reader)
40         {
41                 this->context = NULL;
42
43                 if (context == NULL || handle == NULL)
44                 {
45                         SCARD_DEBUG_ERR("handle is null");
46
47                         return;
48                 }
49
50                 this->context = context;
51                 this->handle = handle;
52                 closed = false;
53         }
54
55         Session::~Session()
56         {
57                 size_t i;
58
59                 closeSync();
60
61                 for (i = 0; i < channels.size(); i++)
62                 {
63                         delete (ClientChannel *)channels[i];
64                 }
65
66                 channels.clear();
67         }
68
69         void Session::closeChannels() throw (ErrorIO &, ErrorIllegalState &)
70         {
71                 size_t i;
72
73                 for (i = 0; i < channels.size(); i++)
74                 {
75                         channels[i]->closeSync();
76                 }
77         }
78
79         ByteArray Session::getATRSync()
80                 throw (ExceptionBase &, ErrorIO &, ErrorSecurity &,
81                         ErrorIllegalState &, ErrorIllegalParameter &)
82         {
83                 ByteArray result;
84                 if (getReader()->isSecureElementPresent() == true)
85                 {
86                         if (atr.isEmpty() == true)
87                         {
88                                 Message msg;
89                                 int rv;
90
91 #ifdef CLIENT_IPC_THREAD
92                                 /* request channel handle from server */
93                                 msg.message = Message::MSG_REQUEST_GET_ATR;
94                                 msg.param1 = (unsigned long)handle;
95                                 msg.error = (unsigned long)context; /* using error to context */
96                                 msg.caller = (void *)this;
97                                 msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
98
99                                 syncLock();
100                                 if (ClientIPC::getInstance().sendMessage(&msg) == true)
101                                 {
102                                         rv = waitTimedCondition(0);
103                                         if (rv != 0)
104                                         {
105                                                 SCARD_DEBUG_ERR("time over");
106                                                 this->error = SCARD_ERROR_OPERATION_TIMEOUT;
107                                         }
108                                 }
109                                 else
110                                 {
111                                         SCARD_DEBUG_ERR("sendMessage failed");
112                                         this->error = SCARD_ERROR_IPC_FAILED;
113                                 }
114                                 syncUnlock();
115
116                                 if (this->error != SCARD_ERROR_OK)
117                                 {
118                                         ThrowError::throwError(this->error);
119                                 }
120 #endif
121                         }
122
123                         result = atr;
124                 }
125                 else
126                 {
127                         SCARD_DEBUG_ERR("unavailable session");
128                         throw ErrorIllegalState(SCARD_ERROR_UNAVAILABLE);
129                 }
130
131                 return result;
132         }
133
134         int Session::getATR(getATRCallback callback, void *userData)
135         {
136                 int result;
137
138                 if (getReader()->isSecureElementPresent() == true)
139                 {
140                         if (atr.isEmpty() == true)
141                         {
142                                 Message msg;
143
144
145                         /* request channel handle from server */
146                                 msg.message = Message::MSG_REQUEST_GET_ATR;
147                                 msg.param1 = (unsigned long)handle;
148                                 msg.error = (unsigned long)context; /* using error to context */
149                                 msg.caller = (void *)this;
150                                 msg.callback = (void *)callback;
151                                 msg.userParam = userData;
152
153                                 if (ClientIPC::getInstance().sendMessage(&msg) == true)
154                                 {
155                                         result = SCARD_ERROR_OK;
156                                 }
157                                 else
158                                 {
159                                         result = SCARD_ERROR_IPC_FAILED;
160                                 }
161                         }
162                         else
163                         {
164                                 result = SCARD_ERROR_OK;
165
166                                 /* TODO : invoke callback directly */
167                                 callback(atr.getBuffer(), atr.getLength(), 0, userData);
168                         }
169                 }
170                 else
171                 {
172                         SCARD_DEBUG_ERR("unavailable session");
173                         result = SCARD_ERROR_ILLEGAL_STATE;
174                 }
175
176                 return result;
177         }
178
179         void Session::closeSync()
180                 throw (ExceptionBase &, ErrorIO &, ErrorSecurity &,
181                         ErrorIllegalState &, ErrorIllegalParameter &)
182         {
183                 Message msg;
184                 int rv;
185
186 #ifdef CLIENT_IPC_THREAD
187                 if (isClosed() == false)
188                 {
189                         closed = true;
190                         closeChannels();
191
192                         /* request channel handle from server */
193                         msg.message = Message::MSG_REQUEST_CLOSE_SESSION;
194                         msg.param1 = (unsigned long)handle;
195                         msg.error = (unsigned long)context; /* using error to context */
196                         msg.caller = (void *)this;
197                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
198
199                         syncLock();
200                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
201                         {
202                                 rv = waitTimedCondition(0);
203
204                                 if (rv != 0)
205                                 {
206                                         SCARD_DEBUG_ERR("time over");
207                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
208                                 }
209                         }
210                         else
211                         {
212                                 SCARD_DEBUG_ERR("sendMessage failed");
213                                 this->error = SCARD_ERROR_IPC_FAILED;
214                         }
215                         syncUnlock();
216
217                         if (this->error != SCARD_ERROR_OK)
218                         {
219                                 ThrowError::throwError(this->error);
220                         }
221                 }
222 #endif
223         }
224
225         int Session::close(closeSessionCallback callback, void *userData)
226         {
227                 int result = SCARD_ERROR_OK;
228                 Message msg;
229
230                 if (isClosed() == false)
231                 {
232                         closed = true;
233                         closeChannels();
234
235                         /* request channel handle from server */
236                         msg.message = Message::MSG_REQUEST_CLOSE_SESSION;
237                         msg.param1 = (unsigned long)handle;
238                         msg.error = (unsigned long)context; /* using error to context */
239                         msg.caller = (void *)this;
240                         msg.callback = (void *)callback;
241                         msg.userParam = userData;
242
243                         if (ClientIPC::getInstance().sendMessage(&msg) == false)
244                         {
245                                 result = SCARD_ERROR_IPC_FAILED;
246                         }
247                 }
248
249                 return result;
250         }
251
252         unsigned int Session::getChannelCountSync()
253         {
254                 channelCount = -1;
255
256                 if (getReader()->isSecureElementPresent() == true)
257                 {
258                         Message msg;
259                         int rv;
260
261
262 #ifdef CLIENT_IPC_THREAD
263                         /* request channel handle from server */
264                         msg.message = Message::MSG_REQUEST_GET_CHANNEL_COUNT;
265                         msg.param1 = (unsigned long)handle;
266                         msg.error = (unsigned long)context; /* using error to context */
267                         msg.caller = (void *)this;
268                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
269
270                         channelCount = -1;
271
272                         syncLock();
273                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
274                         {
275                                 rv = waitTimedCondition(0);
276                                 if (rv != 0)
277                                 {
278                                         SCARD_DEBUG_ERR("time over");
279                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
280                                 }
281                         }
282                         else
283                         {
284                                 SCARD_DEBUG_ERR("sendMessage failed");
285                                 this->error = SCARD_ERROR_IPC_FAILED;
286                         }
287                         syncUnlock();
288
289                         if (this->error != SCARD_ERROR_OK)
290                         {
291                                 ThrowError::throwError(this->error);
292                         }
293 #endif
294                 }
295                 else
296                 {
297                         SCARD_DEBUG_ERR("unavailable session");
298                         throw ErrorIllegalState(SCARD_ERROR_UNAVAILABLE);
299                 }
300
301                 return channelCount;
302         }
303
304         int Session::getChannelCount(getChannelCountCallback callback, void *userData)
305         {
306                 int result;
307
308                 if (getReader()->isSecureElementPresent() == true)
309                 {
310                         Message msg;
311
312
313                         msg.message = Message::MSG_REQUEST_GET_CHANNEL_COUNT;
314                         msg.param1 = (unsigned long)handle;
315                         msg.error = (unsigned long)context; /* using error to context */
316                         msg.caller = (void *)this;
317                         msg.callback = (void *)callback;
318                         msg.userParam = userData;
319
320                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
321                         {
322                                 result = SCARD_ERROR_OK;
323                         }
324                         else
325                         {
326                                 result = SCARD_ERROR_IPC_FAILED;
327                         }
328                 }
329                 else
330                 {
331                         SCARD_DEBUG_ERR("unavailable session");
332                         result = SCARD_ERROR_ILLEGAL_STATE;
333                 }
334
335                 return result;
336         }
337
338         Channel *Session::openChannelSync(int id, ByteArray aid)
339                 throw (ExceptionBase &, ErrorIO &, ErrorIllegalState &,
340                         ErrorIllegalParameter &, ErrorSecurity &)
341         {
342                 openedChannel = NULL;
343
344                 if (getReader()->isSecureElementPresent() == true)
345                 {
346                         Message msg;
347                         int rv;
348
349 #ifdef CLIENT_IPC_THREAD
350                         /* request channel handle from server */
351                         msg.message = Message::MSG_REQUEST_OPEN_CHANNEL;
352                         msg.param1 = id;
353                         msg.param2 = (unsigned long)handle;
354                         msg.data = aid;
355                         msg.error = (unsigned long)context; /* using error to context */
356                         msg.caller = (void *)this;
357                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
358
359                         syncLock();
360                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
361                         {
362                                 rv = waitTimedCondition(0);
363                                 if (rv != 0)
364                                 {
365                                         SCARD_DEBUG_ERR("time over");
366                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
367                                 }
368                         }
369                         else
370                         {
371                                 SCARD_DEBUG_ERR("sendMessage failed");
372                                 this->error = SCARD_ERROR_IPC_FAILED;
373                         }
374                         syncUnlock();
375 #endif
376                         if (this->error != SCARD_ERROR_OK)
377                         {
378                                 ThrowError::throwError(this->error);
379                         }
380                 }
381                 else
382                 {
383                         SCARD_DEBUG_ERR("unavailable session");
384                         throw ErrorIllegalState(SCARD_ERROR_UNAVAILABLE);
385                 }
386
387                 return (Channel *)openedChannel;
388         }
389
390         int Session::openChannel(int id, ByteArray aid, openChannelCallback callback, void *userData)
391         {
392                 int result;
393
394                 if (getReader()->isSecureElementPresent() == true)
395                 {
396                         Message msg;
397
398                         /* request channel handle from server */
399                         msg.message = Message::MSG_REQUEST_OPEN_CHANNEL;
400                         msg.param1 = id;
401                         msg.param2 = (unsigned long)handle;
402                         msg.data = aid;
403                         msg.error = (unsigned long)context; /* using error to context */
404                         msg.caller = (void *)this;
405                         msg.callback = (void *)callback;
406                         msg.userParam = userData;
407
408                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
409                         {
410                                 result = SCARD_ERROR_OK;
411                         }
412                         else
413                         {
414                                 result = SCARD_ERROR_IPC_FAILED;
415                         }
416                 }
417                 else
418                 {
419                         SCARD_DEBUG_ERR("unavailable session");
420                         result = SCARD_ERROR_ILLEGAL_STATE;
421                 }
422
423                 return result;
424         }
425
426         Channel *Session::openBasicChannelSync(ByteArray aid)
427                 throw (ErrorIO &, ErrorIllegalState &, ErrorIllegalParameter &, ErrorSecurity &)
428         {
429                 return openChannelSync(0, aid);
430         }
431
432         Channel *Session::openBasicChannelSync(unsigned char *aid, unsigned int length)
433                 throw (ErrorIO &, ErrorIllegalState &, ErrorIllegalParameter &, ErrorSecurity &)
434         {
435                 return openBasicChannelSync(ByteArray(aid, length));
436         }
437
438         int Session::openBasicChannel(ByteArray aid, openChannelCallback callback, void *userData)
439         {
440                 return openChannel(0, aid, callback, userData);
441         }
442
443         int Session::openBasicChannel(unsigned char *aid, unsigned int length,
444                 openChannelCallback callback, void *userData)
445         {
446                 return openBasicChannel(ByteArray(aid, length), callback, userData);
447         }
448
449         Channel *Session::openLogicalChannelSync(ByteArray aid)
450                 throw (ErrorIO &, ErrorIllegalState &, ErrorIllegalParameter &, ErrorSecurity &)
451         {
452                 return openChannelSync(1, aid);
453         }
454
455         Channel *Session::openLogicalChannelSync(unsigned char *aid, unsigned int length)
456                 throw (ErrorIO &, ErrorIllegalState &, ErrorIllegalParameter &, ErrorSecurity &)
457         {
458                 return openLogicalChannelSync(ByteArray(aid, length));
459         }
460
461         int Session::openLogicalChannel(ByteArray aid, openChannelCallback callback, void *userData)
462         {
463                 return openChannel(1, aid, callback, userData);
464         }
465
466         int Session::openLogicalChannel(unsigned char *aid, unsigned int length,
467                 openChannelCallback callback, void *userData)
468         {
469                 return openLogicalChannel(ByteArray(aid, length), callback, userData);
470         }
471
472         bool Session::dispatcherCallback(void *message)
473         {
474                 Message *msg = (Message *)message;
475                 Session *session = NULL;
476                 bool result = false;
477
478                 if (msg == NULL)
479                 {
480                         SCARD_DEBUG_ERR("message is null");
481                         return result;
482                 }
483
484                 session = (Session *)msg->caller;
485
486                 switch (msg->message)
487                 {
488                 case Message::MSG_REQUEST_OPEN_CHANNEL :
489                         {
490                                 Channel *channel = NULL;
491
492                                 SCARD_DEBUG("MSG_REQUEST_OPEN_CHANNEL");
493
494                                 if (msg->param1 != 0)
495                                 {
496                                         /* create new instance of channel */
497                                         channel = new ClientChannel(session->context,
498                                                 session, msg->param2, msg->data, (void *)msg->param1);
499                                         if (channel != NULL)
500                                         {
501                                                 session->channels.push_back(channel);
502                                         }
503                                         else
504                                         {
505                                                 SCARD_DEBUG_ERR("alloc failed");
506
507                                                 msg->error = SCARD_ERROR_OUT_OF_MEMORY;
508                                         }
509                                 }
510
511                                 if (msg->isSynchronousCall() == true) /* synchronized call */
512                                 {
513                                         /* sync call */
514                                         session->syncLock();
515
516                                         /* copy result */
517                                         session->error = msg->error;
518                                         session->openedChannel = channel;
519
520                                         session->signalCondition();
521                                         session->syncUnlock();
522                                 }
523                                 else if (msg->callback != NULL)
524                                 {
525                                         openChannelCallback cb = (openChannelCallback)msg->callback;
526
527                                         /* async call */
528                                         cb(channel, msg->error, msg->userParam);
529                                 }
530                         }
531                         break;
532
533                 case Message::MSG_REQUEST_GET_ATR :
534                         {
535                                 SCARD_DEBUG("MSG_REQUEST_GET_ATR");
536
537                                 if (msg->isSynchronousCall() == true) /* synchronized call */
538                                 {
539                                         /* sync call */
540                                         session->syncLock();
541
542                                         session->error = msg->error;
543                                         session->atr = msg->data;
544
545                                         session->signalCondition();
546                                         session->syncUnlock();
547                                 }
548                                 else if (msg->callback != NULL)
549                                 {
550                                         getATRCallback cb = (getATRCallback)msg->callback;
551
552                                         /* async call */
553                                         cb(msg->data.getBuffer(), msg->data.getLength(), msg->error, msg->userParam);
554                                 }
555                         }
556                         break;
557
558                 case Message::MSG_REQUEST_CLOSE_SESSION :
559                         {
560                                 SCARD_DEBUG("MSG_REQUEST_CLOSE_SESSION");
561
562                                 if (msg->isSynchronousCall() == true) /* synchronized call */
563                                 {
564                                         /* sync call */
565                                         session->syncLock();
566
567                                         session->error = msg->error;
568
569                                         session->signalCondition();
570                                         session->syncUnlock();
571                                 }
572                                 else if (msg->callback != NULL)
573                                 {
574                                         closeSessionCallback cb = (closeSessionCallback)msg->callback;
575
576                                         /* async call */
577                                         cb(msg->error, msg->userParam);
578                                 }
579                         }
580                         break;
581
582                 case Message::MSG_REQUEST_GET_CHANNEL_COUNT :
583                         {
584                                 SCARD_DEBUG("MSG_REQUEST_GET_CHANNEL_COUNT");
585
586                                 if (msg->isSynchronousCall() == true) /* synchronized call */
587                                 {
588                                         /* sync call */
589                                         session->syncLock();
590
591                                         session->error = msg->error;
592                                         session->channelCount = msg->param1;
593
594                                         session->signalCondition();
595                                         session->syncUnlock();
596                                 }
597                                 else if (msg->callback != NULL)
598                                 {
599                                         getChannelCountCallback cb = (getChannelCountCallback)msg->callback;
600
601                                         /* async call */
602                                         cb(msg->param1, msg->error, msg->userParam);
603                                 }
604                         }
605                         break;
606
607                 default :
608                         SCARD_DEBUG("unknown message : %s", msg->toString());
609                         break;
610                 }
611
612                 return result;
613         }
614 } /* namespace smartcard_service_api */
615
616 /* export C API */
617 #define SESSION_EXTERN_BEGIN \
618         if (handle != NULL) \
619         { \
620                 Session *session = (Session *)handle;
621
622 #define SESSION_EXTERN_END \
623         } \
624         else \
625         { \
626                 SCARD_DEBUG_ERR("Invalid param"); \
627         }
628
629 using namespace smartcard_service_api;
630
631 EXTERN_API reader_h session_get_reader(session_h handle)
632 {
633         reader_h reader = NULL;
634
635         SESSION_EXTERN_BEGIN;
636                 reader = session->getReader();
637         SESSION_EXTERN_END;
638
639         return reader;
640 }
641
642 EXTERN_API int session_get_atr(session_h handle, session_get_atr_cb callback, void *userData)
643 {
644         int result = -1;
645
646         SESSION_EXTERN_BEGIN;
647                 result = session->getATR((getATRCallback)callback, userData);
648         SESSION_EXTERN_END;
649
650         return result;
651 }
652
653 EXTERN_API int session_close(session_h handle, session_close_session_cb callback, void *userData)
654 {
655         int result = -1;
656
657         SESSION_EXTERN_BEGIN;
658                 result = session->close((closeSessionCallback)callback, userData);
659         SESSION_EXTERN_END;
660
661         return result;
662 }
663
664 EXTERN_API bool session_is_closed(session_h handle)
665 {
666         bool result = false;
667
668         SESSION_EXTERN_BEGIN;
669                 result = session->isClosed();
670         SESSION_EXTERN_END;
671
672         return result;
673 }
674
675 EXTERN_API void session_close_channels(session_h handle)
676 {
677         SESSION_EXTERN_BEGIN;
678                 session->closeChannels();
679         SESSION_EXTERN_END;
680 }
681
682 EXTERN_API int session_open_basic_channel(session_h handle, unsigned char *aid,
683         unsigned int length, session_open_channel_cb callback, void *userData)
684 {
685         int result = -1;
686
687         SESSION_EXTERN_BEGIN;
688                 result = session->openBasicChannel(aid, length, (openChannelCallback)callback, userData);
689         SESSION_EXTERN_END;
690
691         return result;
692 }
693
694 EXTERN_API int session_open_logical_channel(session_h handle, unsigned char *aid,
695         unsigned int length, session_open_channel_cb callback, void *userData)
696 {
697         int result = -1;
698
699         SESSION_EXTERN_BEGIN;
700                 result = session->openLogicalChannel(aid, length, (openChannelCallback)callback, userData);
701         SESSION_EXTERN_END;
702
703         return result;
704 }
705
706 EXTERN_API int session_get_channel_count(session_h handle, session_get_channel_count_cb callback, void * userData)
707 {
708         int result = -1;
709
710         SESSION_EXTERN_BEGIN;
711                 result = session->getChannelCount((getChannelCountCallback)callback, userData);
712         SESSION_EXTERN_END;
713
714         return result;
715 }
716
717 EXTERN_API void session_destroy_instance(session_h handle)
718 {
719 }
720
721 EXTERN_API int session_get_atr_sync(session_h handle, unsigned char **buffer, unsigned int *length)
722 {
723         ByteArray temp;
724         int result = -1;
725
726 #ifdef CLIENT_IPC_THREAD
727         if (buffer == NULL || length == NULL)
728                 return result;
729
730         SESSION_EXTERN_BEGIN;
731                 temp = session->getATRSync();
732                 if (temp.getLength() > 0)
733                 {
734                         *length = temp.getLength();
735                         *buffer = (unsigned char *)calloc(1, *length);
736                         memcpy(*buffer, temp.getBuffer(), *length);
737
738                         result = 0;
739                 }
740                 SESSION_EXTERN_END;
741 #endif
742
743         return result;
744 }
745
746 EXTERN_API void session_close_sync(session_h handle)
747 {
748 #ifdef CLIENT_IPC_THREAD
749         SESSION_EXTERN_BEGIN;
750                 session->closeSync();
751         SESSION_EXTERN_END;
752 #endif
753 }
754
755 EXTERN_API channel_h session_open_basic_channel_sync(session_h handle, unsigned char *aid, unsigned int length)
756 {
757         channel_h result = NULL;
758
759 #ifdef CLIENT_IPC_THREAD
760         SESSION_EXTERN_BEGIN;
761                 result = session->openBasicChannelSync(aid, length);
762         SESSION_EXTERN_END;
763 #endif
764
765         return result;
766 }
767
768 EXTERN_API channel_h session_open_logical_channel_sync(session_h handle, unsigned char *aid, unsigned int length)
769 {
770         channel_h result = NULL;
771
772 #ifdef CLIENT_IPC_THREAD
773         SESSION_EXTERN_BEGIN;
774                 result = session->openLogicalChannelSync(aid, length);
775         SESSION_EXTERN_END;
776 #endif
777
778         return result;
779 }
780
781 EXTERN_API unsigned int session_get_channel_count_sync(session_h handle)
782 {
783         unsigned int result = 0;
784
785 #ifdef CLIENT_IPC_THREAD
786         SESSION_EXTERN_BEGIN;
787                 result = session->getChannelCountSync();
788         SESSION_EXTERN_END;
789 #endif
790
791         return result;
792 }