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