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