Separated transmission logic for data on Both Mode.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / camessagehandler.c
1 /* *****************************************************************
2  *
3  * Copyright 2014 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25
26 #include "cainterface.h"
27 #include "camessagehandler.h"
28 #include "caremotehandler.h"
29 #include "caprotocolmessage.h"
30 #include "logger.h"
31 #include "config.h" /* for coap protocol */
32 #include "oic_malloc.h"
33 #include "canetworkconfigurator.h"
34 #include "caadapterutils.h"
35 #include "cainterfacecontroller.h"
36 #include "caretransmission.h"
37 #include "oic_string.h"
38
39 #ifdef WITH_BWT
40 #include "cablockwisetransfer.h"
41 #endif
42
43 #ifndef  SINGLE_THREAD
44 #include "uqueue.h"
45 #include "cathreadpool.h" /* for thread pool */
46 #include "caqueueingthread.h"
47
48 #define SINGLE_HANDLE
49 #define MAX_THREAD_POOL_SIZE    20
50
51 // thread pool handle
52 static ca_thread_pool_t g_threadPoolHandle = NULL;
53
54 // message handler main thread
55 static CAQueueingThread_t g_sendThread;
56 static CAQueueingThread_t g_receiveThread;
57
58 #else
59 #define CA_MAX_RT_ARRAY_SIZE    3
60 #endif  // SINGLE_THREAD
61
62 #define TAG "OIC_CA_MSG_HANDLE"
63
64 static CARetransmission_t g_retransmissionContext;
65
66 // handler field
67 static CARequestCallback g_requestHandler = NULL;
68 static CAResponseCallback g_responseHandler = NULL;
69 static CAErrorCallback g_errorHandler = NULL;
70 static CANetworkMonitorCallback g_nwMonitorHandler = NULL;
71
72 static void CAErrorHandler(const CAEndpoint_t *endpoint,
73                            const void *data, uint32_t dataLen,
74                            CAResult_t result);
75
76 static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
77                                        const CARemoteId_t *identity,
78                                        const void *data, CADataType_t dataType);
79
80 static void CASendErrorInfo(const CAEndpoint_t *endpoint, const CAInfo_t *info,
81                             CAResult_t result);
82
83 #ifdef SINGLE_THREAD
84 static void CAProcessReceivedData(CAData_t *data);
85 #endif
86 static void CADestroyData(void *data, uint32_t size);
87 static void CALogPayloadInfo(CAInfo_t *info);
88 static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *endpoint, uint16_t id,
89                                 CAToken_t token, uint8_t tokenLength);
90
91 #ifdef WITH_BWT
92 void CAAddDataToSendThread(CAData_t *data)
93 {
94     VERIFY_NON_NULL_VOID(data, TAG, "data");
95
96     // add thread
97     CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
98 }
99
100 void CAAddDataToReceiveThread(CAData_t *data)
101 {
102     VERIFY_NON_NULL_VOID(data, TAG, "data");
103
104     // add thread
105     CAQueueingThreadAddData(&g_receiveThread, data, sizeof(CAData_t));
106 }
107 #endif
108
109 static bool CAIsSelectedNetworkAvailable()
110 {
111     u_arraylist_t *list = CAGetSelectedNetworkList();
112     if (!list || u_arraylist_length(list) == 0)
113     {
114         OIC_LOG(ERROR, TAG, "No selected network");
115         return false;
116     }
117
118     return true;
119 }
120
121 static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
122                                        const CARemoteId_t *identity,
123                                        const void *data, CADataType_t dataType)
124 {
125     OIC_LOG(DEBUG, TAG, "CAGenerateHandlerData IN");
126     CAInfo_t *info = NULL;
127     CAData_t *cadata = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
128     if (!cadata)
129     {
130         OIC_LOG(ERROR, TAG, "memory allocation failed");
131         return NULL;
132     }
133
134     CAEndpoint_t* ep = CACloneEndpoint(endpoint);
135     if (!ep)
136     {
137         OIC_LOG(ERROR, TAG, "endpoint clone failed");
138         goto exit;
139     }
140
141     OIC_LOG_V(DEBUG, TAG, "address : %s", ep->addr);
142
143     if (CA_RESPONSE_DATA == dataType)
144     {
145         CAResponseInfo_t* resInfo = (CAResponseInfo_t*)OICCalloc(1, sizeof(CAResponseInfo_t));
146         if (!resInfo)
147         {
148             OIC_LOG(ERROR, TAG, "memory allocation failed");
149             goto exit;
150         }
151
152         CAResult_t result = CAGetResponseInfoFromPDU(data, resInfo, endpoint);
153         if (CA_STATUS_OK != result)
154         {
155             OIC_LOG(ERROR, TAG, "CAGetResponseInfoFromPDU Failed");
156             CADestroyResponseInfoInternal(resInfo);
157             goto exit;
158         }
159         cadata->responseInfo = resInfo;
160         info = &resInfo->info;
161         if (identity)
162         {
163             info->identity = *identity;
164         }
165         OIC_LOG(DEBUG, TAG, "Response Info :");
166         CALogPayloadInfo(info);
167     }
168     else if (CA_REQUEST_DATA == dataType)
169     {
170         CARequestInfo_t* reqInfo = (CARequestInfo_t*)OICCalloc(1, sizeof(CARequestInfo_t));
171         if (!reqInfo)
172         {
173             OIC_LOG(ERROR, TAG, "memory allocation failed");
174             goto exit;
175         }
176
177         CAResult_t result = CAGetRequestInfoFromPDU(data, endpoint, reqInfo);
178         if (CA_STATUS_OK != result)
179         {
180             OIC_LOG(ERROR, TAG, "CAGetRequestInfoFromPDU failed");
181             CADestroyRequestInfoInternal(reqInfo);
182             goto exit;
183         }
184
185         if (CADropSecondMessage(&caglobals.ca.requestHistory, endpoint, reqInfo->info.messageId,
186                                 reqInfo->info.token, reqInfo->info.tokenLength))
187         {
188             OIC_LOG(ERROR, TAG, "Second Request with same Token, Drop it");
189             CADestroyRequestInfoInternal(reqInfo);
190             goto exit;
191         }
192
193         cadata->requestInfo = reqInfo;
194         info = &reqInfo->info;
195         if (identity)
196         {
197             info->identity = *identity;
198         }
199         OIC_LOG(DEBUG, TAG, "Request Info :");
200         CALogPayloadInfo(info);
201    }
202     else if (CA_ERROR_DATA == dataType)
203     {
204         CAErrorInfo_t *errorInfo = (CAErrorInfo_t *)OICCalloc(1, sizeof (CAErrorInfo_t));
205         if (!errorInfo)
206         {
207             OIC_LOG(ERROR, TAG, "Memory allocation failed!");
208             goto exit;
209         }
210
211         CAResult_t result = CAGetErrorInfoFromPDU(data, endpoint, errorInfo);
212         if (CA_STATUS_OK != result)
213         {
214             OIC_LOG(ERROR, TAG, "CAGetErrorInfoFromPDU failed");
215             OICFree(errorInfo);
216             goto exit;
217         }
218
219         cadata->errorInfo = errorInfo;
220         info = &errorInfo->info;
221         if (identity)
222         {
223             info->identity = *identity;
224         }
225         OIC_LOG(DEBUG, TAG, "error Info :");
226         CALogPayloadInfo(info);
227     }
228
229     cadata->remoteEndpoint = ep;
230     cadata->dataType = dataType;
231
232     OIC_LOG(DEBUG, TAG, "CAGenerateHandlerData OUT");
233     return cadata;
234
235 exit:
236     OICFree(cadata);
237     CAFreeEndpoint(ep);
238     return NULL;
239 }
240
241 static void CATimeoutCallback(const CAEndpoint_t *endpoint, const void *pdu, uint32_t size)
242 {
243     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint");
244     VERIFY_NON_NULL_VOID(pdu, TAG, "pdu");
245
246     CAEndpoint_t* ep = CACloneEndpoint(endpoint);
247     if (!ep)
248     {
249         OIC_LOG(ERROR, TAG, "clone failed");
250         return;
251     }
252
253     CAResponseInfo_t* resInfo = (CAResponseInfo_t*)OICCalloc(1, sizeof(CAResponseInfo_t));
254
255     if (!resInfo)
256     {
257         OIC_LOG(ERROR, TAG, "calloc failed");
258         CAFreeEndpoint(ep);
259         return;
260     }
261
262     resInfo->result = CA_RETRANSMIT_TIMEOUT;
263     resInfo->info.type = CAGetMessageTypeFromPduBinaryData(pdu, size);
264     resInfo->info.messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
265
266     CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *) pdu, &(resInfo->info),
267                                        endpoint);
268     if (CA_STATUS_OK != res)
269     {
270         OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
271         CADestroyResponseInfoInternal(resInfo);
272         CAFreeEndpoint(ep);
273         return;
274     }
275
276     CAData_t *cadata = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
277     if (NULL == cadata)
278     {
279         OIC_LOG(ERROR, TAG, "memory allocation failed !");
280         CAFreeEndpoint(ep);
281         CADestroyResponseInfoInternal(resInfo);
282         return;
283     }
284
285     cadata->type = SEND_TYPE_UNICAST;
286     cadata->remoteEndpoint = ep;
287     cadata->requestInfo = NULL;
288     cadata->responseInfo = resInfo;
289
290 #ifdef WITH_BWT
291     if (CAIsSupportedBlockwiseTransfer(endpoint->adapter))
292     {
293         res = CARemoveBlockDataFromListWithSeed(resInfo->info.token, resInfo->info.tokenLength,
294                                                 endpoint->port);
295         if (CA_STATUS_OK != res)
296         {
297             OIC_LOG(ERROR, TAG, "CARemoveBlockDataFromListWithSeed failed");
298         }
299     }
300 #endif // WITH_BWT
301
302 #ifdef SINGLE_THREAD
303     CAProcessReceivedData(cadata);
304 #else
305     CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
306 #endif
307 }
308
309 static void CADestroyData(void *data, uint32_t size)
310 {
311     OIC_LOG(DEBUG, TAG, "CADestroyData IN");
312     if ((size_t)size < sizeof(CAData_t))
313     {
314         OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %d", data, size);
315     }
316     CAData_t *cadata = (CAData_t *) data;
317
318     if (NULL == cadata)
319     {
320         OIC_LOG(ERROR, TAG, "cadata is NULL");
321         return;
322     }
323
324     if (NULL != cadata->remoteEndpoint)
325     {
326         CAFreeEndpoint(cadata->remoteEndpoint);
327     }
328
329     if (NULL != cadata->requestInfo)
330     {
331         CADestroyRequestInfoInternal((CARequestInfo_t *) cadata->requestInfo);
332     }
333
334     if (NULL != cadata->responseInfo)
335     {
336         CADestroyResponseInfoInternal((CAResponseInfo_t *) cadata->responseInfo);
337     }
338
339     if (NULL != cadata->errorInfo)
340     {
341         CADestroyErrorInfoInternal(cadata->errorInfo);
342     }
343
344     OICFree(cadata);
345     OIC_LOG(DEBUG, TAG, "CADestroyData OUT");
346 }
347
348 #ifdef SINGLE_THREAD
349 static void CAProcessReceivedData(CAData_t *data)
350 {
351     OIC_LOG(DEBUG, TAG, "CAProcessReceivedData IN");
352     if (!data)
353     {
354         OIC_LOG(ERROR, TAG, "thread data error!!");
355         return;
356     }
357
358     // parse the data and call the callbacks.
359     // #1 parse the data
360     // #2 get endpoint
361     CAEndpoint_t *rep = (CAEndpoint_t *)(data->remoteEndpoint);
362     if (!rep)
363     {
364         OIC_LOG(ERROR, TAG, "remoteEndpoint error!!");
365         return;
366     }
367
368     if (data->requestInfo && g_requestHandler)
369     {
370         g_requestHandler(rep, data->requestInfo);
371     }
372     else if (data->responseInfo && g_responseHandler)
373     {
374         g_responseHandler(rep, data->responseInfo);
375     }
376     else if (data->errorInfo && g_errorHandler)
377     {
378         g_errorHandler(rep, data->errorInfo);
379     }
380
381     CADestroyData(data, sizeof(CAData_t));
382
383     OIC_LOG(DEBUG, TAG, "CAProcessReceivedData OUT");
384 }
385 #endif
386
387 #ifndef SINGLE_THREAD
388 static void CAReceiveThreadProcess(void *threadData)
389 {
390 #ifndef SINGLE_HANDLE
391     CAData_t *data = (CAData_t *) threadData;
392     CAProcessReceivedData(data);
393 #else
394     (void)threadData;
395 #endif
396 }
397 #endif // SINGLE_THREAD
398
399 static CAResult_t CAProcessMulticastData(const CAData_t *data)
400 {
401     VERIFY_NON_NULL(data, TAG, "data");
402     VERIFY_NON_NULL(data->remoteEndpoint, TAG, "remoteEndpoint");
403
404     coap_pdu_t *pdu = NULL;
405     CAInfo_t *info = NULL;
406     coap_list_t *options = NULL;
407     coap_transport_type transport = coap_udp;
408     CAResult_t res = CA_SEND_FAILED;
409
410     if (!data->requestInfo && !data->responseInfo)
411     {
412         OIC_LOG(ERROR, TAG, "request or response info is empty");
413         return res;
414     }
415
416     if (data->requestInfo)
417     {
418         OIC_LOG(DEBUG, TAG, "requestInfo is available..");
419
420         info = &data->requestInfo->info;
421         pdu = CAGeneratePDU(CA_GET, info, data->remoteEndpoint, &options, &transport);
422     }
423     else if (data->responseInfo)
424     {
425         OIC_LOG(DEBUG, TAG, "responseInfo is available..");
426
427         info = &data->responseInfo->info;
428         pdu = CAGeneratePDU(data->responseInfo->result, info, data->remoteEndpoint,
429                             &options, &transport);
430     }
431
432     if (!pdu)
433     {
434         OIC_LOG(ERROR,TAG,"Failed to generate multicast PDU");
435         CASendErrorInfo(data->remoteEndpoint, info, CA_SEND_FAILED);
436         coap_delete_list(options);
437         return res;
438     }
439
440 #ifdef WITH_BWT
441     if (CAIsSupportedBlockwiseTransfer(data->remoteEndpoint->adapter))
442     {
443         // Blockwise transfer
444         res = CAAddBlockOption(&pdu, info, data->remoteEndpoint, &options);
445         if (CA_STATUS_OK != res)
446         {
447             OIC_LOG(DEBUG, TAG, "CAAddBlockOption has failed");
448             goto exit;
449         }
450     }
451 #endif // WITH_BWT
452
453     CALogPDUInfo(pdu, data->remoteEndpoint);
454
455     OIC_LOG(DEBUG, TAG, "pdu to send :");
456     OIC_LOG_BUFFER(DEBUG, TAG,  (uint8_t*)pdu->hdr, pdu->length);
457
458     res = CASendMulticastData(data->remoteEndpoint, pdu->hdr, pdu->length, data->dataType);
459     if (CA_STATUS_OK != res)
460     {
461         OIC_LOG_V(ERROR, TAG, "send failed:%d", res);
462         goto exit;
463     }
464
465     coap_delete_list(options);
466     coap_delete_pdu(pdu);
467     return res;
468
469 exit:
470     CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res);
471     coap_delete_list(options);
472     coap_delete_pdu(pdu);
473     return res;
474 }
475
476 static CAResult_t CAProcessSendData(const CAData_t *data)
477 {
478     VERIFY_NON_NULL(data, TAG, "data");
479     VERIFY_NON_NULL(data->remoteEndpoint, TAG, "remoteEndpoint");
480
481     CAResult_t res = CA_STATUS_FAILED;
482
483     CASendDataType_t type = data->type;
484
485     coap_pdu_t *pdu = NULL;
486     CAInfo_t *info = NULL;
487     coap_list_t *options = NULL;
488     coap_transport_type transport = coap_udp;
489
490     if (SEND_TYPE_UNICAST == type)
491     {
492         OIC_LOG(DEBUG,TAG,"Unicast message");
493
494 #ifdef ROUTING_GATEWAY
495         /*
496          * When forwarding a packet, do not attempt retransmission as its the responsibility of
497          * packet originator node
498          */
499         bool skipRetransmission = false;
500 #endif
501
502         if (NULL != data->requestInfo)
503         {
504             OIC_LOG(DEBUG, TAG, "requestInfo is available..");
505
506             info = &data->requestInfo->info;
507 #ifdef ROUTING_GATEWAY
508             skipRetransmission = data->requestInfo->info.skipRetransmission;
509 #endif
510             pdu = CAGeneratePDU(data->requestInfo->method, info, data->remoteEndpoint,
511                                 &options, &transport);
512         }
513         else if (NULL != data->responseInfo)
514         {
515             OIC_LOG(DEBUG, TAG, "responseInfo is available..");
516
517             info = &data->responseInfo->info;
518 #ifdef ROUTING_GATEWAY
519             skipRetransmission = data->responseInfo->info.skipRetransmission;
520 #endif
521             pdu = CAGeneratePDU(data->responseInfo->result, info, data->remoteEndpoint,
522                                 &options, &transport);
523         }
524         else
525         {
526             OIC_LOG(DEBUG, TAG, "request info, response info is empty");
527             return CA_STATUS_INVALID_PARAM;
528         }
529
530         // interface controller function call.
531         if (NULL != pdu)
532         {
533 #ifdef WITH_BWT
534             if (CAIsSupportedBlockwiseTransfer(data->remoteEndpoint->adapter))
535             {
536                 // Blockwise transfer
537                 if (NULL != info)
538                 {
539                     CAResult_t res = CAAddBlockOption(&pdu, info,
540                                                       data->remoteEndpoint,
541                                                       &options);
542                     if (CA_STATUS_OK != res)
543                     {
544                         OIC_LOG(INFO, TAG, "to write block option has failed");
545                         CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res);
546                         coap_delete_list(options);
547                         coap_delete_pdu(pdu);
548                         return res;
549                     }
550                 }
551             }
552 #endif // WITH_BWT
553             CALogPDUInfo(pdu, data->remoteEndpoint);
554
555             OIC_LOG_V(INFO, TAG, "CASendUnicastData type : %d", data->dataType);
556             res = CASendUnicastData(data->remoteEndpoint, pdu->hdr, pdu->length, data->dataType);
557             if (CA_STATUS_OK != res)
558             {
559                 OIC_LOG_V(ERROR, TAG, "send failed:%d", res);
560                 CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res);
561                 coap_delete_list(options);
562                 coap_delete_pdu(pdu);
563                 return res;
564             }
565
566 #ifdef WITH_TCP
567             if (CAIsSupportedCoAPOverTCP(data->remoteEndpoint->adapter))
568             {
569                 OIC_LOG(INFO, TAG, "retransmission will be not worked");
570             }
571             else
572 #endif
573 #ifdef ROUTING_GATEWAY
574             if(!skipRetransmission)
575 #endif
576             {
577                 // for retransmission
578                 res = CARetransmissionSentData(&g_retransmissionContext,
579                                                data->remoteEndpoint,
580                                                data->dataType,
581                                                pdu->hdr, pdu->length);
582                 if ((CA_STATUS_OK != res) && (CA_NOT_SUPPORTED != res))
583                 {
584                     //when retransmission not supported this will return CA_NOT_SUPPORTED, ignore
585                     OIC_LOG_V(INFO, TAG, "retransmission is not enabled due to error, res : %d", res);
586                     coap_delete_list(options);
587                     coap_delete_pdu(pdu);
588                     return res;
589                 }
590             }
591
592             coap_delete_list(options);
593             coap_delete_pdu(pdu);
594         }
595         else
596         {
597             OIC_LOG(ERROR,TAG,"Failed to generate unicast PDU");
598             CASendErrorInfo(data->remoteEndpoint, info, CA_SEND_FAILED);
599             return CA_SEND_FAILED;
600         }
601     }
602     else if (SEND_TYPE_MULTICAST == type)
603     {
604         OIC_LOG(DEBUG,TAG,"Multicast message");
605 #ifdef WITH_TCP
606         /*
607          * If CoAP over TCP is enabled, the CoAP pdu wont be same for IP and other adapters.
608          * That's why we need to generate two pdu's, one for IP and second for other transports.
609          * Two possible cases we might have to split: a) when adapter is CA_DEFAULT_ADAPTER
610          * b) when one of the adapter is IP adapter(ex: CA_ADAPTER_IP | CA_ADAPTER_GATT_BTLE)
611          */
612         if (data->remoteEndpoint->adapter == CA_DEFAULT_ADAPTER ||
613                 (CA_ADAPTER_IP & data->remoteEndpoint->adapter &&
614                     CA_ADAPTER_IP != data->remoteEndpoint->adapter))
615         {
616             if (data->remoteEndpoint->adapter == CA_DEFAULT_ADAPTER)
617             {
618                 data->remoteEndpoint->adapter = CA_ALL_ADAPTERS ^ CA_ADAPTER_IP;
619             }
620             else
621             {
622                 data->remoteEndpoint->adapter = data->remoteEndpoint->adapter ^ CA_ADAPTER_IP;
623             }
624             CAProcessMulticastData(data);
625             data->remoteEndpoint->adapter = CA_ADAPTER_IP;
626             CAProcessMulticastData(data);
627         }
628         else
629         {
630             CAProcessMulticastData(data);
631         }
632 #else
633         CAProcessMulticastData(data);
634 #endif
635     }
636
637     return CA_STATUS_OK;
638 }
639
640 #ifndef SINGLE_THREAD
641 static void CASendThreadProcess(void *threadData)
642 {
643     CAData_t *data = (CAData_t *) threadData;
644     CAProcessSendData(data);
645 }
646 #endif
647
648 /*
649  * If a second message arrives with the same message ID, token and the other address
650  * family, drop it.  Typically, IPv6 beats IPv4, so the IPv4 message is dropped.
651  */
652 static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *ep, uint16_t id,
653                                 CAToken_t token, uint8_t tokenLength)
654 {
655     if (!ep)
656     {
657         return true;
658     }
659     if (ep->adapter != CA_ADAPTER_IP)
660     {
661         return false;
662     }
663     if (!caglobals.ip.dualstack)
664     {
665         return false;
666     }
667
668     if (tokenLength > CA_MAX_TOKEN_LEN)
669     {
670         /*
671          * If token length is more than CA_MAX_TOKEN_LEN,
672          * we compare the first CA_MAX_TOKEN_LEN bytes only.
673          */
674         tokenLength = CA_MAX_TOKEN_LEN;
675     }
676
677     bool ret = false;
678     CATransportFlags_t familyFlags = ep->flags & CA_IPFAMILY_MASK;
679
680     for (size_t i = 0; i < sizeof(history->items) / sizeof(history->items[0]); i++)
681     {
682         CAHistoryItem_t *item = &(history->items[i]);
683         if (id == item->messageId && tokenLength == item->tokenLength
684             && memcmp(item->token, token, tokenLength) == 0)
685         {
686             if ((familyFlags ^ item->flags) == CA_IPFAMILY_MASK)
687             {
688                 OIC_LOG_V(INFO, TAG, "IPv%c duplicate message ignored",
689                           familyFlags & CA_IPV6 ? '6' : '4');
690                 ret = true;
691                 break;
692             }
693         }
694     }
695
696     history->items[history->nextIndex].flags = familyFlags;
697     history->items[history->nextIndex].messageId = id;
698     if (token && tokenLength)
699     {
700         memcpy(history->items[history->nextIndex].token, token, tokenLength);
701         history->items[history->nextIndex].tokenLength = tokenLength;
702     }
703
704     if (++history->nextIndex >= HISTORYSIZE)
705     {
706         history->nextIndex = 0;
707     }
708
709     return ret;
710 }
711
712 static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
713                                      const void *data, uint32_t dataLen)
714 {
715     VERIFY_NON_NULL_VOID(sep, TAG, "remoteEndpoint");
716     VERIFY_NON_NULL_VOID(data, TAG, "data");
717
718     OIC_LOG(DEBUG, TAG, "received pdu data :");
719     OIC_LOG_BUFFER(DEBUG, TAG,  data, dataLen);
720
721     uint32_t code = CA_NOT_FOUND;
722     CAData_t *cadata = NULL;
723
724     coap_pdu_t *pdu = (coap_pdu_t *) CAParsePDU((const char *) data, dataLen, &code,
725                                                 &(sep->endpoint));
726     if (NULL == pdu)
727     {
728         OIC_LOG(ERROR, TAG, "Parse PDU failed");
729         return;
730     }
731
732     OIC_LOG_V(DEBUG, TAG, "code = %d", code);
733     if (CA_GET == code || CA_POST == code || CA_PUT == code || CA_DELETE == code)
734     {
735         cadata = CAGenerateHandlerData(&(sep->endpoint), &(sep->identity), pdu, CA_REQUEST_DATA);
736         if (!cadata)
737         {
738             OIC_LOG(ERROR, TAG, "CAReceivedPacketCallback, CAGenerateHandlerData failed!");
739             coap_delete_pdu(pdu);
740             return;
741         }
742     }
743     else
744     {
745         cadata = CAGenerateHandlerData(&(sep->endpoint), &(sep->identity), pdu, CA_RESPONSE_DATA);
746         if (!cadata)
747         {
748             OIC_LOG(ERROR, TAG, "CAReceivedPacketCallback, CAGenerateHandlerData failed!");
749             coap_delete_pdu(pdu);
750             return;
751         }
752
753 #ifdef WITH_TCP
754         if (CAIsSupportedCoAPOverTCP(sep->endpoint.adapter))
755         {
756             OIC_LOG(INFO, TAG, "retransmission is not supported");
757         }
758         else
759 #endif
760         {
761             // for retransmission
762             void *retransmissionPdu = NULL;
763             CARetransmissionReceivedData(&g_retransmissionContext, cadata->remoteEndpoint, pdu->hdr,
764                                          pdu->length, &retransmissionPdu);
765
766             // get token from saved data in retransmission list
767             if (retransmissionPdu && CA_EMPTY == code)
768             {
769                 if (cadata->responseInfo)
770                 {
771                     CAInfo_t *info = &cadata->responseInfo->info;
772                     CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *)retransmissionPdu,
773                                                        info, &(sep->endpoint));
774                     if (CA_STATUS_OK != res)
775                     {
776                         OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
777                         OICFree(info->token);
778                         info->tokenLength = 0;
779                     }
780                 }
781             }
782             OICFree(retransmissionPdu);
783         }
784     }
785
786     cadata->type = SEND_TYPE_UNICAST;
787
788 #ifdef SINGLE_THREAD
789     CAProcessReceivedData(cadata);
790 #else
791 #ifdef WITH_BWT
792     if (CAIsSupportedBlockwiseTransfer(sep->endpoint.adapter))
793     {
794         CAResult_t res = CAReceiveBlockWiseData(pdu, &(sep->endpoint), cadata, dataLen);
795         if (CA_NOT_SUPPORTED == res || CA_REQUEST_TIMEOUT == res)
796         {
797             OIC_LOG(DEBUG, TAG, "this message does not have block option");
798             CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
799         }
800         else
801         {
802             CADestroyData(cadata, sizeof(CAData_t));
803         }
804     }
805     else
806 #endif
807     {
808         CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
809     }
810 #endif // SINGLE_THREAD
811
812     coap_delete_pdu(pdu);
813 }
814
815 void CAHandleRequestResponseCallbacks()
816 {
817 #ifdef SINGLE_THREAD
818     CAReadData();
819     CARetransmissionBaseRoutine((void *)&g_retransmissionContext);
820 #else
821 #ifdef SINGLE_HANDLE
822     // parse the data and call the callbacks.
823     // #1 parse the data
824     // #2 get endpoint
825
826     ca_mutex_lock(g_receiveThread.threadMutex);
827
828     u_queue_message_t *item = u_queue_get_element(g_receiveThread.dataQueue);
829
830     ca_mutex_unlock(g_receiveThread.threadMutex);
831
832     if (NULL == item || NULL == item->msg)
833     {
834         return;
835     }
836
837     // get endpoint
838     CAData_t *td = (CAData_t *) item->msg;
839
840     if (td->requestInfo && g_requestHandler)
841     {
842         OIC_LOG_V(DEBUG, TAG, "request callback : %d", td->requestInfo->info.numOptions);
843         g_requestHandler(td->remoteEndpoint, td->requestInfo);
844     }
845     else if (td->responseInfo && g_responseHandler)
846     {
847         OIC_LOG_V(DEBUG, TAG, "response callback : %d", td->responseInfo->info.numOptions);
848         g_responseHandler(td->remoteEndpoint, td->responseInfo);
849     }
850     else if (td->errorInfo && g_errorHandler)
851     {
852         OIC_LOG_V(DEBUG, TAG, "error callback error: %d", td->errorInfo->result);
853         g_errorHandler(td->remoteEndpoint, td->errorInfo);
854     }
855
856     CADestroyData(item->msg, sizeof(CAData_t));
857     OICFree(item);
858
859 #endif // SINGLE_HANDLE
860 #endif // SINGLE_THREAD
861 }
862
863 static CAData_t* CAPrepareSendData(const CAEndpoint_t *endpoint, const void *sendData,
864                                    CADataType_t dataType)
865 {
866     OIC_LOG(DEBUG, TAG, "CAPrepareSendData IN");
867
868     CAData_t *cadata = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
869     if (!cadata)
870     {
871         OIC_LOG(ERROR, TAG, "memory allocation failed");
872         return NULL;
873     }
874
875     if (CA_REQUEST_DATA == dataType)
876     {
877         // clone request info
878         CARequestInfo_t *request = CACloneRequestInfo((CARequestInfo_t *)sendData);
879
880         if (!request)
881         {
882             OIC_LOG(ERROR, TAG, "CACloneRequestInfo failed");
883             goto exit;
884         }
885
886         cadata->type = request->isMulticast ? SEND_TYPE_MULTICAST : SEND_TYPE_UNICAST;
887         cadata->requestInfo =  request;
888     }
889     else if (CA_RESPONSE_DATA == dataType || CA_RESPONSE_FOR_RES == dataType)
890     {
891         // clone response info
892         CAResponseInfo_t *response = CACloneResponseInfo((CAResponseInfo_t *)sendData);
893
894         if(!response)
895         {
896             OIC_LOG(ERROR, TAG, "CACloneResponseInfo failed");
897             goto exit;
898         }
899
900         cadata->type = response->isMulticast ? SEND_TYPE_MULTICAST : SEND_TYPE_UNICAST;
901         cadata->responseInfo = response;
902     }
903     else
904     {
905         OIC_LOG(ERROR, TAG, "CAPrepareSendData unknown data type");
906         goto exit;
907     }
908
909     CAEndpoint_t* ep = CACloneEndpoint(endpoint);
910     if (!ep)
911     {
912         OIC_LOG(ERROR, TAG, "endpoint clone failed");
913         goto exit;
914     }
915
916     cadata->remoteEndpoint = ep;
917     cadata->dataType = dataType;
918     return cadata;
919
920 exit:
921     CADestroyData(cadata, sizeof(CAData_t));
922     return NULL;
923 }
924
925 CAResult_t CADetachSendMessage(const CAEndpoint_t *endpoint, const void *sendMsg,
926                                CADataType_t dataType)
927 {
928     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
929     VERIFY_NON_NULL(sendMsg, TAG, "sendMsg");
930
931     if (false == CAIsSelectedNetworkAvailable())
932     {
933         return CA_STATUS_FAILED;
934     }
935
936 #ifdef ARDUINO
937     // If max retransmission queue is reached, then don't handle new request
938     if (CA_MAX_RT_ARRAY_SIZE == u_arraylist_length(g_retransmissionContext.dataList))
939     {
940         OIC_LOG(ERROR, TAG, "max RT queue size reached!");
941         return CA_SEND_FAILED;
942     }
943 #endif // ARDUINO
944
945     CAData_t *data = CAPrepareSendData(endpoint, sendMsg, dataType);
946     if(!data)
947     {
948         OIC_LOG(ERROR, TAG, "CAPrepareSendData failed");
949         return CA_MEMORY_ALLOC_FAILED;
950     }
951
952 #ifdef SINGLE_THREAD
953     CAResult_t result = CAProcessSendData(data);
954     if (CA_STATUS_OK != result)
955     {
956         OIC_LOG(ERROR, TAG, "CAProcessSendData failed");
957         CADestroyData(data, sizeof(CAData_t));
958         return result;
959     }
960
961     CADestroyData(data, sizeof(CAData_t));
962 #else
963 #ifdef WITH_BWT
964     if (CAIsSupportedBlockwiseTransfer(endpoint->adapter))
965     {
966         // send block data
967         CAResult_t res = CASendBlockWiseData(data);
968         if (CA_NOT_SUPPORTED == res)
969         {
970             OIC_LOG(DEBUG, TAG, "normal msg will be sent");
971             CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
972             return CA_STATUS_OK;
973         }
974         else
975         {
976             CADestroyData(data, sizeof(CAData_t));
977         }
978         return res;
979     }
980     else
981 #endif // WITH_BWT
982     {
983         CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
984     }
985 #endif // SINGLE_THREAD
986
987     return CA_STATUS_OK;
988 }
989
990 void CASetInterfaceCallbacks(CARequestCallback ReqHandler, CAResponseCallback RespHandler,
991                              CAErrorCallback errorHandler)
992 {
993     g_requestHandler = ReqHandler;
994     g_responseHandler = RespHandler;
995     g_errorHandler = errorHandler;
996 }
997
998 void CASetNetworkMonitorCallback(CANetworkMonitorCallback nwMonitorHandler)
999 {
1000     g_nwMonitorHandler = nwMonitorHandler;
1001 }
1002
1003 CAResult_t CAInitializeMessageHandler()
1004 {
1005     CASetPacketReceivedCallback(CAReceivedPacketCallback);
1006     CASetErrorHandleCallback(CAErrorHandler);
1007
1008 #ifndef SINGLE_THREAD
1009     // create thread pool
1010     CAResult_t res = ca_thread_pool_init(MAX_THREAD_POOL_SIZE, &g_threadPoolHandle);
1011     if (CA_STATUS_OK != res)
1012     {
1013         OIC_LOG(ERROR, TAG, "thread pool initialize error.");
1014         return res;
1015     }
1016
1017     // send thread initialize
1018     res = CAQueueingThreadInitialize(&g_sendThread, g_threadPoolHandle,
1019                                      CASendThreadProcess, CADestroyData);
1020     if (CA_STATUS_OK != res)
1021     {
1022         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
1023         ca_thread_pool_free(g_threadPoolHandle);
1024         g_threadPoolHandle = NULL;
1025         return res;
1026     }
1027
1028     // start send thread
1029     res = CAQueueingThreadStart(&g_sendThread);
1030     if (CA_STATUS_OK != res)
1031     {
1032         OIC_LOG(ERROR, TAG, "thread start error(send thread).");
1033         ca_thread_pool_free(g_threadPoolHandle);
1034         g_threadPoolHandle = NULL;
1035         CAQueueingThreadDestroy(&g_sendThread);
1036         return res;
1037     }
1038
1039     // receive thread initialize
1040     res = CAQueueingThreadInitialize(&g_receiveThread, g_threadPoolHandle,
1041                                      CAReceiveThreadProcess, CADestroyData);
1042     if (CA_STATUS_OK != res)
1043     {
1044         OIC_LOG(ERROR, TAG, "Failed to Initialize receive queue thread");
1045         ca_thread_pool_free(g_threadPoolHandle);
1046         g_threadPoolHandle = NULL;
1047         CAQueueingThreadDestroy(&g_sendThread);
1048         return res;
1049     }
1050
1051 #ifndef SINGLE_HANDLE // This will be enabled when RI supports multi threading
1052     // start receive thread
1053     res = CAQueueingThreadStart(&g_receiveThread);
1054     if (CA_STATUS_OK != res)
1055     {
1056         OIC_LOG(ERROR, TAG, "thread start error(receive thread).");
1057         ca_thread_pool_free(g_threadPoolHandle);
1058         g_threadPoolHandle = NULL;
1059         CAQueueingThreadDestroy(&g_sendThread);
1060         CAQueueingThreadDestroy(&g_receiveThread);
1061         return res;
1062     }
1063 #endif // SINGLE_HANDLE
1064
1065     // retransmission initialize
1066     res = CARetransmissionInitialize(&g_retransmissionContext, g_threadPoolHandle,
1067                                      CASendUnicastData, CATimeoutCallback, NULL);
1068     if (CA_STATUS_OK != res)
1069     {
1070         OIC_LOG(ERROR, TAG, "Failed to Initialize Retransmission.");
1071         ca_thread_pool_free(g_threadPoolHandle);
1072         g_threadPoolHandle = NULL;
1073         CAQueueingThreadDestroy(&g_sendThread);
1074         CAQueueingThreadDestroy(&g_receiveThread);
1075         return res;
1076     }
1077
1078 #ifdef WITH_BWT
1079     // block-wise transfer initialize
1080     res = CAInitializeBlockWiseTransfer(CAAddDataToSendThread, CAAddDataToReceiveThread);
1081     if (CA_STATUS_OK != res)
1082     {
1083         OIC_LOG(ERROR, TAG, "Failed to Initialize BlockWiseTransfer.");
1084         ca_thread_pool_free(g_threadPoolHandle);
1085         g_threadPoolHandle = NULL;
1086         CAQueueingThreadDestroy(&g_sendThread);
1087         CAQueueingThreadDestroy(&g_receiveThread);
1088         CARetransmissionDestroy(&g_retransmissionContext);
1089         return res;
1090     }
1091 #endif
1092
1093     // start retransmission
1094     res = CARetransmissionStart(&g_retransmissionContext);
1095     if (CA_STATUS_OK != res)
1096     {
1097         OIC_LOG(ERROR, TAG, "thread start error(retransmission thread).");
1098         ca_thread_pool_free(g_threadPoolHandle);
1099         g_threadPoolHandle = NULL;
1100         CAQueueingThreadDestroy(&g_sendThread);
1101         CAQueueingThreadDestroy(&g_receiveThread);
1102         CARetransmissionDestroy(&g_retransmissionContext);
1103         return res;
1104     }
1105
1106     // initialize interface adapters by controller
1107     CAInitializeAdapters(g_threadPoolHandle);
1108 #else
1109     // retransmission initialize
1110     CAResult_t res = CARetransmissionInitialize(&g_retransmissionContext, NULL, CASendUnicastData,
1111                                                 CATimeoutCallback, NULL);
1112     if (CA_STATUS_OK != res)
1113     {
1114         OIC_LOG(ERROR, TAG, "Failed to Initialize Retransmission.");
1115         return res;
1116     }
1117
1118     CAInitializeAdapters();
1119 #endif // SINGLE_THREAD
1120
1121     return CA_STATUS_OK;
1122 }
1123
1124 void CATerminateMessageHandler()
1125 {
1126 #ifndef SINGLE_THREAD
1127     CATransportAdapter_t connType;
1128     u_arraylist_t *list = CAGetSelectedNetworkList();
1129     uint32_t length = u_arraylist_length(list);
1130
1131     uint32_t i = 0;
1132     for (i = 0; i < length; i++)
1133     {
1134         void* ptrType = u_arraylist_get(list, i);
1135
1136         if (NULL == ptrType)
1137         {
1138             continue;
1139         }
1140
1141         connType = *(CATransportAdapter_t *)ptrType;
1142         CAStopAdapter(connType);
1143     }
1144
1145     // stop retransmission
1146     if (NULL != g_retransmissionContext.threadMutex)
1147     {
1148         CARetransmissionStop(&g_retransmissionContext);
1149     }
1150
1151     // stop thread
1152     // delete thread data
1153     if (NULL != g_sendThread.threadMutex)
1154     {
1155         CAQueueingThreadStop(&g_sendThread);
1156     }
1157
1158     // stop thread
1159     // delete thread data
1160     if (NULL != g_receiveThread.threadMutex)
1161     {
1162 #ifndef SINGLE_HANDLE // This will be enabled when RI supports multi threading
1163         CAQueueingThreadStop(&g_receiveThread);
1164 #endif
1165     }
1166
1167     // destroy thread pool
1168     if (NULL != g_threadPoolHandle)
1169     {
1170         ca_thread_pool_free(g_threadPoolHandle);
1171         g_threadPoolHandle = NULL;
1172     }
1173
1174 #ifdef WITH_BWT
1175     CATerminateBlockWiseTransfer();
1176 #endif
1177     CARetransmissionDestroy(&g_retransmissionContext);
1178     CAQueueingThreadDestroy(&g_sendThread);
1179     CAQueueingThreadDestroy(&g_receiveThread);
1180
1181     // terminate interface adapters by controller
1182     CATerminateAdapters();
1183 #else
1184     // terminate interface adapters by controller
1185     CATerminateAdapters();
1186
1187     // stop retransmission
1188     CARetransmissionStop(&g_retransmissionContext);
1189     CARetransmissionDestroy(&g_retransmissionContext);
1190 #endif // SINGLE_THREAD
1191 }
1192
1193 void CALogPDUInfo(coap_pdu_t *pdu, const CAEndpoint_t *endpoint)
1194 {
1195     VERIFY_NON_NULL_VOID(pdu, TAG, "pdu");
1196     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint");
1197
1198     OIC_LOG_V(DEBUG, TAG, "PDU Maker - payload : %s", pdu->data);
1199
1200 #ifdef WITH_TCP
1201     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
1202     {
1203         OIC_LOG(DEBUG, TAG, "pdu header data :");
1204         OIC_LOG_BUFFER(DEBUG, TAG,  (const uint8_t *) pdu->hdr, pdu->length);
1205     }
1206     else
1207 #endif
1208     {
1209         OIC_LOG_V(DEBUG, TAG, "PDU Maker - type : %d", pdu->hdr->coap_hdr_udp_t.type);
1210
1211         OIC_LOG_V(DEBUG, TAG, "PDU Maker - code : %d", pdu->hdr->coap_hdr_udp_t.code);
1212
1213         OIC_LOG(DEBUG, TAG, "PDU Maker - token :");
1214
1215         OIC_LOG_BUFFER(DEBUG, TAG, pdu->hdr->coap_hdr_udp_t.token,
1216                        pdu->hdr->coap_hdr_udp_t.token_length);
1217     }
1218 }
1219
1220 static void CALogPayloadInfo(CAInfo_t *info)
1221 {
1222     if (info)
1223     {
1224         if (info->options)
1225         {
1226             for (uint32_t i = 0; i < info->numOptions; i++)
1227             {
1228                 OIC_LOG_V(DEBUG, TAG, "optionID: %u", info->options[i].optionID);
1229
1230                 OIC_LOG_V(DEBUG, TAG, "list: %s", info->options[i].optionData);
1231             }
1232         }
1233
1234         if (info->payload)
1235         {
1236             OIC_LOG_V(DEBUG, TAG, "payload: %p(%zu)", info->payload,
1237                       info->payloadSize);
1238         }
1239
1240         if (info->token)
1241         {
1242             OIC_LOG(DEBUG, TAG, "token:");
1243             OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *) info->token,
1244                            info->tokenLength);
1245         }
1246         OIC_LOG_V(DEBUG, TAG, "msgID: %u", info->messageId);
1247     }
1248     else
1249     {
1250         OIC_LOG(DEBUG, TAG, "info is NULL, cannot output log data");
1251     }
1252 }
1253
1254 void CAErrorHandler(const CAEndpoint_t *endpoint,
1255                     const void *data, uint32_t dataLen,
1256                     CAResult_t result)
1257 {
1258     OIC_LOG(DEBUG, TAG, "CAErrorHandler IN");
1259
1260 #ifndef SINGLE_THREAD
1261     VERIFY_NON_NULL_VOID(endpoint, TAG, "remoteEndpoint");
1262     VERIFY_NON_NULL_VOID(data, TAG, "data");
1263
1264     uint32_t code = CA_NOT_FOUND;
1265     //Do not free remoteEndpoint and data. Currently they will be freed in data thread
1266     //Get PDU data
1267     coap_pdu_t *pdu = (coap_pdu_t *)CAParsePDU((const char *)data, dataLen, &code, endpoint);
1268     if (NULL == pdu)
1269     {
1270         OIC_LOG(ERROR, TAG, "Parse PDU failed");
1271         return;
1272     }
1273
1274     CAData_t *cadata = CAGenerateHandlerData(endpoint, NULL, pdu, CA_ERROR_DATA);
1275     if (!cadata)
1276     {
1277         OIC_LOG(ERROR, TAG, "CAErrorHandler, CAGenerateHandlerData failed!");
1278         coap_delete_pdu(pdu);
1279         return;
1280     }
1281
1282     cadata->errorInfo->result = result;
1283
1284     CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
1285     coap_delete_pdu(pdu);
1286 #endif
1287
1288     OIC_LOG(DEBUG, TAG, "CAErrorHandler OUT");
1289     return;
1290 }
1291
1292 static void CASendErrorInfo(const CAEndpoint_t *endpoint, const CAInfo_t *info, CAResult_t result)
1293 {
1294     OIC_LOG(DEBUG, TAG, "CASendErrorInfo IN");
1295 #ifndef SINGLE_THREAD
1296     CAData_t *cadata = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
1297     if (!cadata)
1298     {
1299         OIC_LOG(ERROR, TAG, "cadata memory allocation failed");
1300         return;
1301     }
1302
1303     CAEndpoint_t* ep = CACloneEndpoint(endpoint);
1304     if (!ep)
1305     {
1306         OIC_LOG(ERROR, TAG, "endpoint clone failed");
1307         OICFree(cadata);
1308         return;
1309     }
1310
1311     CAErrorInfo_t *errorInfo = (CAErrorInfo_t *)OICCalloc(1, sizeof (CAErrorInfo_t));
1312     if (!errorInfo)
1313     {
1314         OIC_LOG(ERROR, TAG, "errorInfo memory allocation failed");
1315         OICFree(cadata);
1316         CAFreeEndpoint(ep);
1317         return;
1318     }
1319
1320     CAResult_t res = CACloneInfo(info, &errorInfo->info);
1321     if (CA_STATUS_OK != res)
1322     {
1323         OIC_LOG(ERROR, TAG, "info clone failed");
1324         OICFree(cadata);
1325         OICFree(errorInfo);
1326         CAFreeEndpoint(ep);
1327         return;
1328     }
1329
1330     errorInfo->result = result;
1331     cadata->remoteEndpoint = ep;
1332     cadata->errorInfo = errorInfo;
1333     cadata->dataType = CA_ERROR_DATA;
1334
1335     CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
1336 #endif
1337     OIC_LOG(DEBUG, TAG, "CASendErrorInfo OUT");
1338 }