Merge "Merge branch 'master' into group-manager" into group-manager
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocserverrequest.c
index 43efdc5..8263100 100644 (file)
 #include "oic_string.h"
 #include "ocpayload.h"
 #include "ocpayloadcbor.h"
+#include "logger.h"
+
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+#include "routingutility.h"
+#endif
 
 #include "cacommon.h"
 #include "cainterface.h"
@@ -34,9 +39,9 @@
 #include "pdu.h"
 
 // Module Name
-#define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
+#define VERIFY_NON_NULL(arg) { if (!arg) {OIC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
 
-#define TAG  PCF("ocserverrequest")
+#define TAG  "OIC_RI_SERVERREQUEST"
 
 static struct OCServerRequest * serverRequestList = NULL;
 static struct OCServerResponse * serverResponseList = NULL;
@@ -56,6 +61,11 @@ static struct OCServerResponse * serverResponseList = NULL;
  */
 static OCStackResult AddServerResponse (OCServerResponse ** response, OCRequestHandle requestHandle)
 {
+    if (!response)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
     OCServerResponse * serverResponse = NULL;
 
     serverResponse = (OCServerResponse *) OICCalloc(1, sizeof(OCServerResponse));
@@ -66,7 +76,7 @@ static OCStackResult AddServerResponse (OCServerResponse ** response, OCRequestH
     serverResponse->requestHandle = requestHandle;
 
     *response = serverResponse;
-    OC_LOG(INFO, TAG, PCF("Server Response Added!!"));
+    OIC_LOG(INFO, TAG, "Server Response Added!!");
     LL_APPEND (serverResponseList, serverResponse);
     return OC_STACK_OK;
 
@@ -93,7 +103,7 @@ static void DeleteServerRequest(OCServerRequest * serverRequest)
         OICFree(serverRequest->requestToken);
         OICFree(serverRequest);
         serverRequest = NULL;
-        OC_LOG(INFO, TAG, PCF("Server Request Removed!!"));
+        OIC_LOG(INFO, TAG, "Server Request Removed!!");
     }
 }
 
@@ -107,9 +117,9 @@ static void DeleteServerResponse(OCServerResponse * serverResponse)
     if(serverResponse)
     {
         LL_DELETE(serverResponseList, serverResponse);
-        OICFree(serverResponse->payload);
+        OCPayloadDestroy(serverResponse->payload);
         OICFree(serverResponse);
-        OC_LOG(INFO, TAG, PCF("Server Response Removed!!"));
+        OIC_LOG(INFO, TAG, "Server Response Removed!!");
     }
 }
 
@@ -134,6 +144,38 @@ static void FindAndDeleteServerResponse(OCServerResponse * serverResponse)
     }
 }
 
+/**
+ * Ensure no accept header option is included when sending responses and add routing info to
+ * outgoing response.
+ *
+ * @param object CA remote endpoint.
+ * @param requestInfo CA request info.
+ *
+ * @return ::OC_STACK_OK on success, some other value upon failure.
+ */
+static OCStackResult OCSendResponse(const CAEndpoint_t *object, CAResponseInfo_t *responseInfo)
+{
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    // Add route info in RM option.
+    OCStackResult rmResult = RMAddInfo(object->routeData, responseInfo, false, NULL);
+    if(OC_STACK_OK != rmResult)
+    {
+        OIC_LOG(ERROR, TAG, "Add option failed");
+        return rmResult;
+    }
+#endif
+
+    // Do not include the accept header option
+    responseInfo->info.acceptFormat = CA_FORMAT_UNDEFINED;
+    CAResult_t result = CASendResponse(object, responseInfo);
+    if(CA_STATUS_OK != result)
+    {
+        OIC_LOG_V(ERROR, TAG, "CASendResponse failed with CA error %u", result);
+        return CAResultToOCResult(result);
+    }
+    return OC_STACK_OK;
+}
+
 //-------------------------------------------------------------------------------------------------
 // Internal APIs
 //-------------------------------------------------------------------------------------------------
@@ -151,24 +193,24 @@ OCServerRequest * GetServerRequestUsingToken (const CAToken_t token, uint8_t tok
 {
     if(!token)
     {
-        OC_LOG(ERROR, TAG, PCF("Invalid Parameter Token"));
+        OIC_LOG(ERROR, TAG, "Invalid Parameter Token");
         return NULL;
     }
 
     OCServerRequest * out = NULL;
-    OC_LOG(INFO, TAG,PCF("Get server request with token"));
-    OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
+    OIC_LOG(INFO, TAG,"Get server request with token");
+    OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
 
-    OC_LOG(INFO, TAG,PCF("Found token"));
+    OIC_LOG(INFO, TAG,"Found token");
     LL_FOREACH (serverRequestList, out)
     {
-        OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->requestToken, tokenLength);
+        OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->requestToken, tokenLength);
         if(memcmp(out->requestToken, token, tokenLength) == 0)
         {
             return out;
         }
     }
-    OC_LOG(ERROR, TAG, PCF("Server Request not found!!"));
+    OIC_LOG(ERROR, TAG, "Server Request not found!!");
     return NULL;
 }
 
@@ -189,7 +231,7 @@ OCServerRequest * GetServerRequestUsingHandle (const OCServerRequest * handle)
             return out;
         }
     }
-    OC_LOG(ERROR, TAG, PCF("Server Request not found!!"));
+    OIC_LOG(ERROR, TAG, "Server Request not found!!");
     return NULL;
 }
 
@@ -211,7 +253,7 @@ OCServerResponse * GetServerResponseUsingHandle (const OCServerRequest * handle)
             return out;
         }
     }
-    OC_LOG(ERROR, TAG, PCF("Server Response not found!!"));
+    OIC_LOG(ERROR, TAG, "Server Response not found!!");
     return NULL;
 }
 
@@ -221,10 +263,18 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
         OCQualityOfService qos, char * query,
         OCHeaderOption * rcvdVendorSpecificHeaderOptions,
         uint8_t * payload, CAToken_t requestToken, uint8_t tokenLength,
-        char * resourceUrl, size_t reqTotalSize, const OCDevAddr *devAddr)
+        char * resourceUrl, size_t reqTotalSize, OCPayloadFormat acceptFormat,
+        const OCDevAddr *devAddr)
 {
+    if (!request)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
     OCServerRequest * serverRequest = NULL;
 
+    OIC_LOG_V(INFO, TAG, "addserverrequest entry!! [%s:%u]", devAddr->addr, devAddr->port);
+
     serverRequest = (OCServerRequest *) OICCalloc(1, sizeof(OCServerRequest) +
         (reqTotalSize ? reqTotalSize : 1) - 1);
     VERIFY_NON_NULL(devAddr);
@@ -239,6 +289,7 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
     serverRequest->observationOption = observationOption;
     serverRequest->observeResult = OC_STACK_ERROR;
     serverRequest->qos = qos;
+    serverRequest->acceptFormat = acceptFormat;
     serverRequest->ehResponseHandler = HandleSingleResponse;
     serverRequest->numResponses = 1;
 
@@ -284,7 +335,7 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
     serverRequest->devAddr = *devAddr;
 
     *request = serverRequest;
-    OC_LOG(INFO, TAG, PCF("Server Request Added!!"));
+    OIC_LOG(INFO, TAG, "Server Request Added!!");
     LL_APPEND (serverRequestList, serverRequest);
     return OC_STACK_OK;
 
@@ -305,6 +356,7 @@ OCStackResult FormOCEntityHandlerRequest(
         OCDevAddr *endpoint,
         OCResourceHandle resource,
         char * queryBuf,
+        OCPayloadType payloadType,
         uint8_t * payload,
         size_t payloadSize,
         uint8_t numVendorOptions,
@@ -324,7 +376,8 @@ OCStackResult FormOCEntityHandlerRequest(
 
         if(payload && payloadSize)
         {
-            if(OCParsePayload(&entityHandlerRequest->payload, payload, payloadSize) != OC_STACK_OK)
+            if(OCParsePayload(&entityHandlerRequest->payload, payloadType,
+                        payload, payloadSize) != OC_STACK_OK)
             {
                 return OC_STACK_ERROR;
             }
@@ -364,14 +417,32 @@ void FindAndDeleteServerRequest(OCServerRequest * serverRequest)
     }
 }
 
-CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result)
+CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result, OCMethod method)
 {
-    CAResponseResult_t caResult = CA_BAD_REQ;
+    CAResponseResult_t caResult;
 
     switch (result)
     {
         case OC_EH_OK:
-            caResult = CA_SUCCESS;
+           switch (method)
+           {
+               case OC_REST_PUT:
+               case OC_REST_POST:
+                   // This Response Code is like HTTP 204 "No Content" but only used in
+                   // response to POST and PUT requests.
+                   caResult = CA_CHANGED;
+                   break;
+               case OC_REST_GET:
+                   // This Response Code is like HTTP 200 "OK" but only used in response to
+                   // GET requests.
+                   caResult = CA_CONTENT;
+                   break;
+               default:
+                   // This should not happen but,
+                   // give it a value just in case but output an error
+                   caResult = CA_CONTENT;
+                   OIC_LOG_V(ERROR, TAG, "Unexpected OC_EH_OK return code for method [%d].", method);
+           }
             break;
         case OC_EH_ERROR:
             caResult = CA_BAD_REQ;
@@ -383,7 +454,7 @@ CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result)
             caResult = CA_DELETED;
             break;
         case OC_EH_SLOW:
-            caResult = CA_SUCCESS;
+            caResult = CA_CONTENT;
             break;
         case OC_EH_FORBIDDEN:
             caResult = CA_UNAUTHORIZED_REQ;
@@ -407,7 +478,6 @@ CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result)
  * @return
  *     OCStackResult
  */
-
 OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
 {
     OCStackResult result = OC_STACK_ERROR;
@@ -417,6 +487,7 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
 
     if(!ehResponse || !ehResponse->requestHandle)
     {
+        OIC_LOG(ERROR, TAG, "ehResponse/requestHandle is NULL");
         return OC_STACK_ERROR;
     }
 
@@ -425,7 +496,7 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
     CopyDevAddrToEndpoint(&serverRequest->devAddr, &responseEndpoint);
 
     responseInfo.info.resourceUri = serverRequest->resourceUrl;
-    responseInfo.result = ConvertEHResultToCAResult(ehResponse->ehResult);
+    responseInfo.result = ConvertEHResultToCAResult(ehResponse->ehResult, serverRequest->method);
 
     if(serverRequest->notificationFlag && serverRequest->qos == OC_HIGH_QOS)
     {
@@ -449,6 +520,11 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
     {
         responseInfo.info.type = CA_MSG_NONCONFIRM;
     }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "default responseInfo type is NON");
+        responseInfo.info.type = CA_MSG_NONCONFIRM;
+    }
 
     char rspToken[CA_MAX_TOKEN_LEN + 1] = {};
     responseInfo.info.messageId = serverRequest->coapID;
@@ -474,7 +550,7 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
 
         if(!responseInfo.info.options)
         {
-            OC_LOG(FATAL, TAG, PCF("Memory alloc for options failed"));
+            OIC_LOG(FATAL, TAG, "Memory alloc for options failed");
             return OC_STACK_NO_MEMORY;
         }
 
@@ -487,8 +563,14 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
             responseInfo.info.options[0].protocolID = CA_COAP_ID;
             responseInfo.info.options[0].optionID = COAP_OPTION_OBSERVE;
             responseInfo.info.options[0].optionLength = sizeof(uint32_t);
-            memcpy(responseInfo.info.options[0].optionData,
-                    &(serverRequest->observationOption), sizeof(uint32_t));
+            uint8_t* observationData = (uint8_t*)responseInfo.info.options[0].optionData;
+            uint32_t observationOption= serverRequest->observationOption;
+
+            for (size_t i=sizeof(uint32_t); i; --i)
+            {
+                observationData[i-1] = observationOption & 0xFF;
+                observationOption >>=8;
+            }
 
             // Point to the next header option before copying vender specific header options
             optionsPointer += 1;
@@ -506,50 +588,58 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
         responseInfo.info.options = NULL;
     }
 
+    responseInfo.isMulticast = false;
+    responseInfo.info.payload = NULL;
+    responseInfo.info.payloadSize = 0;
+    responseInfo.info.payloadFormat = CA_FORMAT_UNDEFINED;
+
     // Put the JSON prefix and suffix around the payload
     if(ehResponse->payload)
     {
-        OCStackResult result;
-        if((result = OCConvertPayload(ehResponse->payload, &responseInfo.info.payload,
-                    &responseInfo.info.payloadSize))
-                != OC_STACK_OK)
+        if (ehResponse->payload->type == PAYLOAD_TYPE_PRESENCE)
+        {
+            responseInfo.isMulticast = true;
+        }
+        else
         {
-            OC_LOG(ERROR, TAG, "Error converting payload");
-            OICFree(responseInfo.info.options);
-            return result;
+            responseInfo.isMulticast = false;
         }
 
-        if(responseInfo.info.payloadSize > MAX_RESPONSE_LENGTH)
+        switch(serverRequest->acceptFormat)
         {
-            OICFree(responseInfo.info.payload);
-            OC_LOG(ERROR, TAG, "Payload too long!");
-            OICFree(responseInfo.info.options);
-            return OC_STACK_INVALID_PARAM;
+            case OC_FORMAT_UNDEFINED:
+                // No preference set by the client, so default to CBOR then
+            case OC_FORMAT_CBOR:
+                if((result = OCConvertPayload(ehResponse->payload, &responseInfo.info.payload,
+                                &responseInfo.info.payloadSize))
+                        != OC_STACK_OK)
+                {
+                    OIC_LOG(ERROR, TAG, "Error converting payload");
+                    OICFree(responseInfo.info.options);
+                    return result;
+                }
+                responseInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
+                break;
+            default:
+                responseInfo.result = CA_NOT_ACCEPTABLE;
         }
     }
-    else
-    {
-        responseInfo.info.payload = NULL;
-        responseInfo.info.payloadSize = 0;
-    }
 
-    #ifdef WITH_PRESENCE
+#ifdef WITH_PRESENCE
     CATransportAdapter_t CAConnTypes[] = {
                             CA_ADAPTER_IP,
                             CA_ADAPTER_GATT_BTLE,
-                            CA_ADAPTER_RFCOMM_BTEDR
-
-                            #ifdef RA_ADAPTER
+                            CA_ADAPTER_RFCOMM_BTEDR,
+                            CA_ADAPTER_NFC
+#ifdef RA_ADAPTER
                             , CA_ADAPTER_REMOTE_ACCESS
-                            #endif
+#endif
+                            , CA_ADAPTER_TCP
                         };
 
-    int size = sizeof(CAConnTypes)/ sizeof(CATransportAdapter_t);
+    size_t size = sizeof(CAConnTypes)/ sizeof(CATransportAdapter_t);
 
     CATransportAdapter_t adapter = responseEndpoint.adapter;
-    CAResult_t caResult = CA_STATUS_FAILED;
-    result = OC_STACK_OK;
-
     // Default adapter, try to send response out on all adapters.
     if (adapter == CA_DEFAULT_ADAPTER)
     {
@@ -557,48 +647,42 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
             (CATransportAdapter_t)(
                 CA_ADAPTER_IP           |
                 CA_ADAPTER_GATT_BTLE    |
-                CA_ADAPTER_RFCOMM_BTEDR
-
-                #ifdef RA_ADAP
+                CA_ADAPTER_RFCOMM_BTEDR |
+                CA_ADAPTER_NFC
+#ifdef RA_ADAP
                 | CA_ADAPTER_REMOTE_ACCESS
-                #endif
+#endif
+                | CA_ADAPTER_TCP
             );
     }
 
-    for(int i = 0; i < size; i++ )
+    result = OC_STACK_OK;
+    OCStackResult tempResult = OC_STACK_OK;
+
+    for(size_t i = 0; i < size; i++ )
     {
         responseEndpoint.adapter = (CATransportAdapter_t)(adapter & CAConnTypes[i]);
         if(responseEndpoint.adapter)
         {
-            //The result is set to OC_STACK_OK only if CASendResponse succeeds in sending the
+            //The result is set to OC_STACK_OK only if OCSendResponse succeeds in sending the
             //response on all the n/w interfaces else it is set to OC_STACK_ERROR
-            caResult = CASendResponse(&responseEndpoint, &responseInfo);
-            if(caResult != CA_STATUS_OK)
-            {
-                OC_LOG_V(ERROR, TAG, "CASendResponse failed with CA error %u", caResult);
-                result = CAResultToOCResult(caResult);
-            }
+            tempResult = OCSendResponse(&responseEndpoint, &responseInfo);
+        }
+        if(OC_STACK_OK != tempResult)
+        {
+            result = tempResult;
         }
     }
-    #else
+#else
 
-    OC_LOG(INFO, TAG, PCF("Calling CASendResponse with:"));
-    OC_LOG_V(INFO, TAG, "\tEndpoint address: %s", responseEndpoint.addr);
-    OC_LOG_V(INFO, TAG, "\tEndpoint adapter: %s", responseEndpoint.adapter);
-    OC_LOG_V(INFO, TAG, "\tResponse result : %s", responseInfo.result);
-    OC_LOG_V(INFO, TAG, "\tResponse for uri: %s", responseInfo.info.resourceUri);
+    OIC_LOG(INFO, TAG, "Calling OCSendResponse with:");
+    OIC_LOG_V(INFO, TAG, "\tEndpoint address: %s", responseEndpoint.addr);
+    OIC_LOG_V(INFO, TAG, "\tEndpoint adapter: %s", responseEndpoint.adapter);
+    OIC_LOG_V(INFO, TAG, "\tResponse result : %s", responseInfo.result);
+    OIC_LOG_V(INFO, TAG, "\tResponse for uri: %s", responseInfo.info.resourceUri);
 
-    CAResult_t caResult = CASendResponse(&responseEndpoint, &responseInfo);
-    if(caResult != CA_STATUS_OK)
-    {
-        OC_LOG(ERROR, TAG, PCF("CASendResponse failed"));
-        result = CAResultToOCResult(caResult);
-    }
-    else
-    {
-        result = OC_STACK_OK;
-    }
-    #endif
+    result = OCSendResponse(&responseEndpoint, &responseInfo);
+#endif
 
     OICFree(responseInfo.info.payload);
     OICFree(responseInfo.info.options);
@@ -621,30 +705,29 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
  */
 OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
 {
-    OCStackResult stackRet = OC_STACK_ERROR;
-    OCServerRequest * serverRequest = NULL;
-    OCServerResponse * serverResponse = NULL;
-
     if(!ehResponse || !ehResponse->payload)
     {
-        OC_LOG(ERROR, TAG, PCF("HandleAggregateResponse invalid parameters"));
+        OIC_LOG(ERROR, TAG, "HandleAggregateResponse invalid parameters");
         return OC_STACK_INVALID_PARAM;
     }
 
-    OC_LOG(INFO, TAG, "Inside HandleAggregateResponse");
+    OIC_LOG(INFO, TAG, "Inside HandleAggregateResponse");
 
-    serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
-    serverResponse = GetServerResponseUsingHandle((OCServerRequest *)ehResponse->requestHandle);
+    OCServerRequest *serverRequest = GetServerRequestUsingHandle((OCServerRequest *)
+                                                                 ehResponse->requestHandle);
+    OCServerResponse *serverResponse = GetServerResponseUsingHandle((OCServerRequest *)
+                                                                    ehResponse->requestHandle);
 
+    OCStackResult stackRet = OC_STACK_ERROR;
     if(serverRequest)
     {
         if(!serverResponse)
         {
-            OC_LOG(INFO, TAG, PCF("This is the first response fragment"));
+            OIC_LOG(INFO, TAG, "This is the first response fragment");
             stackRet = AddServerResponse(&serverResponse, ehResponse->requestHandle);
             if (OC_STACK_OK != stackRet)
             {
-                OC_LOG(ERROR, TAG, PCF("Error adding server response"));
+                OIC_LOG(ERROR, TAG, "Error adding server response");
                 return stackRet;
             }
             VERIFY_NON_NULL(serverResponse);
@@ -653,18 +736,20 @@ OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
         if(ehResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
         {
             stackRet = OC_STACK_ERROR;
-            OC_LOG(ERROR, TAG, PCF("Error adding payload, as it was the incorrect type"));
+            OIC_LOG(ERROR, TAG, "Error adding payload, as it was the incorrect type");
             goto exit;
         }
 
+        OCRepPayload *newPayload = OCRepPayloadClone((OCRepPayload *)ehResponse->payload);
+
         if(!serverResponse->payload)
         {
-            serverResponse->payload = ehResponse->payload;
+            serverResponse->payload = (OCPayload *)newPayload;
         }
         else
         {
             OCRepPayloadAppend((OCRepPayload*)serverResponse->payload,
-                    (OCRepPayload*)ehResponse->payload);
+                    (OCRepPayload*)newPayload);
         }
 
 
@@ -672,7 +757,7 @@ OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
 
         if(serverRequest->numResponses == 0)
         {
-            OC_LOG(INFO, TAG, PCF("This is the last response fragment"));
+            OIC_LOG(INFO, TAG, "This is the last response fragment");
             ehResponse->payload = serverResponse->payload;
             stackRet = HandleSingleResponse(ehResponse);
             //Delete the request and response
@@ -681,7 +766,7 @@ OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
         }
         else
         {
-            OC_LOG(INFO, TAG, PCF("More response fragments to come"));
+            OIC_LOG(INFO, TAG, "More response fragments to come");
             stackRet = OC_STACK_OK;
         }
     }