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