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