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