Remove storing select response every select command
[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                         _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                                                 _ERR("timeout [%d]", rv);
90                                                 this->error = SCARD_ERROR_OPERATION_TIMEOUT;
91                                         }
92                                 }
93                                 else
94                                 {
95                                         _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                                 _INFO("unavailable channel");
110                         }
111                 }
112 #endif
113         }
114
115         int ClientChannel::close(closeCallback callback, void *userParam)
116         {
117                 int result = SCARD_ERROR_OK;
118
119                 if (isClosed() == false)
120                 {
121                         if (getSession()->getReader()->isSecureElementPresent() == true)
122                         {
123                                 Message msg;
124                                 channelNum = -1;
125
126                                 /* send message to server */
127                                 msg.message = Message::MSG_REQUEST_CLOSE_CHANNEL;
128                                 msg.param1 = (unsigned long)handle;
129                                 msg.error = (unsigned long)context; /* using error to context */
130                                 msg.caller = (void *)this;
131                                 msg.callback = (void *)callback;
132                                 msg.userParam = userParam;
133
134                                 if (ClientIPC::getInstance().sendMessage(&msg) == false)
135                                 {
136                                         _ERR("sendMessage failed");
137                                         result = SCARD_ERROR_IPC_FAILED;
138                                 }
139                         }
140                         else
141                         {
142                                 _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                 if (getSession()->getReader()->isSecureElementPresent() == true)
156                 {
157                         Message msg;
158
159 #ifdef CLIENT_IPC_THREAD
160                         /* send message to server */
161                         msg.message = Message::MSG_REQUEST_TRANSMIT;
162                         msg.param1 = (unsigned long)handle;
163                         msg.param2 = 0;
164                         msg.data = command;
165                         msg.error = (unsigned long)context; /* using error to context */
166                         msg.caller = (void *)this;
167                         msg.callback = (void *)this; /* if callback is class instance, it means synchronized call */
168
169                         syncLock();
170                         if (ClientIPC::getInstance().sendMessage(&msg) == true)
171                         {
172                                 rv = waitTimedCondition(0);
173                                 if (rv >= 0)
174                                 {
175                                         result = response;
176                                         rv = SCARD_ERROR_OK;
177                                 }
178                                 else
179                                 {
180                                         _ERR("timeout [%d]", rv);
181                                         this->error = SCARD_ERROR_OPERATION_TIMEOUT;
182                                 }
183                         }
184                         else
185                         {
186                                 _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                         _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                                 _ERR("sendMessage failed");
230                                 result = SCARD_ERROR_IPC_FAILED;
231                         }
232                 }
233                 else
234                 {
235                         _ERR("unavailable channel");
236                         result = SCARD_ERROR_ILLEGAL_STATE;
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                         _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                                 _INFO("MSG_REQUEST_TRANSMIT");
262
263                                 if (msg->isSynchronousCall() == true) /* synchronized call */
264                                 {
265                                         /* sync call */
266                                         channel->syncLock();
267
268                                         /* copy result */
269                                         channel->error = msg->error;
270                                         channel->response = msg->data;
271
272                                         channel->signalCondition();
273                                         channel->syncUnlock();
274                                 }
275                                 else if (msg->callback != NULL)
276                                 {
277                                         transmitCallback cb = (transmitCallback)msg->callback;
278
279                                         /* async call */
280                                         cb(msg->data.getBuffer(), msg->data.getLength(), msg->error, msg->userParam);
281                                 }
282                         }
283                         break;
284
285                 case Message::MSG_REQUEST_CLOSE_CHANNEL :
286                         {
287                                 _INFO("MSG_REQUEST_CLOSE_CHANNEL");
288
289                                 if (msg->isSynchronousCall() == true) /* synchronized call */
290                                 {
291                                         /* sync call */
292                                         channel->syncLock();
293
294                                         channel->error = msg->error;
295
296                                         channel->signalCondition();
297                                         channel->syncUnlock();
298                                 }
299                                 else if (msg->callback != NULL)
300                                 {
301                                         closeCallback cb = (closeCallback)msg->callback;
302
303                                         /* async call */
304                                         cb(msg->error, msg->userParam);
305                                 }
306                         }
307                         break;
308
309                 default:
310                         _DBG("Unknown message : %s", msg->toString());
311                         break;
312                 }
313
314                 delete msg;
315
316                 return result;
317         }
318 } /* namespace smartcard_service_api */
319
320 /* export C API */
321 #define CHANNEL_EXTERN_BEGIN \
322         if (handle != NULL) \
323         { \
324                 ClientChannel *channel = (ClientChannel *)handle;
325
326 #define CHANNEL_EXTERN_END \
327         } \
328         else \
329         { \
330                 _ERR("Invalid param"); \
331         }
332
333 using namespace smartcard_service_api;
334
335 EXTERN_API int channel_close(channel_h handle, channel_close_cb callback, void *userParam)
336 {
337         int result = -1;
338
339         CHANNEL_EXTERN_BEGIN;
340         result = channel->close((closeCallback)callback, userParam);
341         CHANNEL_EXTERN_END;
342
343         return result;
344 }
345
346 EXTERN_API int channel_transmit(channel_h handle, unsigned char *command,
347         unsigned int length, channel_transmit_cb callback, void *userParam)
348 {
349         int result = -1;
350
351         CHANNEL_EXTERN_BEGIN;
352         ByteArray temp;
353
354         temp.setBuffer(command, length);
355         result = channel->transmit(temp, (transmitCallback)callback, userParam);
356         CHANNEL_EXTERN_END;
357
358         return result;
359 }
360
361 EXTERN_API void channel_close_sync(channel_h handle)
362 {
363 #ifdef CLIENT_IPC_THREAD
364         CHANNEL_EXTERN_BEGIN;
365         try
366         {
367                 channel->closeSync();
368         }
369         catch (...)
370         {
371         }
372         CHANNEL_EXTERN_END;
373 #endif
374 }
375
376 EXTERN_API int channel_transmit_sync(channel_h handle, unsigned char *command,
377         unsigned int cmd_len, unsigned char **response, unsigned int *resp_len)
378 {
379         int result = -1;
380
381 #ifdef CLIENT_IPC_THREAD
382         if (command == NULL || cmd_len == 0 || response == NULL || resp_len == NULL)
383                 return result;
384
385         CHANNEL_EXTERN_BEGIN;
386         ByteArray temp, resp;
387
388         temp.setBuffer(command, cmd_len);
389
390         try
391         {
392                 result = channel->transmitSync(temp, resp);
393                 if (resp.getLength() > 0)
394                 {
395                         *resp_len = resp.getLength();
396                         *response = (unsigned char *)calloc(1, *resp_len);
397                         memcpy(*response, resp.getBuffer(), *resp_len);
398                 }
399         }
400         catch (...)
401         {
402                 result = -1;
403         }
404         CHANNEL_EXTERN_END;
405 #endif
406
407         return result;
408 }
409
410 EXTERN_API bool channel_is_basic_channel(channel_h handle)
411 {
412         bool result = false;
413
414         CHANNEL_EXTERN_BEGIN;
415         result = channel->isBasicChannel();
416         CHANNEL_EXTERN_END;
417
418         return result;
419 }
420
421 EXTERN_API bool channel_is_closed(channel_h handle)
422 {
423         bool result = false;
424
425         CHANNEL_EXTERN_BEGIN;
426         result = channel->isClosed();
427         CHANNEL_EXTERN_END;
428
429         return result;
430 }
431
432 EXTERN_API unsigned int channel_get_select_response_length(channel_h handle)
433 {
434         unsigned int result = 0;
435
436         CHANNEL_EXTERN_BEGIN;
437         result = channel->getSelectResponse().getLength();
438         CHANNEL_EXTERN_END;
439
440         return result;
441 }
442
443 EXTERN_API bool channel_get_select_response(channel_h handle,
444         unsigned char *buffer, unsigned int length)
445 {
446         bool result = false;
447
448         if (buffer == NULL || length == 0)
449         {
450                 return result;
451         }
452
453         CHANNEL_EXTERN_BEGIN;
454         ByteArray response;
455
456         response = channel->getSelectResponse();
457         if (response.getLength() > 0)
458         {
459                 memcpy(buffer, response.getBuffer(), MIN(length, response.getLength()));
460                 result = true;
461         }
462         CHANNEL_EXTERN_END;
463
464         return result;
465 }
466
467 EXTERN_API session_h channel_get_session(channel_h handle)
468 {
469         session_h session = NULL;
470
471         CHANNEL_EXTERN_BEGIN;
472         session = channel->getSession();
473         CHANNEL_EXTERN_END;
474
475         return session;
476 }
477
478 EXTERN_API void channel_destroy_instance(channel_h handle)
479 {
480         /* do nothing */
481 }