Fix error handling
[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
22 /* SLP library header */
23
24 /* local header */
25 #include "Debug.h"
26 #include "Message.h"
27 #include "ClientIPC.h"
28 #include "ClientChannel.h"
29 #include "ReaderHelper.h"
30 #include "APDUHelper.h"
31
32 #ifndef EXTERN_API
33 #define EXTERN_API __attribute__((visibility("default")))
34 #endif
35
36 namespace smartcard_service_api
37 {
38         ClientChannel::ClientChannel(void *context, Session *session,
39                 int channelNum, ByteArray selectResponse, void *handle)
40                 : Channel(session)
41         {
42                 this->channelNum = -1;
43                 this->handle = NULL;
44                 this->context = NULL;
45
46                 if (handle == NULL)
47                 {
48                         SCARD_DEBUG_ERR("ClientIPC::getInstance() failed");
49
50                         return;
51                 }
52
53                 this->channelNum = channelNum;
54                 this->handle = handle;
55                 this->selectResponse = selectResponse;
56                 this->context = context;
57         }
58
59         ClientChannel::~ClientChannel()
60         {
61                 closeSync();
62         }
63
64         void ClientChannel::closeSync()
65                 throw(ExceptionBase &, ErrorIO &, ErrorSecurity &,
66                         ErrorIllegalState &, ErrorIllegalParameter &)
67         {
68 #ifdef CLIENT_IPC_THREAD
69                 if (isClosed() == false)
70                 {
71                         if (getSession()->getReader()->isSecureElementPresent() == true)
72                         {
73                                 Message msg;
74                                 int rv;
75
76                                 /* send message to server */
77                                 msg.message = Message::MSG_REQUEST_CLOSE_CHANNEL;
78                                 msg.param1 = (unsigned long)handle;
79                                 msg.error = (unsigned long)context; /* using error to context */
80                                 msg.caller = (void *)this;
81                                 msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
82
83                                 syncLock();
84                                 if (ClientIPC::getInstance().sendMessage(&msg) == true)
85                                 {
86                                         rv = waitTimedCondition(0);
87                                         if (rv < 0)
88                                         {
89                                                 SCARD_DEBUG_ERR("closeSync failed [%d]", rv);
90                                                 this->error = SCARD_ERROR_OPERATION_TIMEOUT;
91                                         }
92                                 }
93                                 else
94                                 {
95                                         SCARD_DEBUG_ERR("sendMessage failed");
96                                         this->error = SCARD_ERROR_IPC_FAILED;
97                                 }
98                                 syncUnlock();
99
100                                 channelNum = -1;
101
102                                 if (this->error != SCARD_ERROR_OK)
103                                 {
104                                         ThrowError::throwError(this->error);
105                                 }
106                         }
107                         else
108                         {
109                                 /* FIXME */
110                                 SCARD_DEBUG("unavailable channel");
111                         }
112                 }
113 #endif
114         }
115
116         int ClientChannel::close(closeCallback callback, void *userParam)
117         {
118                 int result = SCARD_ERROR_OK;
119
120                 if (isClosed() == false)
121                 {
122                         if (getSession()->getReader()->isSecureElementPresent() == true)
123                         {
124                                 Message msg;
125                                 channelNum = -1;
126
127                                 /* send message to server */
128                                 msg.message = Message::MSG_REQUEST_CLOSE_CHANNEL;
129                                 msg.param1 = (unsigned long)handle;
130                                 msg.error = (unsigned long)context; /* using error to context */
131                                 msg.caller = (void *)this;
132                                 msg.callback = (void *)callback;
133                                 msg.userParam = userParam;
134
135                                 if (ClientIPC::getInstance().sendMessage(&msg) == false)
136                                 {
137                                         result = SCARD_ERROR_IPC_FAILED;
138                                 }
139                         }
140                         else
141                         {
142                                 SCARD_DEBUG_ERR("unavailable channel");
143                                 result = SCARD_ERROR_ILLEGAL_STATE;
144                         }
145                 }
146
147                 return result;
148         }
149
150         int ClientChannel::transmitSync(ByteArray command, ByteArray &result)
151                 throw(ExceptionBase &, ErrorIO &, ErrorIllegalState &,
152                         ErrorIllegalParameter &, ErrorSecurity &)
153         {
154                 int rv = SCARD_ERROR_OK;
155
156                 if (getSession()->getReader()->isSecureElementPresent() == true)
157                 {
158                         Message msg;
159
160 #ifdef CLIENT_IPC_THREAD
161                         /* send message to server */
162                         msg.message = Message::MSG_REQUEST_TRANSMIT;
163                         msg.param1 = (unsigned long)handle;
164                         msg.param2 = 0;
165                         msg.data = command;
166                         msg.error = (unsigned long)context; /* using error to context */
167                         msg.caller = (void *)this;
168                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
169
170                         syncLock();
171                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
172                         {
173                                 rv = waitTimedCondition(0);
174                                 if (rv >= 0)
175                                 {
176                                         result = response;
177
178                                         rv = SCARD_ERROR_OK;
179                                 }
180                                 else
181                                 {
182                                         SCARD_DEBUG_ERR("timeout");
183
184                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
185                                 }
186                         }
187                         else
188                         {
189                                 SCARD_DEBUG_ERR("sendMessage failed");
190                         }
191                         syncUnlock();
192
193                         if (this->error != SCARD_ERROR_OK)
194                         {
195                                 ThrowError::throwError(this->error);
196                         }
197 #endif
198                 }
199                 else
200                 {
201                         SCARD_DEBUG_ERR("unavailable channel");
202                         throw ErrorIllegalState(SCARD_ERROR_UNAVAILABLE);
203                 }
204
205                 return rv;
206         }
207
208         int ClientChannel::transmit(ByteArray command, transmitCallback callback, void *userParam)
209         {
210                 int result;
211
212                 if (getSession()->getReader()->isSecureElementPresent() == true)
213                 {
214                         Message msg;
215
216                         /* send message to server */
217                         msg.message = Message::MSG_REQUEST_TRANSMIT;
218                         msg.param1 = (unsigned long)handle;
219                         msg.param2 = 0;
220                         msg.data = command;
221                         msg.error = (unsigned long)context; /* using error to context */
222                         msg.caller = (void *)this;
223                         msg.callback = (void *)callback;
224                         msg.userParam = userParam;
225
226                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
227                         {
228                                 result = SCARD_ERROR_OK;
229                         }
230                         else
231                         {
232                                 result = SCARD_ERROR_IPC_FAILED;
233                         }
234                 }
235                 else
236                 {
237                         SCARD_DEBUG_ERR("unavailable channel");
238                         result = SCARD_ERROR_ILLEGAL_STATE;
239                 }
240
241                 return result;
242         }
243
244         bool ClientChannel::dispatcherCallback(void *message)
245         {
246                 Message *msg = (Message *)message;
247                 ClientChannel *channel = NULL;
248                 bool result = false;
249
250                 if (msg == NULL)
251                 {
252                         SCARD_DEBUG_ERR("message is null");
253                         return result;
254                 }
255
256                 channel = (ClientChannel *)msg->caller;
257
258                 switch (msg->message)
259                 {
260                 case Message::MSG_REQUEST_TRANSMIT :
261                         {
262                                 /* transmit result */
263                                 SCARD_DEBUG("MSG_REQUEST_TRANSMIT");
264
265                                 if (msg->error == 0 &&
266                                         ResponseHelper::getStatus(msg->data) == 0)
267                                 {
268                                         /* store select response */
269                                         if (msg->data.getAt(1) == APDUCommand::INS_SELECT_FILE)
270                                                 channel->setSelectResponse(msg->data);
271                                 }
272
273                                 if (msg->isSynchronousCall() == true) /* synchronized call */
274                                 {
275                                         /* sync call */
276                                         channel->syncLock();
277
278                                         /* copy result */
279                                         channel->error = msg->error;
280                                         channel->response = msg->data;
281
282                                         channel->signalCondition();
283                                         channel->syncUnlock();
284                                 }
285                                 else if (msg->callback != NULL)
286                                 {
287                                         transmitCallback cb = (transmitCallback)msg->callback;
288
289                                         /* async call */
290                                         cb(msg->data.getBuffer(), msg->data.getLength(), msg->error, msg->userParam);
291                                 }
292                         }
293                         break;
294
295                 case Message::MSG_REQUEST_CLOSE_CHANNEL :
296                         {
297                                 SCARD_DEBUG("MSG_REQUEST_CLOSE_CHANNEL");
298
299                                 if (msg->isSynchronousCall() == true) /* synchronized call */
300                                 {
301                                         /* sync call */
302                                         channel->syncLock();
303
304                                         channel->error = msg->error;
305
306                                         channel->signalCondition();
307                                         channel->syncUnlock();
308                                 }
309                                 else if (msg->callback != NULL)
310                                 {
311                                         closeCallback cb = (closeCallback)msg->callback;
312
313                                         /* async call */
314                                         cb(msg->error, msg->userParam);
315                                 }
316                         }
317                         break;
318
319                 default:
320                         SCARD_DEBUG("unknwon message : %s", msg->toString());
321                         break;
322                 }
323
324                 return result;
325         }
326 } /* namespace smartcard_service_api */
327
328 /* export C API */
329 #define CHANNEL_EXTERN_BEGIN \
330         if (handle != NULL) \
331         { \
332                 ClientChannel *channel = (ClientChannel *)handle;
333
334 #define CHANNEL_EXTERN_END \
335         } \
336         else \
337         { \
338                 SCARD_DEBUG_ERR("Invalid param"); \
339         }
340
341 using namespace smartcard_service_api;
342
343 EXTERN_API int channel_close(channel_h handle, channel_close_cb callback, void *userParam)
344 {
345         int result = -1;
346
347         CHANNEL_EXTERN_BEGIN;
348         result = channel->close((closeCallback)callback, userParam);
349         CHANNEL_EXTERN_END;
350
351         return result;
352 }
353
354 EXTERN_API int channel_transmit(channel_h handle, unsigned char *command,
355         unsigned int length, channel_transmit_cb callback, void *userParam)
356 {
357         int result = -1;
358
359         CHANNEL_EXTERN_BEGIN;
360         ByteArray temp;
361
362         temp.setBuffer(command, length);
363         result = channel->transmit(temp, (transmitCallback)callback, userParam);
364         CHANNEL_EXTERN_END;
365
366         return result;
367 }
368
369 EXTERN_API void channel_close_sync(channel_h handle)
370 {
371 #ifdef CLIENT_IPC_THREAD
372         CHANNEL_EXTERN_BEGIN;
373         try
374         {
375                 channel->closeSync();
376         }
377         catch (...)
378         {
379         }
380         CHANNEL_EXTERN_END;
381 #endif
382 }
383
384 EXTERN_API int channel_transmit_sync(channel_h handle, unsigned char *command,
385         unsigned int cmd_len, unsigned char **response, unsigned int *resp_len)
386 {
387         int result = -1;
388
389 #ifdef CLIENT_IPC_THREAD
390         if (command == NULL || cmd_len == 0 || response == NULL || resp_len == NULL)
391                 return result;
392
393         CHANNEL_EXTERN_BEGIN;
394         ByteArray temp, resp;
395
396         temp.setBuffer(command, cmd_len);
397
398         try
399         {
400                 result = channel->transmitSync(temp, resp);
401                 if (resp.getLength() > 0)
402                 {
403                         *resp_len = resp.getLength();
404                         *response = (unsigned char *)calloc(1, *resp_len);
405                         memcpy(*response, resp.getBuffer(), *resp_len);
406                 }
407         }
408         catch (...)
409         {
410                 result = -1;
411         }
412         CHANNEL_EXTERN_END;
413 #endif
414
415         return result;
416 }
417
418 EXTERN_API bool channel_is_basic_channel(channel_h handle)
419 {
420         bool result = false;
421
422         CHANNEL_EXTERN_BEGIN;
423         result = channel->isBasicChannel();
424         CHANNEL_EXTERN_END;
425
426         return result;
427 }
428
429 EXTERN_API bool channel_is_closed(channel_h handle)
430 {
431         bool result = false;
432
433         CHANNEL_EXTERN_BEGIN;
434         result = channel->isClosed();
435         CHANNEL_EXTERN_END;
436
437         return result;
438 }
439
440 EXTERN_API unsigned int channel_get_select_response_length(channel_h handle)
441 {
442         unsigned int result = 0;
443
444         CHANNEL_EXTERN_BEGIN;
445         result = channel->getSelectResponse().getLength();
446         CHANNEL_EXTERN_END;
447
448         return result;
449 }
450
451 EXTERN_API bool channel_get_select_response(channel_h handle,
452         unsigned char *buffer, unsigned int length)
453 {
454         bool result = false;
455
456         if (buffer == NULL || length == 0)
457         {
458                 return result;
459         }
460
461         CHANNEL_EXTERN_BEGIN;
462         ByteArray response;
463
464         response = channel->getSelectResponse();
465         if (response.getLength() > 0)
466         {
467                 memcpy(buffer, response.getBuffer(), MIN(length, response.getLength()));
468                 result = true;
469         }
470         CHANNEL_EXTERN_END;
471
472         return result;
473 }
474
475 EXTERN_API session_h channel_get_session(channel_h handle)
476 {
477         session_h session = NULL;
478
479         CHANNEL_EXTERN_BEGIN;
480         session = channel->getSession();
481         CHANNEL_EXTERN_END;
482
483         return session;
484 }
485
486 EXTERN_API void channel_destroy_instance(channel_h handle)
487 {
488         /* do nothing */
489 }