Merge branch '1.1-rel'
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / cablockwisetransfer.c
index aced0f6..a78aa06 100644 (file)
@@ -40,6 +40,7 @@
 #include "caremotehandler.h"
 #include "cablockwisetransfer.h"
 #include "oic_malloc.h"
+#include "oic_string.h"
 #include "camutex.h"
 #include "logger.h"
 
@@ -77,7 +78,7 @@ static bool CACheckPayloadLength(const CAData_t *sendData)
 CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc sendThreadFunc,
                                          CAReceiveThreadFunc receivedThreadFunc)
 {
-    OIC_LOG(DEBUG, TAG, "initialize");
+    OIC_LOG(DEBUG, TAG, "CAInitializeBlockWiseTransfer");
 
     // set block-wise transfer context
     if (!g_context.sendThreadFunc)
@@ -108,10 +109,11 @@ CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc sendThreadFunc,
 
 CAResult_t CATerminateBlockWiseTransfer()
 {
-    OIC_LOG(DEBUG, TAG, "terminate");
+    OIC_LOG(DEBUG, TAG, "CATerminateBlockWiseTransfer");
 
     if (g_context.dataList)
     {
+        CARemoveAllBlockDataFromList();
         u_arraylist_free(&g_context.dataList);
     }
 
@@ -173,6 +175,16 @@ CAResult_t CASendBlockWiseData(const CAData_t *sendData)
             OIC_LOG(DEBUG, TAG, "reset message can't be sent to the block");
             return CA_NOT_SUPPORTED;
         }
+
+        /*
+         * Other uses of the Block options in conjunction with multicast
+         * messages are for further study.
+         */
+        if (sendData->requestInfo->isMulticast)
+        {
+            OIC_LOG(DEBUG, TAG, "multicast message can't be sent to the block");
+            return CA_NOT_SUPPORTED;
+        }
     }
     else if (sendData->responseInfo)
     {
@@ -181,6 +193,11 @@ CAResult_t CASendBlockWiseData(const CAData_t *sendData)
             OIC_LOG(DEBUG, TAG, "reset message can't be sent to the block");
             return CA_NOT_SUPPORTED;
         }
+        if (sendData->responseInfo->isMulticast)
+        {
+            OIC_LOG(DEBUG, TAG, "multicast message can't be sent to the block");
+            return CA_NOT_SUPPORTED;
+        }
     }
 
     // #1. check if it is already included in block data list
@@ -299,12 +316,16 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     {
         OIC_LOG(DEBUG, TAG, "code is CA_EMPTY..");
 
-        // get token from block-wise transfer list when CA_EMPTY(RST/ACK) is received
-        CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint, receivedData->responseInfo);
-        if (CA_STATUS_OK != res)
+        if (!receivedData->responseInfo->info.token)
         {
-            OIC_LOG(ERROR, TAG, "fail to get token");
-            return res;
+            // get token from block-wise transfer list when CA_EMPTY(RST/ACK) is received
+            CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint,
+                                                         receivedData->responseInfo);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "fail to get token");
+                return res;
+            }
         }
 
         CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
@@ -319,12 +340,10 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                 OIC_LOG(INFO, TAG, "retransmission was stopped");
                 return CA_REQUEST_TIMEOUT;
             }
-            else
-            {
-                OIC_LOG(ERROR, TAG, "blockId is null");
-                CADestroyBlockID(blockDataID);
-                return CA_STATUS_FAILED;
-            }
+
+            OIC_LOG(ERROR, TAG, "blockId is null");
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
         }
 
         CARemoveBlockDataFromList(blockDataID);
@@ -359,43 +378,43 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
         }
     }
 
-    // check if there is error code
+    // if there is no block option in pdu, check if there is error code.
     if (!isBlock1 && !isBlock2)
     {
+        CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+                (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
+                pdu->hdr->coap_hdr_udp_t.token_length,
+                endpoint->port);
+        if (NULL == blockDataID || blockDataID->idLength < 1)
+        {
+            OIC_LOG(ERROR, TAG, "blockId is null");
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
+        }
+
         uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
         if (CA_REQUEST_ENTITY_INCOMPLETE == code)
         {
-            CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-                    (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
-                    pdu->hdr->coap_hdr_udp_t.token_length,
-                    endpoint->port);
-            if (NULL == blockDataID || blockDataID->idLength < 1)
+            CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+            if (!data)
             {
-                OIC_LOG(ERROR, TAG, "blockId is null");
+                OIC_LOG(ERROR, TAG, "getting has failed");
                 CADestroyBlockID(blockDataID);
                 return CA_STATUS_FAILED;
             }
 
-            CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
-            if (!data)
+            coap_block_t *block = CAGetBlockOption(blockDataID, data->type);
+            if (!block)
             {
-                OIC_LOG(ERROR, TAG, "getting has failed");
+                OIC_LOG(ERROR, TAG, "block is null");
                 CADestroyBlockID(blockDataID);
                 return CA_STATUS_FAILED;
             }
 
+            CAResult_t res = CA_STATUS_OK;
             if (COAP_OPTION_BLOCK2 == data->type)
             {
-                coap_block_t *block2 = CAGetBlockOption(blockDataID, COAP_OPTION_BLOCK2);
-                if (!block2)
-                {
-                    OIC_LOG(ERROR, TAG, "block is null");
-                    CADestroyBlockID(blockDataID);
-                    return CA_STATUS_FAILED;
-                }
-
-                CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, *block2,
-                                                       dataLen);
+                res = CASetNextBlockOption2(pdu, endpoint, receivedData, *block, dataLen);
                 if (CA_STATUS_OK != res)
                 {
                     OIC_LOG(ERROR, TAG, "setting has failed");
@@ -405,16 +424,7 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
             }
             else if (COAP_OPTION_BLOCK1 == data->type)
             {
-                coap_block_t *block1 = CAGetBlockOption(blockDataID, COAP_OPTION_BLOCK1);
-                if (!block1)
-                {
-                    OIC_LOG(ERROR, TAG, "block is null");
-                    CADestroyBlockID(blockDataID);
-                    return CA_STATUS_FAILED;
-                }
-
-                CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, *block1,
-                                                       dataLen);
+                res = CASetNextBlockOption1(pdu, endpoint, receivedData, *block, dataLen);
                 if (CA_STATUS_OK != res)
                 {
                     OIC_LOG(ERROR, TAG, "setting has failed");
@@ -422,12 +432,7 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                     return res;
                 }
             }
-            else
-            {
-                OIC_LOG(ERROR, TAG, "Invalid Block Option");
-                CADestroyBlockID(blockDataID);
-                return CA_STATUS_FAILED;
-            }
+            CADestroyBlockID(blockDataID);
         }
         else
         {
@@ -438,24 +443,12 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
             // and sent data remain in block data list, remove block data
             if (receivedData->responseInfo)
             {
-                CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-                        (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
-                        pdu->hdr->coap_hdr_udp_t.token_length,
-                        endpoint->port);
-                if (NULL == blockDataID || blockDataID->idLength < 1)
-                {
-                    OIC_LOG(ERROR, TAG, "blockId is null");
-                    CADestroyBlockID(blockDataID);
-                    return CA_STATUS_FAILED;
-                }
-
                 CARemoveBlockDataFromList(blockDataID);
-                CADestroyBlockID(blockDataID);
             }
+            CADestroyBlockID(blockDataID);
             return CA_NOT_SUPPORTED;
         }
     }
-
     return CA_STATUS_OK;
 }
 
@@ -891,14 +884,15 @@ CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
         // check the blcok-wise transfer status for next step
         if (CA_BLOCK_UNKNOWN == blockWiseStatus || CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
         {
-            if (0 == block.m) // Last block is received
+            OIC_LOG_V(DEBUG, TAG, "M bit is %d", block.m);
+
+            if (0 == block.m)
             {
-                OIC_LOG(DEBUG, TAG, "M bit is 0");
+                // Last block is received
                 blockWiseStatus = CA_OPTION1_REQUEST_LAST_BLOCK;
             }
             else
             {
-                OIC_LOG(DEBUG, TAG, "M bit is 1");
                 blockWiseStatus = CA_OPTION1_REQUEST_BLOCK;
             }
         }
@@ -1239,7 +1233,7 @@ CAResult_t CASetMoreBitFromBlock(size_t payloadLen, coap_block_t *block)
 }
 
 CAResult_t CANegotiateBlockSize(CABlockData_t *currData, coap_block_t *block,
-                                coap_pdu_t *pdu, uint16_t blockType)
+                                const coap_pdu_t *pdu, uint16_t blockType)
 {
     OIC_LOG(DEBUG, TAG, "IN-NegotiateBlockSize");
 
@@ -1395,27 +1389,12 @@ CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t *info,
         goto exit;
     }
 
-    uint32_t code = (*pdu)->hdr->coap_hdr_udp_t.code;
-    if (CA_GET == code || CA_POST == code || CA_PUT == code || CA_DELETE == code)
-    {
-        // if received message type is RESET from remote device,
-        // we have to use the updated message id of request message to find token.
-        res = CAUpdateMessageId(*pdu, blockDataID);
-        if (CA_STATUS_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "fail to update message id");
-            goto exit;
-        }
-    }
-    else
+    uint32_t repCode = CA_RESPONSE_CODE((*pdu)->hdr->coap_hdr_udp_t.code);
+    if (CA_REQUEST_ENTITY_INCOMPLETE == repCode)
     {
-        uint32_t repCode = CA_RESPONSE_CODE((*pdu)->hdr->coap_hdr_udp_t.code);
-        if (CA_REQUEST_ENTITY_INCOMPLETE == repCode)
-        {
-            OIC_LOG(INFO, TAG, "don't use option");
-            res = CA_STATUS_OK;
-            goto exit;
-        }
+        OIC_LOG(INFO, TAG, "don't use option");
+        res = CA_STATUS_OK;
+        goto exit;
     }
 
     uint8_t blockType = CAGetBlockOptionType(blockDataID);
@@ -1462,19 +1441,33 @@ CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t *info,
         if (!coap_add_data(*pdu, dataLength, (const unsigned char *) info->payload))
         {
             OIC_LOG(INFO, TAG, "it have to use block");
+            res = CA_STATUS_FAILED;
+            goto exit;
         }
         else
         {
             OIC_LOG(INFO, TAG, "not Blockwise Transfer");
-            goto exit;
         }
     }
 
-exit:
-    if (CA_ADAPTER_IP == endpoint->adapter && 0 == endpoint->port)
+    uint32_t code = (*pdu)->hdr->coap_hdr_udp_t.code;
+    if (CA_GET == code || CA_POST == code || CA_PUT == code || CA_DELETE == code)
     {
-        CARemoveBlockDataFromList(blockDataID);
+        // if received message type is RESET from remote device,
+        // we have to use the updated message id of request message to find token.
+        CABlockData_t *blockData = CAGetBlockDataFromBlockDataList(blockDataID);
+        if (blockData)
+        {
+            res = CAUpdateMessageId(*pdu, blockDataID);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "fail to update message id");
+                goto exit;
+            }
+        }
     }
+
+exit:
     CADestroyBlockID(blockDataID);
     OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption");
     return res;
@@ -1621,6 +1614,7 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t data
             }
         }
 
+        // add block option to option list.
         res = CAAddBlockOptionImpl(block1, COAP_OPTION_BLOCK1, options);
         if (CA_STATUS_OK != res)
         {
@@ -1628,6 +1622,7 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t data
             goto exit;
         }
 
+        // add option list to pdu.
         res = CAAddOptionToPDU(*pdu, options);
         if (CA_STATUS_OK != res)
         {
@@ -1635,6 +1630,7 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t data
             goto exit;
         }
 
+        // add the payload data as the block size.
         if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info->payload, block1->num,
                             block1->szx))
         {
@@ -1645,6 +1641,8 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t data
     else
     {
         OIC_LOG(DEBUG, TAG, "received response message with block option1");
+
+        // add block option to option list.
         res = CAAddBlockOptionImpl(block1, COAP_OPTION_BLOCK1, options);
         if (CA_STATUS_OK != res)
         {
@@ -1652,6 +1650,7 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t data
             goto exit;
         }
 
+        // add option list to pdu.
         res = CAAddOptionToPDU(*pdu, options);
         if (CA_STATUS_OK != res)
         {
@@ -1659,13 +1658,14 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t *info, size_t data
             goto exit;
         }
 
+        // add the payload data as the block size.
         if (!coap_add_data(*pdu, dataLength, (const unsigned char *) info->payload))
         {
             OIC_LOG(ERROR, TAG, "failed to add payload");
             return CA_STATUS_FAILED;
         }
 
-        // reset block-list after write block
+        // if it is last block message, remove block data from list.
         if (0 == block1->m)
         {
             // remove data from list
@@ -2032,11 +2032,20 @@ CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint
 
         // get resource uri information from received response message
         // to send next request message to remote device
-        CAResponseInfo_t resInfo = { 0 };
-        CAGetResponseInfoFromPDU(pdu, &resInfo, endpoint);
+        CAResponseInfo_t* resInfo = (CAResponseInfo_t*)OICCalloc(1, sizeof(*resInfo));
+        if (!resInfo)
+        {
+            OIC_LOG(ERROR, TAG, "memory allocation failed");
+            OICFree(requestData.token);
+            return NULL;
+        }
 
+        CAGetResponseInfoFromPDU(pdu, resInfo, endpoint);
         requestInfo->method = CA_GET;
-        requestInfo->info.resourceUri = resInfo.info.resourceUri;
+        requestInfo->info.resourceUri = OICStrdup(resInfo->info.resourceUri);
+
+        // after copying the resource uri, destroy response info.
+        CADestroyResponseInfoInternal(resInfo);
     }
 
     CAData_t *data = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
@@ -2358,7 +2367,6 @@ CAResult_t CACheckBlockDataValidation(const CAData_t *sendData, CABlockData_t **
     for (size_t i = 0; i < len; i++)
     {
         CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
-
         if (!currData)
         {
             continue;
@@ -2456,7 +2464,7 @@ coap_block_t *CAGetBlockOption(const CABlockDataID_t *blockID, uint16_t blockTyp
             {
                 return &currData->block2;
             }
-            else
+            else if (COAP_OPTION_BLOCK1 == blockType)
             {
                 return &currData->block1;
             }
@@ -2592,10 +2600,7 @@ CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID)
             }
 
             // destroy memory
-            if (currData->sentData)
-            {
-                CADestroyDataSet(currData->sentData);
-            }
+            CADestroyDataSet(currData->sentData);
             CADestroyBlockID(currData->blockDataId);
             OICFree(currData->payload);
             OICFree(currData);
@@ -2608,6 +2613,33 @@ CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID)
     return CA_STATUS_OK;
 }
 
+CAResult_t CARemoveAllBlockDataFromList()
+{
+    OIC_LOG(DEBUG, TAG, "CARemoveAllBlockDataFromList");
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = len; i > 0; i--)
+    {
+        CABlockData_t *removedData = u_arraylist_remove(g_context.dataList, i - 1);
+        if (removedData)
+        {
+            // destroy memory
+            if (removedData->sentData)
+            {
+                CADestroyDataSet(removedData->sentData);
+            }
+            CADestroyBlockID(removedData->blockDataId);
+            OICFree(removedData->payload);
+            OICFree(removedData);
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return CA_STATUS_OK;
+}
+
 void CADestroyDataSet(CAData_t* data)
 {
     VERIFY_NON_NULL_VOID(data, TAG, "data");
@@ -2689,3 +2721,30 @@ void CALogBlockInfo(coap_block_t *block)
 
     OIC_LOG_V(DEBUG, TAG, "block option-szx : %d", block->szx);
 }
+
+CAResult_t CARemoveBlockDataFromListWithSeed(const CAToken_t token, uint8_t tokenLength,
+                                             uint16_t portNumber)
+{
+    CABlockDataID_t* blockDataID = CACreateBlockDatablockId(token, tokenLength, portNumber);
+    if (NULL == blockDataID || blockDataID->idLength < 1)
+    {
+        OIC_LOG(ERROR, TAG, "blockId is null");
+        CADestroyBlockID(blockDataID);
+        return CA_STATUS_FAILED;
+    }
+
+    CAResult_t res = CA_STATUS_OK;
+
+    if (NULL != CAGetBlockDataFromBlockDataList(blockDataID))
+    {
+        res = CARemoveBlockDataFromList(blockDataID);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CARemoveBlockDataFromList failed");
+        }
+    }
+
+    CADestroyBlockID(blockDataID);
+
+    return res;
+}