Merge branch 'master' into simulator.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / cablockwisetransfer.c
1 /* ****************************************************************
2  *
3  * Copyright 2015 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 // Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
22 // definitions that may otherwise be skipped. Skipping can cause implicit
23 // declaration warnings and/or bugs and subtle problems in code execution.
24 // For glibc information on feature test macros,
25 // Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
26 //
27 // This file requires #define use due to random()
28 // For details on compatibility and glibc support,
29 // Refer http://www.gnu.org/software/libc/manual/html_node/BSD-Random.html
30 #define _DEFAULT_SOURCE
31 #define _BSD_SOURCE
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "caadapterutils.h"
38 #include "cainterface.h"
39 #include "camessagehandler.h"
40 #include "caremotehandler.h"
41 #include "cablockwisetransfer.h"
42 #include "oic_malloc.h"
43 #include "camutex.h"
44 #include "logger.h"
45
46 #define TAG "CA_BWT"
47
48 #define BLOCKWISE_OPTION_BUFFER    (sizeof(unsigned int))
49 #define BLOCK_NUMBER_IDX           4
50 #define BLOCK_M_BIT_IDX            3
51 #define PORT_LENGTH                2
52
53 #define BLOCK_SIZE(arg) (1 << ((arg) + 4))
54
55 // context for block-wise transfer
56 static CABlockWiseContext_t g_context = { 0 };
57
58 static bool CACheckPayloadLength(const CAData_t *sendData)
59 {
60     size_t payloadLen = 0;
61     CAGetPayloadInfo(sendData, &payloadLen);
62
63     // check if message has to be transfered to a block
64     size_t maxBlockSize = BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE);
65     OIC_LOG_V(DEBUG, TAG, "payloadLen=%zu, maxBlockSize=%zu", payloadLen, maxBlockSize);
66
67     if (payloadLen <= maxBlockSize)
68     {
69         return false;
70     }
71
72     return true;
73 }
74
75 CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc sendThreadFunc,
76                                          CAReceiveThreadFunc receivedThreadFunc)
77 {
78     OIC_LOG(DEBUG, TAG, "initialize");
79
80     // set block-wise transfer context
81     if (!g_context.sendThreadFunc)
82     {
83         g_context.sendThreadFunc = sendThreadFunc;
84     }
85
86     if (!g_context.receivedThreadFunc)
87     {
88         g_context.receivedThreadFunc = receivedThreadFunc;
89     }
90
91     if (!g_context.dataList)
92     {
93         g_context.dataList = u_arraylist_create();
94     }
95
96     CAResult_t res = CAInitBlockWiseMutexVariables();
97     if (CA_STATUS_OK != res)
98     {
99         OIC_LOG(ERROR, TAG, "init has failed");
100     }
101
102     return res;
103 }
104
105 CAResult_t CATerminateBlockWiseTransfer()
106 {
107     OIC_LOG(DEBUG, TAG, "terminate");
108
109     if (g_context.dataList)
110     {
111         u_arraylist_free(&g_context.dataList);
112     }
113
114     CATerminateBlockWiseMutexVariables();
115
116     return CA_STATUS_OK;
117 }
118
119 CAResult_t CAInitBlockWiseMutexVariables()
120 {
121     if (!g_context.blockDataListMutex)
122     {
123         g_context.blockDataListMutex = ca_mutex_new();
124         if (!g_context.blockDataListMutex)
125         {
126             OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
127             return CA_STATUS_FAILED;
128         }
129     }
130
131     if (!g_context.blockDataSenderMutex)
132     {
133         g_context.blockDataSenderMutex = ca_mutex_new();
134         if (!g_context.blockDataSenderMutex)
135         {
136             OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
137             CATerminateBlockWiseMutexVariables();
138             return CA_STATUS_FAILED;
139         }
140     }
141
142     return CA_STATUS_OK;
143 }
144
145 void CATerminateBlockWiseMutexVariables()
146 {
147     if (g_context.blockDataListMutex)
148     {
149         ca_mutex_free(g_context.blockDataListMutex);
150         g_context.blockDataListMutex = NULL;
151     }
152
153     if (g_context.blockDataSenderMutex)
154     {
155         ca_mutex_free(g_context.blockDataSenderMutex);
156         g_context.blockDataSenderMutex = NULL;
157     }
158 }
159
160 CAResult_t CASendBlockWiseData(const CAData_t *sendData)
161 {
162     VERIFY_NON_NULL(sendData, TAG, "sendData");
163
164     // check if message type is CA_MSG_RESET
165     if (sendData->requestInfo)
166     {
167         if (CA_MSG_RESET == sendData->requestInfo->info.type)
168         {
169             OIC_LOG(DEBUG, TAG, "reset message can't be sent to the block");
170             return CA_NOT_SUPPORTED;
171         }
172     }
173     else if (sendData->responseInfo)
174     {
175         if (CA_MSG_RESET == sendData->responseInfo->info.type)
176         {
177             OIC_LOG(DEBUG, TAG, "reset message can't be sent to the block");
178             return CA_NOT_SUPPORTED;
179         }
180     }
181
182     // #1. check if it is already included in block data list
183     CABlockData_t *currData = NULL;
184     CAResult_t res = CACheckBlockDataValidation(sendData, &currData);
185     if (CA_STATUS_OK != res)
186     {
187         // #2. if it is not included, add the data into list
188         if (!currData)
189         {
190             OIC_LOG(DEBUG, TAG, "There is no block data");
191
192             bool isBlock = CACheckPayloadLength(sendData);
193             if (!isBlock)
194             {
195                 if (sendData->requestInfo)
196                 {
197                     currData = CACreateNewBlockData(sendData);
198                     if (!currData)
199                     {
200                         OIC_LOG(ERROR, TAG, "failed to create block data");
201                         return CA_MEMORY_ALLOC_FAILED;
202                     }
203                 }
204                 return CA_NOT_SUPPORTED;
205             }
206             currData = CACreateNewBlockData(sendData);
207             if (!currData)
208             {
209                 OIC_LOG(ERROR, TAG, "failed to create block data");
210                 return CA_MEMORY_ALLOC_FAILED;
211             }
212         }
213     }
214
215     // #3. check request/response block option type and payload length
216     res = CACheckBlockOptionType(currData);
217     if (CA_STATUS_OK == res)
218     {
219         // #4. send block message
220         OIC_LOG(DEBUG, TAG, "send first block msg");
221         res = CAAddSendThreadQueue(currData->sentData,
222                                    (const CABlockDataID_t *)&currData->blockDataId);
223         if (CA_STATUS_OK != res)
224         {
225             OIC_LOG(ERROR, TAG, "add has failed");
226             return res;
227         }
228     }
229
230     return res;
231 }
232
233 CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const CABlockDataID_t *blockID)
234 {
235     VERIFY_NON_NULL(sendData, TAG, "sendData");
236     VERIFY_NON_NULL(blockID, TAG, "blockID");
237
238     CAData_t *cloneData = CACloneCAData(sendData);
239     if (!cloneData)
240     {
241         OIC_LOG(ERROR, TAG, "clone has failed");
242         CARemoveBlockDataFromList(blockID);
243         return CA_STATUS_FAILED;
244     }
245
246     if (g_context.sendThreadFunc)
247     {
248         ca_mutex_lock(g_context.blockDataSenderMutex);
249         g_context.sendThreadFunc(cloneData);
250         ca_mutex_unlock(g_context.blockDataSenderMutex);
251     }
252     else
253     {
254         CADestroyDataSet(cloneData);
255     }
256     return CA_STATUS_OK;
257 }
258
259 CAResult_t CACheckBlockOptionType(CABlockData_t *currData)
260 {
261     VERIFY_NON_NULL(currData, TAG, "currData");
262     VERIFY_NON_NULL(currData->sentData, TAG, "currData->sentData");
263
264     bool isBlock = CACheckPayloadLength(currData->sentData);
265     if (!isBlock)
266     {
267         return CA_NOT_SUPPORTED;
268     }
269
270     // set block option (COAP_OPTION_BLOCK2 or COAP_OPTION_BLOCK1)
271     if (currData->sentData->requestInfo) // request message
272     {
273         currData->type = COAP_OPTION_BLOCK1;
274     }
275     else // response message
276     {
277         currData->type = COAP_OPTION_BLOCK2;
278     }
279
280     return CA_STATUS_OK;
281 }
282
283 // TODO make pdu const after libcoap is updated to support that.
284 CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
285                                   const CAData_t *receivedData, size_t dataLen)
286 {
287     OIC_LOG(DEBUG, TAG, "CAReceiveBlockWiseData");
288     VERIFY_NON_NULL(pdu, TAG, "pdu");
289     VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
290     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
291     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
292
293     // check if received message type is CA_MSG_RESET
294     if (CA_EMPTY == pdu->hdr->coap_hdr_udp_t.code)
295     {
296         OIC_LOG(DEBUG, TAG, "code is CA_EMPTY..");
297
298         // get token from block-wise transfer list when CA_EMPTY(RST/ACK) is received
299         CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint, receivedData->responseInfo);
300         if (CA_STATUS_OK != res)
301         {
302             OIC_LOG(ERROR, TAG, "fail to get token");
303             return res;
304         }
305
306         CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
307                 receivedData->responseInfo->info.token,
308                 receivedData->responseInfo->info.tokenLength,
309                 endpoint->port);
310         if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
311         {
312             // if retransmission is timeout, callback msg will be send without token.
313             if (NULL == blockDataID && !receivedData->responseInfo->info.token)
314             {
315                 OIC_LOG(INFO, TAG, "retransmission was stopped");
316                 return CA_REQUEST_TIMEOUT;
317             }
318             else
319             {
320                 OIC_LOG(ERROR, TAG, "blockId is null");
321                 CADestroyBlockID(blockDataID);
322                 return CA_STATUS_FAILED;
323             }
324         }
325
326         CARemoveBlockDataFromList(blockDataID);
327         CADestroyBlockID(blockDataID);
328         return CA_NOT_SUPPORTED;
329     }
330
331     // check if block option is set and get block data
332     coap_block_t block = {0, 0, 0};
333
334     // get block1 option
335     int isBlock1 = coap_get_block(pdu, COAP_OPTION_BLOCK1, &block);
336     if (isBlock1)
337     {
338         CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, block, dataLen);
339         if (CA_STATUS_OK != res)
340         {
341             OIC_LOG(ERROR, TAG, "setting has failed");
342             return res;
343         }
344     }
345
346     // get block2 option
347     int isBlock2 = coap_get_block(pdu, COAP_OPTION_BLOCK2, &block);
348     if (isBlock2)
349     {
350         CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, block, dataLen);
351         if (CA_STATUS_OK != res)
352         {
353             OIC_LOG(ERROR, TAG, "setting has failed");
354             return res;
355         }
356     }
357
358     // check if there is error code
359     if (!isBlock1 && !isBlock2)
360     {
361         uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
362         if (CA_REQUEST_ENTITY_INCOMPLETE == code)
363         {
364             CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
365                     (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
366                      pdu->hdr->coap_hdr_udp_t.token_length,
367                      endpoint->port);
368
369             if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
370             {
371                 OIC_LOG(ERROR, TAG, "blockId is null");
372                 CADestroyBlockID(blockDataID);
373                 return CA_STATUS_FAILED;
374             }
375
376             CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
377             if (!data)
378             {
379                 OIC_LOG(ERROR, TAG, "getting has failed");
380                 CADestroyBlockID(blockDataID);
381                 return CA_STATUS_FAILED;
382             }
383
384             if (COAP_OPTION_BLOCK2 == data->type)
385             {
386                 coap_block_t *block2 = CAGetBlockOption(blockDataID, COAP_OPTION_BLOCK2);
387                 if (!block2)
388                 {
389                     OIC_LOG(ERROR, TAG, "block is null");
390                     CADestroyBlockID(blockDataID);
391                     return CA_STATUS_FAILED;
392                 }
393
394                 CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, *block2,
395                                                        dataLen);
396                 if (CA_STATUS_OK != res)
397                 {
398                     OIC_LOG(ERROR, TAG, "setting has failed");
399                     CADestroyBlockID(blockDataID);
400                     return res;
401                 }
402             }
403             else if (COAP_OPTION_BLOCK1 == data->type)
404             {
405                 coap_block_t *block1 = CAGetBlockOption(blockDataID, COAP_OPTION_BLOCK1);
406                 if (!block1)
407                 {
408                     OIC_LOG(ERROR, TAG, "block is null");
409                     CADestroyBlockID(blockDataID);
410                     return CA_STATUS_FAILED;
411                 }
412
413                 CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, *block1,
414                                                        dataLen);
415                 if (CA_STATUS_OK != res)
416                 {
417                     OIC_LOG(ERROR, TAG, "setting has failed");
418                     CADestroyBlockID(blockDataID);
419                     return res;
420                 }
421             }
422         }
423         else
424         {
425             // normal pdu data
426             OIC_LOG(DEBUG, TAG, "it's normal pdu");
427
428             // if received data is response message
429             // and sent data remain in block data list, remove block data
430             if (receivedData->responseInfo)
431             {
432                 CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
433                         (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
434                         pdu->hdr->coap_hdr_udp_t.token_length,
435                         endpoint->port);
436                 if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
437                 {
438                     OIC_LOG(ERROR, TAG, "blockId is null");
439                     CADestroyBlockID(blockDataID);
440                     return CA_STATUS_FAILED;
441                 }
442
443                 CARemoveBlockDataFromList(blockDataID);
444                 CADestroyBlockID(blockDataID);
445             }
446             return CA_NOT_SUPPORTED;
447         }
448     }
449
450     return CA_STATUS_OK;
451 }
452
453 CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData,
454                              uint8_t blockWiseStatus, const CABlockDataID_t *blockID)
455 {
456     VERIFY_NON_NULL(pdu, TAG, "pdu");
457     VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
458     VERIFY_NON_NULL(blockID, TAG, "blockID");
459
460     CAResult_t res = CA_STATUS_OK;
461     CAData_t *data = NULL;
462
463     // process blockWiseStatus
464     switch (blockWiseStatus)
465     {
466         case CA_OPTION2_FIRST_BLOCK:
467             res = CAAddSendThreadQueue(receivedData, blockID);
468             if (CA_STATUS_OK != res)
469             {
470                 OIC_LOG(ERROR, TAG, "add has failed");
471                 return res;
472             }
473             break;
474
475         case CA_OPTION2_CON:
476             // add data to send thread
477             data = CAGetDataSetFromBlockDataList(blockID);
478             if (!data)
479             {
480                 OIC_LOG(ERROR, TAG, "it's unavailable");
481                 return CA_STATUS_FAILED;
482             }
483
484             if (data->requestInfo)
485             {
486                 data->requestInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
487             }
488
489             if (data->responseInfo)
490             {
491                 data->responseInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
492             }
493
494             res = CAAddSendThreadQueue(data, blockID);
495             if (CA_STATUS_OK != res)
496             {
497                 OIC_LOG(ERROR, TAG, "add has failed");
498                 return res;
499             }
500
501             break;
502
503         case CA_OPTION1_ACK:
504         case CA_OPTION2_ACK:
505         case CA_SENT_PREVIOUS_NON_MSG:
506             res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
507                                      blockID);
508             if (CA_STATUS_OK != res)
509             {
510                 OIC_LOG(ERROR, TAG, "send has failed");
511                 return res;
512             }
513             break;
514
515         case CA_OPTION2_LAST_BLOCK:
516             // process last block and send upper layer
517             res = CAReceiveLastBlock(blockID, receivedData);
518             if (CA_STATUS_OK != res)
519             {
520                 OIC_LOG(ERROR, TAG, "receive has failed");
521                 return res;
522             }
523
524             // remove data from list
525             res = CARemoveBlockDataFromList(blockID);
526             if (CA_STATUS_OK != res)
527             {
528                 OIC_LOG(ERROR, TAG, "remove has failed");
529                 return res;
530             }
531             break;
532
533         case CA_OPTION1_NO_ACK_LAST_BLOCK:
534             // process last block and send upper layer
535             res = CAReceiveLastBlock(blockID, receivedData);
536             if (CA_STATUS_OK != res)
537             {
538                 OIC_LOG(ERROR, TAG, "receive has failed");
539                 return res;
540             }
541
542             if (CA_MSG_NONCONFIRM == pdu->hdr->coap_hdr_udp_t.type)
543             {
544                 // remove data from list
545                 res = CARemoveBlockDataFromList(blockID);
546                 if (CA_STATUS_OK != res)
547                 {
548                     OIC_LOG(ERROR, TAG, "remove has failed");
549                     return res;
550                 }
551             }
552             break;
553
554         case CA_OPTION1_NO_ACK_BLOCK:
555             if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
556             {
557                 // add data to send thread
558                 res = CASendBlockMessage(pdu, CA_MSG_ACKNOWLEDGE, blockWiseStatus,
559                                          blockID);
560                 if (CA_STATUS_OK != res)
561                 {
562                     OIC_LOG(ERROR, TAG, "send has failed");
563                     return res;
564                 }
565             }
566             break;
567
568         case CA_BLOCK_INCOMPLETE:
569             if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type ||
570                     CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
571             {
572                 // add data to send thread
573                 res = CASendErrorMessage(pdu, blockWiseStatus,
574                                          CA_REQUEST_ENTITY_INCOMPLETE,
575                                          blockID);
576                 if (CA_STATUS_OK != res)
577                 {
578                     OIC_LOG(ERROR, TAG, "send has failed");
579                     return res;
580                 }
581             }
582             break;
583
584         case CA_BLOCK_TOO_LARGE:
585             if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
586             {
587                 res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
588                                          blockID);
589                 if (CA_STATUS_OK != res)
590                 {
591                     OIC_LOG(ERROR, TAG, "send has failed");
592                     return res;
593                 }
594             }
595             else if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
596             {
597                 res = CASendErrorMessage(pdu, blockWiseStatus,
598                                          CA_REQUEST_ENTITY_TOO_LARGE,
599                                          blockID);
600                 if (CA_STATUS_OK != res)
601                 {
602                     OIC_LOG(ERROR, TAG, "send has failed");
603                     return res;
604                 }
605             }
606             break;
607         default:
608             OIC_LOG_V(ERROR, TAG, "no logic [%d]", blockWiseStatus);
609     }
610     return CA_STATUS_OK;
611 }
612
613 CAResult_t CASendBlockMessage(const coap_pdu_t *pdu, CAMessageType_t msgType,
614                               uint8_t status, const CABlockDataID_t *blockID)
615 {
616     VERIFY_NON_NULL(pdu, TAG, "pdu");
617     VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
618     VERIFY_NON_NULL(blockID, TAG, "blockID");
619
620     CAData_t *data = CAGetDataSetFromBlockDataList(blockID);
621     if (!data)
622     {
623         OIC_LOG(ERROR, TAG, "CAData is unavailable");
624         return CA_STATUS_FAILED;
625     }
626
627     if (CA_MSG_CONFIRM == msgType)
628     {
629         OIC_LOG(DEBUG, TAG, "need new msgID");
630         if (data->requestInfo)
631         {
632             data->requestInfo->info.messageId = 0;
633         }
634
635         if (data->responseInfo)
636         {
637             data->responseInfo->info.messageId = 0;
638         }
639     }
640     else if (CA_MSG_ACKNOWLEDGE == msgType)
641     {
642         if (data->responseInfo)
643         {
644             OIC_LOG(DEBUG, TAG, "set ACK message");
645             data->responseInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
646             data->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
647             if (CA_OPTION1_NO_ACK_LAST_BLOCK == status)
648             {
649                 data->responseInfo->result = CA_CHANGED;
650             }
651             else if (CA_OPTION1_NO_ACK_BLOCK == status)
652             {
653                 data->responseInfo->result = CA_CONTINUE;
654             }
655         }
656     }
657
658     // add data to send thread
659     CAResult_t res = CAAddSendThreadQueue(data, blockID);
660     if (CA_STATUS_OK != res)
661     {
662         OIC_LOG(ERROR, TAG, "add has failed");
663     }
664
665     return res;
666 }
667
668 CAResult_t CASendErrorMessage(const coap_pdu_t *pdu, uint8_t status,
669                               CAResponseResult_t responseResult,
670                               const CABlockDataID_t *blockID)
671 {
672     VERIFY_NON_NULL(pdu, TAG, "pdu");
673     VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
674     VERIFY_NON_NULL(blockID, TAG, "blockID");
675
676     // create error responseInfo
677     CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockID);
678     if (!data)
679     {
680         OIC_LOG(ERROR, TAG, "data is unavailable");
681         return CA_STATUS_FAILED;
682     }
683
684     CAData_t *cloneData = NULL;
685     if (data->sentData && data->sentData->responseInfo)
686     {
687         data->sentData->responseInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
688         data->sentData->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
689         data->sentData->responseInfo->result = responseResult;
690         cloneData = CACloneCAData(data->sentData);
691         if (!cloneData)
692         {
693             OIC_LOG(ERROR, TAG, "clone has failed");
694             return CA_MEMORY_ALLOC_FAILED;
695         }
696         OIC_LOG(DEBUG, TAG, "set ACK message");
697     }
698     else if (data->sentData)
699     {
700         cloneData = CACreateNewDataSet(pdu, data->sentData->remoteEndpoint);
701         if(!cloneData)
702         {
703             OIC_LOG(ERROR, TAG, PCF("CACreateNewDataSet failed"));
704             return CA_MEMORY_ALLOC_FAILED;
705         }
706
707         cloneData->responseInfo->info.type = CA_MSG_CONFIRM;
708         cloneData->responseInfo->result = responseResult;
709         OIC_LOG(DEBUG, TAG, "set CON message");
710     }
711     else
712     {
713         OIC_LOG(ERROR, TAG, "data has no sent-data");
714         return CA_MEMORY_ALLOC_FAILED;
715     }
716
717     // add data to send thread
718     if (g_context.sendThreadFunc)
719     {
720         ca_mutex_lock(g_context.blockDataSenderMutex);
721         g_context.sendThreadFunc(cloneData);
722         ca_mutex_unlock(g_context.blockDataSenderMutex);
723     }
724     else
725     {
726         CADestroyDataSet(cloneData);
727     }
728
729     // if error code is 4.08, remove the stored payload and initialize block number
730     if (CA_BLOCK_INCOMPLETE == status)
731     {
732         OICFree(data->payload);
733         data->payload = NULL;
734         data->payloadLength = 0;
735         data->receivedPayloadLen = 0;
736         data->block1.num = 0;
737         data->block2.num = 0;
738     }
739
740     return CA_STATUS_OK;
741 }
742
743 CAResult_t CAReceiveLastBlock(const CABlockDataID_t *blockID,
744                               const CAData_t *receivedData)
745 {
746     VERIFY_NON_NULL(blockID, TAG, "blockID");
747     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
748
749     // total block data have to notify to Application
750     CAData_t *cloneData = CACloneCAData(receivedData);
751     if (!cloneData)
752     {
753         OIC_LOG(ERROR, TAG, "clone has failed");
754         return CA_MEMORY_ALLOC_FAILED;
755     }
756
757     // update payload
758     size_t fullPayloadLen = 0;
759     CAPayload_t fullPayload = CAGetPayloadFromBlockDataList(blockID,
760                                                             &fullPayloadLen);
761     if (fullPayload)
762     {
763         CAResult_t res = CAUpdatePayloadToCAData(cloneData, fullPayload, fullPayloadLen);
764         if (CA_STATUS_OK != res)
765         {
766             OIC_LOG(ERROR, TAG, "update has failed");
767             CADestroyDataSet(cloneData);
768             return res;
769         }
770     }
771
772     if (g_context.receivedThreadFunc)
773     {
774         g_context.receivedThreadFunc(cloneData);
775     }
776     else
777     {
778         CADestroyDataSet(cloneData);
779     }
780
781     return CA_STATUS_OK;
782 }
783
784 // TODO make pdu const after libcoap is updated to support that.
785 CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
786                                  const CAData_t *receivedData, coap_block_t block,
787                                  size_t dataLen)
788 {
789     OIC_LOG(INFO, TAG, "CASetNextBlockOption1");
790     VERIFY_NON_NULL(pdu, TAG, "pdu");
791     VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
792     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
793     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
794
795     OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
796
797     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
798             (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
799             pdu->hdr->coap_hdr_udp_t.token_length,
800             endpoint->port);
801
802     if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
803     {
804         OIC_LOG(ERROR, TAG, "blockId is null");
805         CADestroyBlockID(blockDataID);
806         return CA_STATUS_FAILED;
807     }
808
809     // BlockData data is created if it not existed
810     if (!CAIsBlockDataInList(blockDataID))
811     {
812         OIC_LOG(DEBUG, TAG, "no message in list");
813
814         CAData_t *data = CACreateNewDataSet(pdu, endpoint);
815         if (!data)
816         {
817             OIC_LOG(ERROR, TAG, "data is null");
818             CADestroyBlockID(blockDataID);
819             return CA_STATUS_FAILED;
820         }
821
822         CABlockData_t *currData = CACreateNewBlockData(data);
823         if (!currData)
824         {
825             OIC_LOG(ERROR, TAG, "currData is null");
826             CADestroyDataSet(data);
827             CADestroyBlockID(blockDataID);
828             return CA_STATUS_FAILED;
829         }
830         CADestroyDataSet(data);
831     }
832
833     // update BLOCK OPTION1 type
834     CAResult_t res = CAUpdateBlockOptionType(blockDataID,
835                                              COAP_OPTION_BLOCK1);
836     if (CA_STATUS_OK != res)
837     {
838         OIC_LOG(ERROR, TAG, "update has failed");
839         CARemoveBlockDataFromList(blockDataID);
840         CADestroyBlockID(blockDataID);
841         return res;
842     }
843
844     CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
845     if (!data)
846     {
847         OIC_LOG(ERROR, TAG, "getting has failed");
848         CADestroyBlockID(blockDataID);
849         return CA_STATUS_FAILED;
850     }
851
852     uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
853     // received type from remote device
854     if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
855     {
856         uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
857         if (0 == block.m &&
858                 (CA_REQUEST_ENTITY_INCOMPLETE != code && CA_REQUEST_ENTITY_TOO_LARGE != code))
859         {
860             int isBlock2 = coap_get_block(pdu, COAP_OPTION_BLOCK2, &block);
861             if (isBlock2)
862             {
863                 OIC_LOG(INFO, TAG, "received data is combining block1 and block2");
864                 // initialize block number for response message
865                 data->block1.num = 0;
866                 CADestroyBlockID(blockDataID);
867                 return CA_STATUS_OK;
868             }
869             else
870             {
871                 OIC_LOG(INFO, TAG, "received data is not bulk data");
872                 CAReceiveLastBlock(blockDataID, receivedData);
873                 CARemoveBlockDataFromList(blockDataID);
874                 CADestroyBlockID(blockDataID);
875                 return CA_STATUS_OK;
876             }
877         }
878
879         blockWiseStatus = CA_OPTION1_ACK;
880         res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
881         if (CA_STATUS_OK != res)
882         {
883             OIC_LOG(ERROR, TAG, "update has failed");
884             CADestroyBlockID(blockDataID);
885             return res;
886         }
887
888         res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK1);
889         if (CA_STATUS_OK != res)
890         {
891             OIC_LOG(ERROR, TAG, "update has failed");
892             CARemoveBlockDataFromList(blockDataID);
893             CADestroyBlockID(blockDataID);
894             return res;
895         }
896     }
897     else // CON or NON message
898     {
899         OIC_LOG_V(INFO, TAG, "num:%d, M:%d", block.num, block.m);
900
901         // check the size option
902         bool isSizeOption = CAIsPayloadLengthInPduWithBlockSizeOption(pdu,
903                                                                       COAP_OPTION_SIZE1,
904                                                                       &(data->payloadLength));
905
906         // check if received payload is exact
907         if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
908         {
909             blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
910                                                     COAP_OPTION_BLOCK1, dataLen);
911         }
912
913         if (CA_BLOCK_RECEIVED_ALREADY != blockWiseStatus)
914         {
915             // store the received payload and merge
916             res = CAUpdatePayloadData(data, receivedData, blockWiseStatus,
917                                       isSizeOption, COAP_OPTION_BLOCK1);
918             if (CA_STATUS_OK != res)
919             {
920                 OIC_LOG(ERROR, TAG, "update has failed");
921                 CARemoveBlockDataFromList(blockDataID);
922                 CADestroyBlockID(blockDataID);
923                 return res;
924             }
925
926             res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
927             if (CA_STATUS_OK != res)
928             {
929                 OIC_LOG(ERROR, TAG, "update has failed");
930                 CARemoveBlockDataFromList(blockDataID);
931                 CADestroyBlockID(blockDataID);
932                 return res;
933             }
934
935             // update block data
936             res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK1);
937             if (CA_STATUS_OK != res)
938             {
939                 OIC_LOG(ERROR, TAG, "update has failed");
940                 CARemoveBlockDataFromList(blockDataID);
941                 CADestroyBlockID(blockDataID);
942                 return res;
943             }
944         }
945
946         // check the blcok-wise transfer status for next step
947         if (CA_BLOCK_UNKNOWN == blockWiseStatus || CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
948         {
949             if (0 == block.m) // Last block is received
950             {
951                 OIC_LOG(DEBUG, TAG, "M bit is 0");
952                 blockWiseStatus = CA_OPTION1_NO_ACK_LAST_BLOCK;
953             }
954             else
955             {
956                 OIC_LOG(DEBUG, TAG, "M bit is 1");
957                 blockWiseStatus = CA_OPTION1_NO_ACK_BLOCK;
958             }
959         }
960     }
961
962     res = CAProcessNextStep(pdu, receivedData, blockWiseStatus, blockDataID);
963     if (CA_STATUS_OK != res)
964     {
965         OIC_LOG(ERROR, TAG, "setting has failed");
966         CARemoveBlockDataFromList(blockDataID);
967     }
968
969     CADestroyBlockID(blockDataID);
970     return res;
971 }
972
973 // TODO make pdu const after libcoap is updated to support that.
974 CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
975                                  const CAData_t *receivedData, coap_block_t block,
976                                  size_t dataLen)
977 {
978     OIC_LOG(DEBUG, TAG, "CASetNextBlockOption2");
979     OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
980
981     VERIFY_NON_NULL(pdu, TAG, "pdu");
982     VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
983     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
984     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
985
986     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
987             (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
988             pdu->hdr->coap_hdr_udp_t.token_length,
989             endpoint->port);
990
991     if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
992     {
993         OIC_LOG(ERROR, TAG, "blockId is null");
994         CADestroyBlockID(blockDataID);
995         return CA_STATUS_FAILED;
996     }
997
998     // BlockData data is created if it not existed
999     if (!CAIsBlockDataInList(blockDataID))
1000     {
1001         OIC_LOG(DEBUG, TAG, "no msg in list.");
1002
1003         CAData_t *data = CACreateNewDataSet(pdu, endpoint);
1004         if (!data)
1005         {
1006             OIC_LOG(ERROR, TAG, "data is null");
1007             CADestroyBlockID(blockDataID);
1008             return CA_STATUS_FAILED;
1009         }
1010
1011         CABlockData_t *currData = CACreateNewBlockData(data);
1012         if (!currData)
1013         {
1014             OIC_LOG(ERROR, TAG, "data is null");
1015             CADestroyDataSet(data);
1016             CADestroyBlockID(blockDataID);
1017             return CA_STATUS_FAILED;
1018         }
1019         CADestroyDataSet(data);
1020     }
1021
1022     // set Block Option Type
1023     CAResult_t res = CAUpdateBlockOptionType(blockDataID,
1024                                              COAP_OPTION_BLOCK2);
1025     if (CA_STATUS_OK != res)
1026     {
1027         OIC_LOG(ERROR, TAG, "update has failed");
1028         CARemoveBlockDataFromList(blockDataID);
1029         CADestroyBlockID(blockDataID);
1030         return res;
1031     }
1032
1033     CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
1034     if (!data)
1035     {
1036         OIC_LOG(ERROR, TAG, "getting has failed");
1037         CARemoveBlockDataFromList(blockDataID);
1038         CADestroyBlockID(blockDataID);
1039         return CA_STATUS_FAILED;
1040     }
1041
1042     uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
1043     if (0 == block.num && CA_GET == pdu->hdr->coap_hdr_udp_t.code && 0 == block.m)
1044     {
1045         OIC_LOG(INFO, TAG, "first block number");
1046
1047         res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2, blockWiseStatus);
1048         if (CA_STATUS_OK != res)
1049         {
1050             OIC_LOG(ERROR, TAG, "update has failed");
1051             CARemoveBlockDataFromList(blockDataID);
1052             CADestroyBlockID(blockDataID);
1053             return res;
1054         }
1055
1056         // first block data have to notify to Application
1057         res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
1058         if (CA_STATUS_OK != res)
1059         {
1060             OIC_LOG(ERROR, TAG, "update has failed");
1061             CARemoveBlockDataFromList(blockDataID);
1062             CADestroyBlockID(blockDataID);
1063             return res;
1064         }
1065         blockWiseStatus = CA_OPTION2_FIRST_BLOCK;
1066     }
1067     else
1068     {
1069         // received type from remote device
1070         if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type ||
1071                 (CA_MSG_NONCONFIRM == pdu->hdr->coap_hdr_udp_t.type &&
1072                         NULL != receivedData->responseInfo))
1073         {
1074             OIC_LOG(DEBUG, TAG, "received ACK or NON");
1075
1076             // check the size option
1077             bool isSizeOption = CAIsPayloadLengthInPduWithBlockSizeOption(pdu,
1078                                                                           COAP_OPTION_SIZE2,
1079                                                                           &(data->payloadLength));
1080
1081             // check if received payload is exact
1082             if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
1083             {
1084                 blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
1085                                                         COAP_OPTION_BLOCK2, dataLen);
1086             }
1087
1088             if (CA_BLOCK_RECEIVED_ALREADY != blockWiseStatus)
1089             {
1090                 // store the received payload and merge
1091                 res = CAUpdatePayloadData(data, receivedData, blockWiseStatus,
1092                                           isSizeOption, COAP_OPTION_BLOCK2);
1093                 if (CA_STATUS_OK != res)
1094                 {
1095                     OIC_LOG(ERROR, TAG, "update has failed");
1096                     CARemoveBlockDataFromList(blockDataID);
1097                     CADestroyBlockID(blockDataID);
1098                     return res;
1099                 }
1100             }
1101
1102             if (0 == block.m && CA_BLOCK_UNKNOWN == blockWiseStatus) // Last block is received
1103             {
1104                 OIC_LOG(DEBUG, TAG, "M bit is 0");
1105                 blockWiseStatus = CA_OPTION2_LAST_BLOCK;
1106             }
1107             else
1108             {
1109                 if (CA_BLOCK_UNKNOWN == blockWiseStatus ||
1110                         CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
1111                 {
1112                     OIC_LOG(DEBUG, TAG, "M bit is 1");
1113
1114                     if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
1115                     {
1116                         blockWiseStatus = CA_OPTION2_ACK;
1117                     }
1118                     else
1119                     {
1120                         blockWiseStatus = CA_OPTION2_NON;
1121                     }
1122                 }
1123
1124                 res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2,
1125                                                blockWiseStatus);
1126                 if (CA_STATUS_OK != res)
1127                 {
1128                     OIC_LOG(ERROR, TAG, "update has failed");
1129                     CARemoveBlockDataFromList(blockDataID);
1130                     CADestroyBlockID(blockDataID);
1131                     return res;
1132                 }
1133
1134                 res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
1135                 if (CA_STATUS_OK != res)
1136                 {
1137                     OIC_LOG(ERROR, TAG, "update has failed");
1138                     CARemoveBlockDataFromList(blockDataID);
1139                     CADestroyBlockID(blockDataID);
1140                     return res;
1141                 }
1142             }
1143         }
1144         else // CON message and so on.
1145         {
1146             OIC_LOG_V(INFO, TAG, "num:%d, M:%d", block.num, block.m);
1147
1148             blockWiseStatus = CA_OPTION2_CON;
1149
1150             res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2, blockWiseStatus);
1151             if (CA_STATUS_OK != res)
1152             {
1153                 OIC_LOG(ERROR, TAG, "update has failed");
1154                 CARemoveBlockDataFromList(blockDataID);
1155                 CADestroyBlockID(blockDataID);
1156                 return res;
1157             }
1158
1159             res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
1160             if (CA_STATUS_OK != res)
1161             {
1162                 OIC_LOG(ERROR, TAG, "update has failed");
1163                 CARemoveBlockDataFromList(blockDataID);
1164                 CADestroyBlockID(blockDataID);
1165                 return res;
1166             }
1167         }
1168     }
1169
1170     res = CAProcessNextStep(pdu, receivedData, blockWiseStatus, blockDataID);
1171     if (CA_STATUS_OK != res)
1172     {
1173         OIC_LOG(ERROR, TAG, "setting has failed");
1174         CARemoveBlockDataFromList(blockDataID);
1175         CADestroyBlockID(blockDataID);
1176         return res;
1177     }
1178
1179     CADestroyBlockID(blockDataID);
1180     return CA_STATUS_OK;
1181 }
1182
1183 CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *pdu,
1184                                     coap_block_t *block, uint16_t blockType,
1185                                     uint32_t status)
1186 {
1187     VERIFY_NON_NULL(currData, TAG, "currData");
1188     VERIFY_NON_NULL(pdu, TAG, "pdu");
1189     VERIFY_NON_NULL(block, TAG, "block");
1190
1191     // update block data
1192     CAResult_t res = CA_STATUS_OK;
1193     uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
1194
1195     if (CA_REQUEST_ENTITY_INCOMPLETE == code || CA_REQUEST_ENTITY_TOO_LARGE == code)
1196     {
1197         // response error code of the received block message
1198         res = CAHandleBlockErrorResponse(block, blockType, code);
1199         if (CA_STATUS_OK != res)
1200         {
1201             OIC_LOG(ERROR, TAG, "error handle has failed");
1202             return res;
1203         }
1204     }
1205     else
1206     {
1207         // update block option items
1208         switch (status)
1209         {
1210             case CA_OPTION1_ACK:
1211                 if (currData->block1.num > block->num)
1212                 {
1213                     OIC_LOG(ERROR, TAG, "received incorrect block num");
1214                     return CA_STATUS_FAILED;
1215                 }
1216                 block->num++;
1217                 break;
1218             case CA_OPTION2_NON:
1219                 block->num++;
1220                 block->m = 0;
1221                 break;
1222             case CA_OPTION2_CON:
1223                 block->m = 0;
1224                 break;
1225             case CA_OPTION2_ACK:
1226                 if (currData->block2.num > block->num)
1227                 {
1228                     OIC_LOG(ERROR, TAG, "received incorrect block num");
1229                     return CA_STATUS_FAILED;
1230                 }
1231                 block->num++;
1232                 block->m = 0;
1233                 break;
1234             case CA_BLOCK_TOO_LARGE:
1235                 // if state of received block message is CA_BLOCK_TOO_LARGE or CA_BLOCK_INCOMPLETE
1236                 // we set the response error code appropriately and send
1237                 if (COAP_OPTION_BLOCK2 == blockType)
1238                 {
1239                     block->num++;
1240                     block->m = 0;
1241                     block->szx = currData->block2.szx;
1242                 }
1243                 else
1244                 {
1245                     block->szx = currData->block1.szx;
1246                 }
1247                 break;
1248             default:
1249                 OIC_LOG_V(ERROR, TAG, "no logic [%d]", status);
1250         }
1251
1252         if (CA_BLOCK_INCOMPLETE != status && CA_BLOCK_TOO_LARGE != status)
1253         {
1254             // negotiate block size
1255             res = CANegotiateBlockSize(currData, block, pdu->hdr->coap_hdr_udp_t.type, blockType);
1256             if (CA_STATUS_OK != res)
1257             {
1258                 OIC_LOG(ERROR, TAG, "negotiation has failed");
1259                 return res;
1260             }
1261         }
1262     }
1263     return res;
1264 }
1265
1266 CAResult_t CAGetMoreBitFromBlock(size_t payloadLen, coap_block_t *block)
1267 {
1268     VERIFY_NON_NULL(block, TAG, "block");
1269
1270     if ((size_t)((block->num + 1) << (block->szx + BLOCK_NUMBER_IDX))
1271         < payloadLen)
1272     {
1273         OIC_LOG(DEBUG, TAG, "Set the M-bit(1)");
1274         block->m = 1;
1275     }
1276     else
1277     {
1278         OIC_LOG(DEBUG, TAG, "Set the M-bit(0)");
1279         block->m = 0;
1280     }
1281
1282     return CA_STATUS_OK;
1283 }
1284
1285 CAResult_t CANegotiateBlockSize(CABlockData_t *currData, coap_block_t *block,
1286                                 CAMessageType_t msgType, uint16_t blockType)
1287 {
1288     OIC_LOG(DEBUG, TAG, "IN-NegotiateBlockSize");
1289
1290     VERIFY_NON_NULL(currData, TAG, "currData");
1291     VERIFY_NON_NULL(block, TAG, "block");
1292
1293     // #1. check the block option type
1294     if (COAP_OPTION_BLOCK2 == blockType)
1295     {
1296         // #2. check the message type
1297         if (CA_MSG_ACKNOWLEDGE == msgType)
1298         {
1299             if (block->szx > currData->block2.szx)
1300             {
1301                 OIC_LOG(DEBUG, TAG, "sze is big");
1302
1303                 // #3. calculate new block number from block size
1304                 unsigned int blockNum = BLOCK_SIZE(block->szx) /
1305                                         BLOCK_SIZE(currData->block2.szx) - 1;
1306                 OIC_LOG(DEBUG, TAG, "num is set as Negotiation");
1307                 block->num += blockNum;
1308                 block->szx = currData->block2.szx;
1309                 OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
1310             }
1311         }
1312         else
1313         {
1314             if (block->szx > currData->block2.szx)
1315             {
1316                 OIC_LOG(DEBUG, TAG, "sze is big");
1317                 block->szx = currData->block2.szx;
1318             }
1319         }
1320     }
1321     else if (COAP_OPTION_BLOCK1 == blockType)
1322     {
1323         if (CA_MSG_ACKNOWLEDGE == msgType)
1324         {
1325             if (block->szx < currData->block1.szx)
1326             {
1327                 OIC_LOG(DEBUG, TAG, "sze is small");
1328
1329                 unsigned int blockNum = BLOCK_SIZE(currData->block1.szx) /
1330                                         BLOCK_SIZE(block->szx) - 1;
1331                 block->num += blockNum;
1332                 OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
1333             }
1334         }
1335         else
1336         {
1337             if (block->szx > currData->block1.szx)
1338             {
1339                 OIC_LOG(DEBUG, TAG, "sze is big");
1340                 block->szx = currData->block1.szx;
1341             }
1342         }
1343     }
1344     else
1345     {
1346         OIC_LOG(DEBUG, TAG, "Invalid block option");
1347         return CA_STATUS_FAILED;
1348     }
1349
1350     OIC_LOG(DEBUG, TAG, "OUT-NegotiateBlockSize");
1351
1352     return CA_STATUS_OK;
1353 }
1354
1355 CAResult_t CAUpdateBlockData(CABlockData_t *currData, coap_block_t block,
1356                              uint16_t blockType)
1357 {
1358     VERIFY_NON_NULL(currData, TAG, "currData");
1359
1360     // check if block size is bigger than CABlockSize_t
1361     if (block.szx > CA_BLOCK_SIZE_1024_BYTE)
1362     {
1363         OIC_LOG(DEBUG, TAG, "invalid block szx");
1364         return CA_STATUS_FAILED;
1365     }
1366
1367     // update block option
1368     if (COAP_OPTION_BLOCK2 == blockType)
1369     {
1370         currData->block2 = block;
1371     }
1372     else
1373     {
1374         currData->block1 = block;
1375     }
1376
1377     OIC_LOG(DEBUG, TAG, "data has updated");
1378     return CA_STATUS_OK;
1379 }
1380
1381 CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID)
1382 {
1383     VERIFY_NON_NULL(pdu, TAG, "pdu");
1384     VERIFY_NON_NULL(blockID, TAG, "blockID");
1385
1386     // if CON message is sent, update messageId in block-wise transfer list
1387     if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
1388     {
1389         CAData_t * cadata = CAGetDataSetFromBlockDataList(blockID);
1390         if (!cadata)
1391         {
1392             OIC_LOG(ERROR, TAG, "CAData is unavailable");
1393             return CA_STATUS_FAILED;
1394         }
1395
1396         if (cadata->requestInfo)
1397         {
1398             cadata->requestInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
1399         }
1400     }
1401
1402     return CA_STATUS_OK;
1403 }
1404
1405 CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t *info,
1406                             const CAEndpoint_t *endpoint, coap_list_t **options)
1407 {
1408     OIC_LOG(DEBUG, TAG, "IN-AddBlockOption");
1409     VERIFY_NON_NULL(pdu, TAG, "pdu");
1410     VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
1411     VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
1412     VERIFY_NON_NULL(info, TAG, "info");
1413     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
1414     VERIFY_NON_NULL(options, TAG, "options");
1415
1416     size_t dataLength = 0;
1417     if (info->payload)
1418     {
1419         dataLength = info->payloadSize;
1420         OIC_LOG_V(DEBUG, TAG, "dataLength - %zu", dataLength);
1421     }
1422
1423     OIC_LOG_V(DEBUG, TAG, "previous payload - %s", (*pdu)->data);
1424
1425     CAResult_t res = CA_STATUS_OK;
1426     uint32_t code = CA_RESPONSE_CODE((*pdu)->hdr->coap_hdr_udp_t.code);
1427     if (CA_REQUEST_ENTITY_INCOMPLETE == code)
1428     {
1429         OIC_LOG(INFO, TAG, "don't use option");
1430         return res;
1431     }
1432
1433     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
1434             (CAToken_t)(*pdu)->hdr->coap_hdr_udp_t.token,
1435             (*pdu)->hdr->coap_hdr_udp_t.token_length,
1436             endpoint->port);
1437
1438     if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
1439     {
1440         OIC_LOG(ERROR, TAG, "blockId is null");
1441         res = CA_STATUS_FAILED;
1442         goto exit;
1443     }
1444
1445     uint8_t blockType = CAGetBlockOptionType(blockDataID);
1446     if (COAP_OPTION_BLOCK2 == blockType)
1447     {
1448         res = CAAddBlockOption2(pdu, info, dataLength, blockDataID, options);
1449         if (CA_STATUS_OK != res)
1450         {
1451             OIC_LOG(ERROR, TAG, "add has failed");
1452             goto exit;
1453         }
1454     }
1455     else if (COAP_OPTION_BLOCK1 == blockType)
1456     {
1457         res = CAAddBlockOption1(pdu, info, dataLength, blockDataID, options);
1458         if (CA_STATUS_OK != res)
1459         {
1460             OIC_LOG(ERROR, TAG, "add has failed");
1461             goto exit;
1462         }
1463     }
1464     else
1465     {
1466         OIC_LOG(DEBUG, TAG, "no BLOCK option");
1467
1468         // in case it is not large data, add option list to pdu.
1469         if (*options)
1470         {
1471             for (coap_list_t *opt = *options; opt; opt = opt->next)
1472             {
1473                 OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
1474                           COAP_OPTION_DATA(*(coap_option *) opt->data));
1475
1476                 OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", (*pdu)->length);
1477                 coap_add_option(*pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
1478                                 COAP_OPTION_LENGTH(*(coap_option *) opt->data),
1479                                 COAP_OPTION_DATA(*(coap_option *) opt->data), coap_udp);
1480             }
1481         }
1482
1483         OIC_LOG_V(DEBUG, TAG, "[%d] pdu length after option", (*pdu)->length);
1484
1485         // if response data is so large. it have to send as block transfer
1486         if (!coap_add_data(*pdu, dataLength, (const unsigned char *) info->payload))
1487         {
1488             OIC_LOG(INFO, TAG, "it have to use block");
1489         }
1490         else
1491         {
1492             OIC_LOG(INFO, TAG, "not Blockwise Transfer");
1493             goto exit;
1494         }
1495     }
1496
1497     // if received message type is RESET from remote device,
1498     // we have to use the updated message id to find token.
1499     res = CAUpdateMessageId(*pdu, blockDataID);
1500     if (CA_STATUS_OK != res)
1501     {
1502         OIC_LOG(ERROR, TAG, "fail to update CON message id ");
1503         goto exit;
1504     }
1505
1506 exit:
1507     if (CA_ADAPTER_IP == endpoint->adapter && 0 == endpoint->port)
1508     {
1509         CARemoveBlockDataFromList(blockDataID);
1510     }
1511     CADestroyBlockID(blockDataID);
1512     OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption");
1513     return res;
1514 }
1515
1516 CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t *info, size_t dataLength,
1517                              const CABlockDataID_t *blockID, coap_list_t **options)
1518 {
1519     OIC_LOG(DEBUG, TAG, "IN-AddBlockOption2");
1520     VERIFY_NON_NULL(pdu, TAG, "pdu");
1521     VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
1522     VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
1523     VERIFY_NON_NULL(info, TAG, "info");
1524     VERIFY_NON_NULL(blockID, TAG, "blockID");
1525     VERIFY_NON_NULL(options, TAG, "options");
1526
1527     // get set block data from CABlock list-set.
1528     coap_block_t *block1 = CAGetBlockOption(blockID, COAP_OPTION_BLOCK1);
1529     coap_block_t *block2 = CAGetBlockOption(blockID, COAP_OPTION_BLOCK2);
1530     if (!block1 || !block2)
1531     {
1532         OIC_LOG(ERROR, TAG, "getting has failed");
1533         return CA_STATUS_FAILED;
1534     }
1535
1536     CALogBlockInfo(block2);
1537
1538     uint8_t code = 0;
1539     if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->coap_hdr_udp_t.type ||
1540             (CA_MSG_NONCONFIRM == (*pdu)->hdr->coap_hdr_udp_t.type &&
1541                     CA_GET != (*pdu)->hdr->coap_hdr_udp_t.code))
1542     {
1543         CAGetMoreBitFromBlock(dataLength, block2);
1544         CALogBlockInfo(block2);
1545
1546         // if block number is 0, add size2 option
1547         if (0 == block2->num)
1548         {
1549             CAResult_t res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE2, dataLength, options);
1550             if (CA_STATUS_OK != res)
1551             {
1552                 OIC_LOG(ERROR, TAG, "add has failed");
1553                 CARemoveBlockDataFromList(blockID);
1554                 return res;
1555             }
1556         }
1557
1558         CAResult_t res = CAAddBlockOptionImpl(block2, COAP_OPTION_BLOCK2, options);
1559         if (CA_STATUS_OK != res)
1560         {
1561             OIC_LOG(ERROR, TAG, "add has failed");
1562             CARemoveBlockDataFromList(blockID);
1563             return res;
1564         }
1565
1566         if (block1->num)
1567         {
1568             OIC_LOG(DEBUG, TAG, "combining block1 and block2");
1569             res = CAAddBlockOptionImpl(block1, COAP_OPTION_BLOCK1, options);
1570             if (CA_STATUS_OK != res)
1571             {
1572                 OIC_LOG(ERROR, TAG, "add has failed");
1573                 CARemoveBlockDataFromList(blockID);
1574                 return res;
1575             }
1576             // initialize block number
1577             block1->num = 0;
1578         }
1579
1580         res = CAAddOptionToPDU(*pdu, options);
1581         if (CA_STATUS_OK != res)
1582         {
1583             OIC_LOG(ERROR, TAG, "add has failed");
1584             CARemoveBlockDataFromList(blockID);
1585             return res;
1586         }
1587
1588         if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info->payload,
1589                             block2->num, block2->szx))
1590         {
1591             OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
1592             return CA_STATUS_FAILED;
1593         }
1594
1595         if (!block2->m)
1596         {
1597             // if sent message is last response block message, remove data
1598             CARemoveBlockDataFromList(blockID);
1599         }
1600         else
1601         {
1602             if (CA_MSG_NONCONFIRM == (*pdu)->hdr->coap_hdr_udp_t.type)
1603             {
1604                 OIC_LOG(DEBUG, TAG, "NON, send next block..");
1605                 // update block data
1606                 block2->num++;
1607                 CAResult_t res = CAProcessNextStep(*pdu, NULL,
1608                                                    CA_SENT_PREVIOUS_NON_MSG,
1609                                                    blockID);
1610                 if (CA_STATUS_OK != res)
1611                 {
1612                     OIC_LOG(ERROR, TAG, "failed to process next step");
1613                     CARemoveBlockDataFromList(blockID);
1614                     return res;
1615                 }
1616             }
1617         }
1618     }
1619     else
1620     {
1621         OIC_LOG(DEBUG, TAG, "option2, not ACK msg");
1622         CAResult_t res = CAAddBlockOptionImpl(block2, COAP_OPTION_BLOCK2, options);
1623         if (CA_STATUS_OK != res)
1624         {
1625             OIC_LOG(ERROR, TAG, "add has failed");
1626             CARemoveBlockDataFromList(blockID);
1627             return res;
1628         }
1629
1630         res = CAAddOptionToPDU(*pdu, options);
1631         if (CA_STATUS_OK != res)
1632         {
1633             OIC_LOG(ERROR, TAG, "add has failed");
1634             CARemoveBlockDataFromList(blockID);
1635             return res;
1636         }
1637     }
1638
1639     return CA_STATUS_OK;
1640
1641 error:
1642     OIC_LOG_V(ERROR, TAG, "error : %d", code);
1643
1644     char* phrase = coap_response_phrase(code);
1645     if(phrase)
1646     {
1647         coap_add_data(*pdu, strlen(phrase),
1648                       (unsigned char *) phrase);
1649     }
1650     return CA_STATUS_FAILED;
1651 }
1652
1653 CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t dataLength,
1654                              const CABlockDataID_t *blockID, coap_list_t **options)
1655 {
1656     OIC_LOG(DEBUG, TAG, "IN-AddBlockOption1");
1657     VERIFY_NON_NULL(pdu, TAG, "pdu");
1658     VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
1659     VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
1660     VERIFY_NON_NULL(info, TAG, "info");
1661     VERIFY_NON_NULL(blockID, TAG, "blockID");
1662     VERIFY_NON_NULL(options, TAG, "options");
1663
1664     // get set block data from CABlock list-set.
1665     coap_block_t *block1 = CAGetBlockOption(blockID, COAP_OPTION_BLOCK1);
1666     if (!block1)
1667     {
1668         OIC_LOG(ERROR, TAG, "getting has failed");
1669         return CA_STATUS_FAILED;
1670     }
1671
1672     CALogBlockInfo(block1);
1673
1674     if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->coap_hdr_udp_t.type)
1675     {
1676         OIC_LOG(DEBUG, TAG, "option1 and ACK msg..");
1677         CAResult_t res = CAAddBlockOptionImpl(block1, COAP_OPTION_BLOCK1, options);
1678         if (CA_STATUS_OK != res)
1679         {
1680             OIC_LOG(ERROR, TAG, "add has failed");
1681             CARemoveBlockDataFromList(blockID);
1682             return res;
1683         }
1684
1685         res = CAAddOptionToPDU(*pdu, options);
1686         if (CA_STATUS_OK != res)
1687         {
1688             OIC_LOG(ERROR, TAG, "add has failed");
1689             CARemoveBlockDataFromList(blockID);
1690             return res;
1691         }
1692
1693         if (!coap_add_data(*pdu, dataLength, (const unsigned char *) info->payload))
1694         {
1695             OIC_LOG(ERROR, TAG, "failed to add payload");
1696             return CA_STATUS_FAILED;
1697         }
1698
1699         // reset block-list after write block
1700         if (0 == block1->m)
1701         {
1702             // remove data from list
1703             CAResult_t res = CARemoveBlockDataFromList(blockID);
1704             if (CA_STATUS_OK != res)
1705             {
1706                 OIC_LOG(ERROR, TAG, "remove has failed");
1707                 return res;
1708             }
1709         }
1710     }
1711     else
1712     {
1713         CAGetMoreBitFromBlock(dataLength, block1);
1714
1715         CAResult_t res = CA_STATUS_OK;
1716         // if block number is 0, add size1 option
1717         if (0 == block1->num)
1718         {
1719             res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE1, dataLength, options);
1720             if (CA_STATUS_OK != res)
1721             {
1722                 OIC_LOG(ERROR, TAG, "add has failed");
1723                 CARemoveBlockDataFromList(blockID);
1724                 return res;
1725             }
1726         }
1727
1728         res = CAAddBlockOptionImpl(block1, COAP_OPTION_BLOCK1, options);
1729         if (CA_STATUS_OK != res)
1730         {
1731             OIC_LOG(ERROR, TAG, "add has failed");
1732             CARemoveBlockDataFromList(blockID);
1733             return res;
1734         }
1735
1736         res = CAAddOptionToPDU(*pdu, options);
1737         if (CA_STATUS_OK != res)
1738         {
1739             OIC_LOG(ERROR, TAG, "add has failed");
1740             CARemoveBlockDataFromList(blockID);
1741             return res;
1742         }
1743
1744         CALogBlockInfo(block1);
1745
1746         if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info->payload,
1747                             block1->num, block1->szx))
1748         {
1749             OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
1750             return CA_STATUS_FAILED;
1751         }
1752
1753         // check the message type and if message type is NON, next block message will be sent
1754         if (CA_MSG_NONCONFIRM == (*pdu)->hdr->coap_hdr_udp_t.type)
1755         {
1756             if (block1->m)
1757             {
1758                 OIC_LOG(DEBUG, TAG, "NON, send next block..");
1759                 // update block data
1760                 block1->num++;
1761                 CAResult_t res = CAProcessNextStep(*pdu, NULL,
1762                                                    CA_SENT_PREVIOUS_NON_MSG,
1763                                                    blockID);
1764                 if (CA_STATUS_OK != res)
1765                 {
1766                     OIC_LOG(ERROR, TAG, "failed to process next step");
1767                     CARemoveBlockDataFromList(blockID);
1768                     return res;
1769                 }
1770             }
1771             else
1772             {
1773                 CARemoveBlockDataFromList(blockID);
1774             }
1775         }
1776     }
1777
1778     OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption1");
1779
1780     return CA_STATUS_OK;
1781 }
1782
1783 CAResult_t CAAddBlockOptionImpl(coap_block_t *block, uint8_t blockType,
1784                                 coap_list_t **options)
1785 {
1786     OIC_LOG(DEBUG, TAG, "IN-AddBlockOptionImpl");
1787     VERIFY_NON_NULL(block, TAG, "block");
1788     VERIFY_NON_NULL(options, TAG, "options");
1789
1790     unsigned char buf[BLOCKWISE_OPTION_BUFFER] = { 0 };
1791     unsigned int optionLength = coap_encode_var_bytes(buf,
1792                                                       ((block->num << BLOCK_NUMBER_IDX)
1793                                                        | (block->m << BLOCK_M_BIT_IDX)
1794                                                        | block->szx));
1795
1796     int ret = coap_insert(options,
1797                           CACreateNewOptionNode(blockType, optionLength, (char *) buf),
1798                           CAOrderOpts);
1799     if (ret <= 0)
1800     {
1801         return CA_STATUS_INVALID_PARAM;
1802     }
1803
1804     OIC_LOG(DEBUG, TAG, "OUT-AddBlockOptionImpl");
1805     return CA_STATUS_OK;
1806 }
1807
1808 CAResult_t CAAddOptionToPDU(coap_pdu_t *pdu, coap_list_t **options)
1809 {
1810     // after adding the block option to option list, add option list to pdu.
1811     if (*options)
1812     {
1813         for (coap_list_t *opt = *options; opt; opt = opt->next)
1814         {
1815             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
1816                       COAP_OPTION_DATA(*(coap_option *) opt->data));
1817
1818             OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
1819             int ret = coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
1820                                       COAP_OPTION_LENGTH(*(coap_option *) opt->data),
1821                                       COAP_OPTION_DATA(*(coap_option *) opt->data), coap_udp);
1822             if (!ret)
1823             {
1824                 return CA_STATUS_FAILED;
1825             }
1826         }
1827     }
1828
1829     OIC_LOG_V(DEBUG, TAG, "[%d] pdu length after option", pdu->length);
1830
1831     return CA_STATUS_OK;
1832 }
1833
1834 CAResult_t CAAddBlockSizeOption(coap_pdu_t *pdu, uint16_t sizeType, size_t dataLength,
1835                                 coap_list_t **options)
1836 {
1837     OIC_LOG(DEBUG, TAG, "IN-CAAddBlockSizeOption");
1838     VERIFY_NON_NULL(pdu, TAG, "pdu");
1839     VERIFY_NON_NULL(options, TAG, "options");
1840
1841     if (sizeType != COAP_OPTION_SIZE1 && sizeType != COAP_OPTION_SIZE2)
1842     {
1843         OIC_LOG(ERROR, TAG, "unknown option type");
1844         return CA_STATUS_FAILED;
1845     }
1846
1847     unsigned char value[BLOCKWISE_OPTION_BUFFER] = { 0 };
1848     unsigned int optionLength = coap_encode_var_bytes(value, dataLength);
1849
1850     int ret = coap_insert(options,
1851                           CACreateNewOptionNode(sizeType, optionLength, (char *) value),
1852                           CAOrderOpts);
1853     if (ret <= 0)
1854     {
1855         return CA_STATUS_INVALID_PARAM;
1856     }
1857
1858     OIC_LOG(DEBUG, TAG, "OUT-CAAddBlockSizeOption");
1859
1860     return CA_STATUS_OK;
1861 }
1862
1863 // TODO make pdu const after libcoap is updated to support that.
1864 bool CAIsPayloadLengthInPduWithBlockSizeOption(coap_pdu_t *pdu,
1865                                                uint16_t sizeType,
1866                                                size_t *totalPayloadLen)
1867 {
1868     OIC_LOG(DEBUG, TAG, "IN-CAIsPayloadLengthInPduWithBlockSizeOption");
1869     VERIFY_NON_NULL(pdu, TAG, "pdu");
1870     VERIFY_NON_NULL(totalPayloadLen, TAG, "totalPayloadLen");
1871
1872     if (sizeType != COAP_OPTION_SIZE1 && sizeType != COAP_OPTION_SIZE2)
1873     {
1874         OIC_LOG(ERROR, TAG, "unknown option type");
1875         return CA_STATUS_FAILED;
1876     }
1877
1878     coap_opt_iterator_t opt_iter;
1879     coap_opt_t *option = coap_check_option(pdu, sizeType, &opt_iter);
1880     if (option)
1881     {
1882         OIC_LOG(DEBUG, TAG, "get size option from pdu");
1883         *totalPayloadLen = coap_decode_var_bytes(COAP_OPT_VALUE(option),
1884                                                  COAP_OPT_LENGTH(option));
1885
1886         OIC_LOG_V(DEBUG, TAG, "the total payload length to be received is [%zu]bytes",
1887                   *totalPayloadLen);
1888
1889         return true;
1890     }
1891
1892     OIC_LOG(DEBUG, TAG, "OUT-CAIsPayloadLengthInPduWithBlockSizeOption");
1893
1894     return false;
1895 }
1896
1897 uint8_t CACheckBlockErrorType(CABlockData_t *currData, coap_block_t *receivedBlock,
1898                               const CAData_t *receivedData, uint16_t blockType,
1899                               size_t dataLen)
1900 {
1901     OIC_LOG(DEBUG, TAG, "IN-CheckBlockError");
1902
1903     VERIFY_NON_NULL(currData, TAG, "currData is NULL");
1904     VERIFY_NON_NULL(receivedBlock, TAG, "receivedBlock is NULL");
1905     VERIFY_NON_NULL(receivedData, TAG, "receivedData is NULL");
1906
1907     // #1. check the received payload length
1908     size_t blockPayloadLen = 0;
1909     CAGetPayloadInfo(receivedData, &blockPayloadLen);
1910
1911     // #2. check if the block sequence is right
1912     if (COAP_OPTION_BLOCK1 == blockType)
1913     {
1914         size_t prePayloadLen = currData->receivedPayloadLen;
1915         if (prePayloadLen != (size_t)BLOCK_SIZE(receivedBlock->szx)
1916             * receivedBlock->num)
1917         {
1918             if (receivedBlock->num > currData->block1.num + 1)
1919             {
1920                 // 408 Error handling of block loss
1921                 OIC_LOG(ERROR, TAG, "option1: error 4.08");
1922                 OIC_LOG(ERROR, TAG, "it didn't order");
1923                 return CA_BLOCK_INCOMPLETE;
1924             }
1925             return CA_BLOCK_RECEIVED_ALREADY;
1926         }
1927     }
1928     else if (COAP_OPTION_BLOCK2 == blockType)
1929     {
1930         if (receivedBlock->num != currData->block2.num)
1931         {
1932             if (receivedBlock->num > currData->block2.num)
1933             {
1934                 // 408 Error handling of block loss
1935                 OIC_LOG(ERROR, TAG, "option2: error 4.08");
1936                 OIC_LOG(ERROR, TAG, "it didn't order");
1937                 return CA_BLOCK_INCOMPLETE;
1938             }
1939             return CA_BLOCK_RECEIVED_ALREADY;
1940         }
1941     }
1942
1943     // #3. check if error check logic is required
1944     size_t optionLen = dataLen - blockPayloadLen;
1945     if (receivedBlock->m && blockPayloadLen !=
1946         (size_t)BLOCK_SIZE(receivedBlock->szx))
1947     {
1948         // 413 Error handling of too large entity
1949         if (COAP_MAX_PDU_SIZE < BLOCK_SIZE(receivedBlock->szx) + optionLen)
1950         {
1951             // buffer size is smaller than received block size
1952             OIC_LOG(ERROR, TAG, "error type 4.13");
1953             OIC_LOG(ERROR, TAG, "too large size");
1954
1955             // set the block size to be smaller than COAP_MAX_PDU_SIZE
1956             for (int32_t size = CA_DEFAULT_BLOCK_SIZE; size >= 0; size--)
1957             {
1958                 if (COAP_MAX_PDU_SIZE >= BLOCK_SIZE(size) + optionLen)
1959                 {
1960                     OIC_LOG_V(ERROR, TAG, "replace sze with %d", size);
1961                     if (COAP_OPTION_BLOCK2 == blockType)
1962                     {
1963                         currData->block2.szx = size;
1964                     }
1965                     else
1966                     {
1967                         currData->block1.szx = size;
1968                     }
1969                     break;
1970                 }
1971             }
1972             return CA_BLOCK_TOO_LARGE;
1973         }
1974         else
1975         {
1976             // 408 Error handling of payload loss
1977             OIC_LOG(ERROR, TAG, "error type 4.08");
1978             OIC_LOG(ERROR, TAG, "payload len != block sze");
1979             return CA_BLOCK_INCOMPLETE;
1980         }
1981     }
1982     else if (0 == receivedBlock->m && 0 != currData->payloadLength)
1983     {
1984         // if the received block is last block, check the total payload length
1985         size_t receivedPayloadLen = currData->receivedPayloadLen;
1986         receivedPayloadLen += blockPayloadLen;
1987
1988         if (receivedPayloadLen != currData->payloadLength)
1989         {
1990             OIC_LOG(ERROR, TAG, "error type 4.08");
1991             OIC_LOG(ERROR, TAG, "total payload length is wrong");
1992             return CA_BLOCK_INCOMPLETE;
1993         }
1994     }
1995
1996     OIC_LOG(DEBUG, TAG, "received all data normally");
1997
1998     OIC_LOG(DEBUG, TAG, "OUT-CheckBlockError");
1999
2000     return CA_BLOCK_UNKNOWN;
2001 }
2002
2003 CAResult_t CAUpdatePayloadData(CABlockData_t *currData, const CAData_t *receivedData,
2004                                uint8_t status, bool isSizeOption, uint16_t blockType)
2005 {
2006     OIC_LOG(DEBUG, TAG, "IN-UpdatePayloadData");
2007
2008     VERIFY_NON_NULL(currData, TAG, "currData");
2009     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
2010
2011     // if error code is 4.08, do not update payload
2012     if (CA_BLOCK_INCOMPLETE == status)
2013     {
2014         OIC_LOG(ERROR, TAG, "no require to update");
2015         return CA_STATUS_OK;
2016     }
2017
2018     size_t blockPayloadLen = 0;
2019     CAPayload_t blockPayload = CAGetPayloadInfo(receivedData, &blockPayloadLen);
2020
2021     if (CA_BLOCK_TOO_LARGE == status)
2022     {
2023         blockPayloadLen = (COAP_OPTION_BLOCK2 == blockType) ?
2024                 BLOCK_SIZE(currData->block2.szx) : BLOCK_SIZE(currData->block1.szx);
2025     }
2026
2027     // memory allocation for the received block payload
2028     size_t prePayloadLen = currData->receivedPayloadLen;
2029     if (blockPayload)
2030     {
2031         if (currData->payloadLength)
2032         {
2033             // in case the block message has the size option
2034             // allocate the memory for the total payload
2035             if (isSizeOption)
2036             {
2037                 CAPayload_t prePayload = currData->payload;
2038
2039                 OIC_LOG(DEBUG, TAG, "allocate memory for the total payload");
2040                 currData->payload = (CAPayload_t) OICCalloc(1, currData->payloadLength);
2041                 if (NULL == currData->payload)
2042                 {
2043                     OIC_LOG(ERROR, TAG, "out of memory");
2044                     return CA_MEMORY_ALLOC_FAILED;
2045                 }
2046                 memcpy(currData->payload, prePayload, prePayloadLen);
2047                 OICFree(prePayload);
2048             }
2049
2050             // update the total payload
2051             memcpy(currData->payload + prePayloadLen, blockPayload, blockPayloadLen);
2052         }
2053         else
2054         {
2055             OIC_LOG(DEBUG, TAG, "allocate memory for the received block payload");
2056
2057             size_t totalPayloadLen = prePayloadLen + blockPayloadLen;
2058             CAPayload_t newPayload = OICRealloc(currData->payload, totalPayloadLen);
2059             if (NULL == newPayload)
2060             {
2061                 OIC_LOG(ERROR, TAG, "out of memory");
2062                 return CA_MEMORY_ALLOC_FAILED;
2063             }
2064
2065             // update the total payload
2066             memset(newPayload + prePayloadLen, 0, blockPayloadLen);
2067             currData->payload = newPayload;
2068             memcpy(currData->payload + prePayloadLen, blockPayload, blockPayloadLen);
2069         }
2070
2071         // update received payload length
2072         currData->receivedPayloadLen += blockPayloadLen;
2073
2074         OIC_LOG_V(DEBUG, TAG, "updated payload: %s, len: %zu", currData->payload,
2075                   currData->receivedPayloadLen);
2076     }
2077
2078     OIC_LOG(DEBUG, TAG, "OUT-UpdatePayloadData");
2079     return CA_STATUS_OK;
2080 }
2081
2082 CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint)
2083 {
2084     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", NULL);
2085     VERIFY_NON_NULL_RET(pdu->hdr, TAG, "pdu->hdr", NULL);
2086     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
2087
2088     CAInfo_t responseData = { .tokenLength = pdu->hdr->coap_hdr_udp_t.token_length };
2089     responseData.token = (CAToken_t) OICMalloc(responseData.tokenLength);
2090     if (!responseData.token)
2091     {
2092         OIC_LOG(ERROR, TAG, "out of memory");
2093         return NULL;
2094     }
2095     memcpy(responseData.token, pdu->hdr->coap_hdr_udp_t.token, responseData.tokenLength);
2096
2097     CAResponseInfo_t* responseInfo = (CAResponseInfo_t*) OICCalloc(1, sizeof(CAResponseInfo_t));
2098     if (!responseInfo)
2099     {
2100         OIC_LOG(ERROR, TAG, "out of memory");
2101         OICFree(responseData.token);
2102         return NULL;
2103     }
2104     responseInfo->info = responseData;
2105
2106     CAData_t *data = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
2107     if (!data)
2108     {
2109         OIC_LOG(ERROR, TAG, "out of memory");
2110         OICFree(responseInfo);
2111         return NULL;
2112     }
2113
2114     data->requestInfo = NULL;
2115     data->responseInfo = responseInfo;
2116     data->remoteEndpoint = CACloneEndpoint(endpoint);
2117     data->type = SEND_TYPE_UNICAST;
2118
2119     return data;
2120 }
2121
2122 CAData_t *CACloneCAData(const CAData_t *data)
2123 {
2124     VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
2125
2126     CAData_t *clone = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
2127     if (!clone)
2128     {
2129         OIC_LOG(ERROR, TAG, "out of memory");
2130         return NULL;
2131     }
2132     *clone = *data;
2133
2134     if (data->requestInfo)
2135     {
2136         clone->requestInfo = CACloneRequestInfo(data->requestInfo);
2137     }
2138     else if (data->responseInfo)
2139     {
2140         clone->responseInfo = CACloneResponseInfo(data->responseInfo);
2141     }
2142
2143     if (data->remoteEndpoint)
2144     {
2145         clone->remoteEndpoint = CACloneEndpoint(data->remoteEndpoint);
2146     }
2147
2148     return clone;
2149 }
2150
2151 CAResult_t CAUpdatePayloadToCAData(CAData_t *data, const CAPayload_t payload,
2152                                    size_t payloadLen)
2153 {
2154     OIC_LOG(DEBUG, TAG, "IN-UpdatePayload");
2155
2156     VERIFY_NON_NULL(data, TAG, "data is NULL");
2157     VERIFY_NON_NULL(payload, TAG, "payload is NULL");
2158
2159     CAPayload_t newPayload = NULL;
2160     switch (data->dataType)
2161     {
2162         case CA_REQUEST_DATA:
2163             if (!data->requestInfo)
2164             {
2165                 OIC_LOG(ERROR, TAG, "request info is null");
2166                 return CA_STATUS_FAILED;
2167             }
2168             // allocate payload field
2169             newPayload = OICRealloc(data->requestInfo->info.payload, payloadLen);
2170             if (!newPayload)
2171             {
2172                 OIC_LOG(ERROR, TAG, "out of memory");
2173                 return CA_STATUS_FAILED;
2174             }
2175             data->requestInfo->info.payload = newPayload;
2176             memcpy(data->requestInfo->info.payload, payload, payloadLen);
2177             data->requestInfo->info.payloadSize = payloadLen;
2178             break;
2179
2180         case CA_RESPONSE_DATA:
2181             if (!data->responseInfo)
2182             {
2183                 OIC_LOG(ERROR, TAG, "response info is null");
2184                 return CA_STATUS_FAILED;
2185             }
2186             // allocate payload field
2187             newPayload = OICRealloc(data->responseInfo->info.payload, payloadLen);
2188             if (!newPayload)
2189             {
2190                 OIC_LOG(ERROR, TAG, "out of memory");
2191                 return CA_STATUS_FAILED;
2192             }
2193             data->responseInfo->info.payload = newPayload;
2194             memcpy(data->responseInfo->info.payload, payload, payloadLen);
2195             data->responseInfo->info.payloadSize = payloadLen;
2196             break;
2197
2198         default:
2199             // does not occur case
2200             OIC_LOG(ERROR, TAG, "not supported data type");
2201             return CA_NOT_SUPPORTED;
2202     }
2203
2204     OIC_LOG(DEBUG, TAG, "OUT-UpdatePayload");
2205
2206     return CA_STATUS_OK;
2207 }
2208
2209 CAPayload_t CAGetPayloadInfo(const CAData_t *data, size_t *payloadLen)
2210 {
2211     VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
2212     VERIFY_NON_NULL_RET(payloadLen, TAG, "payloadLen", NULL);
2213
2214     if (data->requestInfo)
2215     {
2216         if (data->requestInfo->info.payload)
2217         {
2218             *payloadLen = data->requestInfo->info.payloadSize;
2219             return data->requestInfo->info.payload;
2220         }
2221     }
2222     else
2223     {
2224         if (data->responseInfo->info.payload)
2225         {
2226             *payloadLen = data->responseInfo->info.payloadSize;
2227             return data->responseInfo->info.payload;
2228         }
2229     }
2230
2231     return NULL;
2232 }
2233
2234 CAResult_t CAHandleBlockErrorResponse(coap_block_t *block, uint16_t blockType,
2235                                       uint32_t responseResult)
2236 {
2237     OIC_LOG(DEBUG, TAG, "IN-HandleBlockErrorRes");
2238     VERIFY_NON_NULL(block, TAG, "block is NULL");
2239
2240     // update block data
2241     switch (responseResult)
2242     {
2243         case CA_REQUEST_ENTITY_INCOMPLETE:
2244             block->num = 0;
2245             break;
2246         case CA_REQUEST_ENTITY_TOO_LARGE:
2247             if (COAP_OPTION_BLOCK1 == blockType)
2248             {
2249                 block->num++;
2250             }
2251             block->m = 0;
2252             break;
2253         default:
2254             OIC_LOG_V(ERROR, TAG, "there is no Error Code of BWT[%d]", responseResult);
2255     }
2256
2257     OIC_LOG(DEBUG, TAG, "OUT-HandleBlockErrorRes");
2258     return CA_STATUS_OK;
2259 }
2260
2261 CAResult_t CAUpdateBlockOptionType(const CABlockDataID_t *blockID,
2262                                    uint8_t blockType)
2263 {
2264     OIC_LOG(DEBUG, TAG, "IN-UpdateBlockOptionType");
2265     VERIFY_NON_NULL(blockID, TAG, "blockID");
2266
2267     ca_mutex_lock(g_context.blockDataListMutex);
2268
2269     size_t len = u_arraylist_length(g_context.dataList);
2270     for (size_t i = 0; i < len; i++)
2271     {
2272         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2273         if (CABlockidMatches(currData, blockID))
2274         {
2275             currData->type = blockType;
2276             ca_mutex_unlock(g_context.blockDataListMutex);
2277             OIC_LOG(DEBUG, TAG, "OUT-UpdateBlockOptionType");
2278             return CA_STATUS_OK;
2279         }
2280     }
2281     ca_mutex_unlock(g_context.blockDataListMutex);
2282
2283     OIC_LOG(DEBUG, TAG, "OUT-UpdateBlockOptionType");
2284     return CA_STATUS_FAILED;
2285 }
2286
2287 uint8_t CAGetBlockOptionType(const CABlockDataID_t *blockID)
2288 {
2289     OIC_LOG(DEBUG, TAG, "IN-GetBlockOptionType");
2290     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", 0);
2291
2292     ca_mutex_lock(g_context.blockDataListMutex);
2293
2294     size_t len = u_arraylist_length(g_context.dataList);
2295     for (size_t i = 0; i < len; i++)
2296     {
2297         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2298         if (CABlockidMatches(currData, blockID))
2299         {
2300             ca_mutex_unlock(g_context.blockDataListMutex);
2301             OIC_LOG(DEBUG, TAG, "OUT-GetBlockOptionType");
2302             return currData->type;
2303         }
2304     }
2305     ca_mutex_unlock(g_context.blockDataListMutex);
2306
2307     OIC_LOG(DEBUG, TAG, "OUT-GetBlockOptionType");
2308     return 0;
2309 }
2310
2311 CAData_t *CAGetDataSetFromBlockDataList(const CABlockDataID_t *blockID)
2312 {
2313     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
2314
2315     ca_mutex_lock(g_context.blockDataListMutex);
2316
2317     size_t len = u_arraylist_length(g_context.dataList);
2318     for (size_t i = 0; i < len; i++)
2319     {
2320         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2321         if (CABlockidMatches(currData, blockID))
2322         {
2323             ca_mutex_unlock(g_context.blockDataListMutex);
2324             return currData->sentData;
2325         }
2326     }
2327     ca_mutex_unlock(g_context.blockDataListMutex);
2328
2329     return NULL;
2330 }
2331
2332 CAResult_t CAGetTokenFromBlockDataList(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
2333                                        CAResponseInfo_t *responseInfo)
2334 {
2335     OIC_LOG(DEBUG, TAG, "IN-CAGetTokenFromBlockDataList");
2336     VERIFY_NON_NULL(pdu, TAG, "pdu");
2337     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
2338     VERIFY_NON_NULL(responseInfo, TAG, "responseInfo");
2339
2340     ca_mutex_lock(g_context.blockDataListMutex);
2341
2342     size_t len = u_arraylist_length(g_context.dataList);
2343     for (size_t i = 0; i < len; i++)
2344     {
2345         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2346         if (NULL == currData)
2347         {
2348             continue;
2349         }
2350
2351         if (NULL != currData->sentData && NULL != currData->sentData->requestInfo)
2352         {
2353             if (pdu->hdr->coap_hdr_udp_t.id == currData->sentData->requestInfo->info.messageId &&
2354                     endpoint->adapter == currData->sentData->remoteEndpoint->adapter)
2355             {
2356                 if (NULL != currData->sentData->requestInfo->info.token)
2357                 {
2358                     uint8_t length = currData->sentData->requestInfo->info.tokenLength;
2359                     responseInfo->info.tokenLength = length;
2360                     responseInfo->info.token = (char *) OICMalloc(length);
2361                     if (NULL == responseInfo->info.token)
2362                     {
2363                         OIC_LOG(ERROR, TAG, "out of memory");
2364                         ca_mutex_unlock(g_context.blockDataListMutex);
2365                         return CA_MEMORY_ALLOC_FAILED;
2366                     }
2367                     memcpy(responseInfo->info.token, currData->sentData->requestInfo->info.token,
2368                            responseInfo->info.tokenLength);
2369
2370                     ca_mutex_unlock(g_context.blockDataListMutex);
2371                     OIC_LOG(DEBUG, TAG, "OUT-CAGetTokenFromBlockDataList");
2372                     return CA_STATUS_OK;
2373                 }
2374             }
2375         }
2376     }
2377
2378     ca_mutex_unlock(g_context.blockDataListMutex);
2379
2380     OIC_LOG(DEBUG, TAG, "OUT-CAGetTokenFromBlockDataList");
2381     return CA_STATUS_OK;
2382 }
2383
2384 CAResult_t CACheckBlockDataValidation(const CAData_t *sendData, CABlockData_t **blockData)
2385 {
2386     VERIFY_NON_NULL(sendData, TAG, "sendData");
2387     VERIFY_NON_NULL(blockData, TAG, "blockData");
2388
2389     ca_mutex_lock(g_context.blockDataListMutex);
2390
2391     size_t len = u_arraylist_length(g_context.dataList);
2392     for (size_t i = 0; i < len; i++)
2393     {
2394         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2395
2396         if (!currData)
2397         {
2398             continue;
2399         }
2400
2401         if (sendData->requestInfo) // sendData is requestMessage
2402         {
2403             OIC_LOG(DEBUG, TAG, "Send request");
2404             if (NULL != currData->blockDataId
2405                     && NULL != currData->blockDataId->id
2406                     && currData->blockDataId->idLength > 0
2407                     && NULL != sendData->requestInfo->info.token)
2408             {
2409                 CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
2410                         (CAToken_t)sendData->requestInfo->info.token,
2411                         sendData->requestInfo->info.tokenLength,
2412                         sendData->remoteEndpoint->port);
2413
2414                 if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
2415                 {
2416                     OIC_LOG(ERROR, TAG, "blockId is null");
2417                     CADestroyBlockID(blockDataID);
2418                     return CA_STATUS_FAILED;
2419                 }
2420
2421                 if (CABlockidMatches(currData, blockDataID))
2422                 {
2423                     OIC_LOG(ERROR, TAG, "already sent");
2424                     CADestroyBlockID(blockDataID);
2425                     continue;
2426                 }
2427                 CADestroyBlockID(blockDataID);
2428             }
2429         }
2430         else if (sendData->responseInfo) // sendData is responseMessage
2431         {
2432             OIC_LOG(DEBUG, TAG, "Send response");
2433             if (NULL != currData->blockDataId
2434                     && NULL != currData->blockDataId->id
2435                     && currData->blockDataId->idLength > 0
2436                     && NULL != sendData->responseInfo->info.token)
2437             {
2438                 CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
2439                         (CAToken_t)sendData->responseInfo->info.token,
2440                         sendData->responseInfo->info.tokenLength,
2441                         sendData->remoteEndpoint->port);
2442
2443                 if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
2444                 {
2445                     OIC_LOG(ERROR, TAG, "blockId is null");
2446                     CADestroyBlockID(blockDataID);
2447                     return CA_STATUS_FAILED;
2448                 }
2449
2450                 if (CABlockidMatches(currData, blockDataID))
2451                 {
2452                     // set sendData
2453                     if (NULL != currData->sentData)
2454                     {
2455                         OIC_LOG(DEBUG, TAG, "init block number");
2456                         CADestroyDataSet(currData->sentData);
2457                     }
2458                     currData->sentData = CACloneCAData(sendData);
2459                     *blockData = currData;
2460                     CADestroyBlockID(blockDataID);
2461                     ca_mutex_unlock(g_context.blockDataListMutex);
2462                     return CA_STATUS_OK;
2463                 }
2464                 CADestroyBlockID(blockDataID);
2465             }
2466         }
2467         else
2468         {
2469             OIC_LOG(ERROR, TAG, "no CAInfo data");
2470             continue;
2471         }
2472     }
2473     ca_mutex_unlock(g_context.blockDataListMutex);
2474
2475     return CA_STATUS_FAILED;
2476 }
2477
2478 CABlockData_t *CAGetBlockDataFromBlockDataList(const CABlockDataID_t *blockID)
2479 {
2480     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
2481
2482     ca_mutex_lock(g_context.blockDataListMutex);
2483
2484     size_t len = u_arraylist_length(g_context.dataList);
2485     for (size_t i = 0; i < len; i++)
2486     {
2487         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2488         if (CABlockidMatches(currData, blockID))
2489         {
2490             ca_mutex_unlock(g_context.blockDataListMutex);
2491             return currData;
2492         }
2493     }
2494     ca_mutex_unlock(g_context.blockDataListMutex);
2495
2496     return NULL;
2497 }
2498
2499 coap_block_t *CAGetBlockOption(const CABlockDataID_t *blockID,
2500                                uint16_t blockType)
2501 {
2502     OIC_LOG(DEBUG, TAG, "IN-GetBlockOption");
2503     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
2504
2505     ca_mutex_lock(g_context.blockDataListMutex);
2506
2507     size_t len = u_arraylist_length(g_context.dataList);
2508     for (size_t i = 0; i < len; i++)
2509     {
2510         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2511         if (CABlockidMatches(currData, blockID))
2512         {
2513             ca_mutex_unlock(g_context.blockDataListMutex);
2514             OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
2515             if (COAP_OPTION_BLOCK2 == blockType)
2516             {
2517                 return &currData->block2;
2518             }
2519             else
2520             {
2521                 return &currData->block1;
2522             }
2523         }
2524     }
2525     ca_mutex_unlock(g_context.blockDataListMutex);
2526
2527     OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
2528     return NULL;
2529 }
2530
2531 CAPayload_t CAGetPayloadFromBlockDataList(const CABlockDataID_t *blockID,
2532                                           size_t *fullPayloadLen)
2533 {
2534     OIC_LOG(DEBUG, TAG, "IN-GetFullPayload");
2535     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
2536     VERIFY_NON_NULL_RET(fullPayloadLen, TAG, "fullPayloadLen", NULL);
2537
2538     ca_mutex_lock(g_context.blockDataListMutex);
2539
2540     size_t len = u_arraylist_length(g_context.dataList);
2541     for (size_t i = 0; i < len; i++)
2542     {
2543         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2544         if (CABlockidMatches(currData, blockID))
2545         {
2546             ca_mutex_unlock(g_context.blockDataListMutex);
2547             *fullPayloadLen = currData->receivedPayloadLen;
2548             OIC_LOG(DEBUG, TAG, "OUT-GetFullPayload");
2549             return currData->payload;
2550         }
2551     }
2552     ca_mutex_unlock(g_context.blockDataListMutex);
2553
2554     OIC_LOG(DEBUG, TAG, "OUT-GetFullPayload");
2555     return NULL;
2556 }
2557
2558 CABlockData_t *CACreateNewBlockData(const CAData_t *sendData)
2559 {
2560     OIC_LOG(DEBUG, TAG, "IN-CACreateNewBlockData");
2561     VERIFY_NON_NULL_RET(sendData, TAG, "sendData", NULL);
2562
2563     // create block data
2564     CABlockData_t *data = (CABlockData_t *) OICCalloc(1, sizeof(CABlockData_t));
2565     if (!data)
2566     {
2567         OIC_LOG(ERROR, TAG, "memory alloc has failed");
2568         return NULL;
2569     }
2570
2571     data->block1.szx = CA_DEFAULT_BLOCK_SIZE;
2572     data->block2.szx = CA_DEFAULT_BLOCK_SIZE;
2573     data->sentData = CACloneCAData(sendData);
2574     if(!data->sentData)
2575     {
2576         OIC_LOG(ERROR, TAG, PCF("memory alloc has failed"));
2577         OICFree(data);
2578         return NULL;
2579     }
2580
2581     CAToken_t token = NULL;
2582     uint8_t tokenLength = 0;
2583     if (data->sentData->requestInfo)
2584     {
2585         // update token info
2586         tokenLength = data->sentData->requestInfo->info.tokenLength;
2587         token = data->sentData->requestInfo->info.token;
2588     }
2589     else if(data->sentData->responseInfo)
2590     {
2591         tokenLength = data->sentData->responseInfo->info.tokenLength;
2592         token = data->sentData->responseInfo->info.token;
2593     }
2594
2595     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
2596             token, tokenLength,
2597             data->sentData->remoteEndpoint->port);
2598     if (NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
2599     {
2600         OIC_LOG(ERROR, TAG, "blockId is null");
2601         CADestroyBlockID(blockDataID);
2602         CADestroyDataSet(data->sentData);
2603         OICFree(data);
2604         return NULL;
2605     }
2606     data->blockDataId = blockDataID;
2607
2608     ca_mutex_lock(g_context.blockDataListMutex);
2609
2610     bool res = u_arraylist_add(g_context.dataList, (void *) data);
2611     if (!res)
2612     {
2613         OIC_LOG(ERROR, TAG, "add has failed");
2614         CADestroyBlockID(data->blockDataId);
2615         CADestroyDataSet(data->sentData);
2616         OICFree(data);
2617         ca_mutex_unlock(g_context.blockDataListMutex);
2618         return NULL;
2619     }
2620     ca_mutex_unlock(g_context.blockDataListMutex);
2621
2622     OIC_LOG(DEBUG, TAG, "OUT-CreateBlockData");
2623     return data;
2624 }
2625
2626 CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID)
2627 {
2628     OIC_LOG(DEBUG, TAG, "CARemoveBlockData");
2629     VERIFY_NON_NULL(blockID, TAG, "blockID");
2630
2631     ca_mutex_lock(g_context.blockDataListMutex);
2632
2633     size_t len = u_arraylist_length(g_context.dataList);
2634     for (size_t i = 0; i < len; i++)
2635     {
2636         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2637         if (CABlockidMatches(currData, blockID))
2638         {
2639             CABlockData_t *removedData = u_arraylist_remove(g_context.dataList, i);
2640             if (!removedData)
2641             {
2642                 OIC_LOG(ERROR, TAG, "data is NULL");
2643                 ca_mutex_unlock(g_context.blockDataListMutex);
2644                 return CA_STATUS_FAILED;
2645             }
2646
2647             // destroy memory
2648             if (currData->sentData)
2649             {
2650                 CADestroyDataSet(currData->sentData);
2651             }
2652             CADestroyBlockID(currData->blockDataId);
2653             OICFree(currData->payload);
2654             OICFree(currData);
2655             ca_mutex_unlock(g_context.blockDataListMutex);
2656             return CA_STATUS_OK;
2657         }
2658     }
2659     ca_mutex_unlock(g_context.blockDataListMutex);
2660
2661     return CA_STATUS_OK;
2662 }
2663
2664 bool CAIsBlockDataInList(const CABlockDataID_t *blockID)
2665 {
2666     OIC_LOG(DEBUG, TAG, "IN-IsBlockDataInList");
2667     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", false);
2668
2669     ca_mutex_lock(g_context.blockDataListMutex);
2670
2671     size_t len = u_arraylist_length(g_context.dataList);
2672     for (size_t i = 0; i < len; i++)
2673     {
2674         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
2675         if (CABlockidMatches(currData, blockID))
2676         {
2677             OIC_LOG(DEBUG, TAG, "found block data");
2678             ca_mutex_unlock(g_context.blockDataListMutex);
2679             return true;
2680         }
2681     }
2682     ca_mutex_unlock(g_context.blockDataListMutex);
2683
2684     OIC_LOG(DEBUG, TAG, "OUT-IsBlockDataInList");
2685     return false;
2686 }
2687
2688 void CADestroyDataSet(CAData_t* data)
2689 {
2690     VERIFY_NON_NULL_VOID(data, TAG, "data");
2691
2692     CAFreeEndpoint(data->remoteEndpoint);
2693     CADestroyRequestInfoInternal(data->requestInfo);
2694     CADestroyResponseInfoInternal(data->responseInfo);
2695     OICFree(data);
2696 }
2697
2698 CABlockDataID_t* CACreateBlockDatablockId(const CAToken_t token, uint8_t tokenLength,
2699                                           uint16_t portNumber)
2700 {
2701     char port[PORT_LENGTH] = {0,};
2702     port[0] = (char)((portNumber>>8) & 0xFF);
2703     port[1] = (char)(portNumber & 0xFF);
2704
2705     CABlockDataID_t* blockDataID = (CABlockDataID_t *) OICMalloc(sizeof(CABlockDataID_t));
2706     if (!blockDataID)
2707     {
2708         OIC_LOG(ERROR, TAG, "memory alloc has failed");
2709         return NULL;
2710     }
2711     blockDataID->idLength = tokenLength + sizeof(port);
2712     blockDataID->id = (uint8_t *) OICMalloc(blockDataID->idLength);
2713     if (!blockDataID->id)
2714     {
2715         OIC_LOG(ERROR, TAG, "memory alloc has failed");
2716         OICFree(blockDataID);
2717         return NULL;
2718     }
2719
2720     if (token)
2721     {
2722         memcpy(blockDataID->id, token, tokenLength);
2723     }
2724
2725     memcpy(blockDataID->id + tokenLength, port, sizeof(port));
2726
2727     OIC_LOG(DEBUG, TAG, "BlockID is ");
2728     OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)blockDataID->id, blockDataID->idLength);
2729
2730     return blockDataID;
2731 }
2732
2733 void CADestroyBlockID(CABlockDataID_t *blockID)
2734 {
2735     VERIFY_NON_NULL_VOID(blockID, TAG, "blockID");
2736     OICFree(blockID->id);
2737     OICFree(blockID);
2738     blockID = NULL;
2739 }
2740
2741 bool CABlockidMatches(const CABlockData_t *currData, const CABlockDataID_t *blockID)
2742 {
2743     VERIFY_NON_NULL_RET(currData, TAG, "currData", false);
2744     VERIFY_NON_NULL_RET(blockID, TAG, "blockID", false);
2745     VERIFY_NON_NULL_RET(blockID->id, TAG, "blockID->id", false);
2746
2747     if ((currData->blockDataId)
2748         && (currData->blockDataId->id)
2749         && (currData->blockDataId->idLength == blockID->idLength)
2750         && !memcmp(currData->blockDataId->id, blockID->id, currData->blockDataId->idLength))
2751     {
2752         return true;
2753     }
2754     return false;
2755 }
2756
2757 void CALogBlockInfo(coap_block_t *block)
2758 {
2759     VERIFY_NON_NULL_VOID(block, TAG, "block");
2760
2761     OIC_LOG(DEBUG, TAG, "block option info");
2762
2763     OIC_LOG_V(DEBUG, TAG, "block option-num : %d", block->num);
2764
2765     OIC_LOG_V(DEBUG, TAG, "block option-m   : %d", block->m);
2766
2767     OIC_LOG_V(DEBUG, TAG, "block option-szx : %d", block->szx);
2768 }