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