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