// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <string.h>
#include "ocstack.h"
#include "ocserverrequest.h"
#include "ocresourcehandler.h"
+#include "oic_malloc.h"
+#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"
+#include "utlist.h"
+#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;
-OCServerRequest * GetServerRequestUsingToken (const CAToken_t token)
+//-------------------------------------------------------------------------------------------------
+// Local functions
+//-------------------------------------------------------------------------------------------------
+
+/**
+ * Add a server response to the server response list
+ *
+ * @param response initialized server response that is created by this function
+ * @param requestHandle - handle of the response
+ *
+ * @return
+ * OCStackResult
+ */
+static OCStackResult AddServerResponse (OCServerResponse ** response, OCRequestHandle requestHandle)
+{
+ if (!response)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ OCServerResponse * serverResponse = NULL;
+
+ serverResponse = (OCServerResponse *) OICCalloc(1, sizeof(OCServerResponse));
+ VERIFY_NON_NULL(serverResponse);
+
+ serverResponse->payload = NULL;
+
+ serverResponse->requestHandle = requestHandle;
+
+ *response = serverResponse;
+ OIC_LOG(INFO, TAG, "Server Response Added!!");
+ LL_APPEND (serverResponseList, serverResponse);
+ return OC_STACK_OK;
+
+exit:
+ if (serverResponse)
+ {
+ OICFree(serverResponse);
+ serverResponse = NULL;
+ }
+ *response = NULL;
+ return OC_STACK_NO_MEMORY;
+}
+
+/**
+ * Delete a server request from the server request list
+ *
+ * @param serverRequest - server request to delete
+ */
+static void DeleteServerRequest(OCServerRequest * serverRequest)
+{
+ if(serverRequest)
+ {
+ LL_DELETE(serverRequestList, serverRequest);
+ OICFree(serverRequest->requestToken);
+ OICFree(serverRequest);
+ serverRequest = NULL;
+ OIC_LOG(INFO, TAG, "Server Request Removed!!");
+ }
+}
+
+/**
+ * Delete a server response from the server response list
+ *
+ * @param serverResponse - server response to delete
+ */
+static void DeleteServerResponse(OCServerResponse * serverResponse)
+{
+ if(serverResponse)
+ {
+ LL_DELETE(serverResponseList, serverResponse);
+ OCPayloadDestroy(serverResponse->payload);
+ OICFree(serverResponse);
+ OIC_LOG(INFO, TAG, "Server Response Removed!!");
+ }
+}
+
+/**
+ * Find a server response and delete it from the server response list
+ *
+ * @param serverResponse - server response to find and delete
+ */
+static void FindAndDeleteServerResponse(OCServerResponse * serverResponse)
+{
+ OCServerResponse* tmp;
+ if(serverResponse)
+ {
+ LL_FOREACH(serverResponseList, tmp)
+ {
+ if (serverResponse == tmp)
+ {
+ DeleteServerResponse(tmp);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * 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
+//-------------------------------------------------------------------------------------------------
+
+/**
+ * Get a server request from the server request list using the specified token.
+ *
+ * @param token - token of server request
+ * @param tokenLength - length of token
+ *
+ * @return
+ * OCServerRequest*
+ */
+OCServerRequest * GetServerRequestUsingToken (const CAToken_t token, uint8_t tokenLength)
+{
+ if(!token)
+ {
+ OIC_LOG(ERROR, TAG, "Invalid Parameter Token");
+ return NULL;
+ }
+
OCServerRequest * out = NULL;
+ OIC_LOG(INFO, TAG,"Get server request with token");
+ OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
+
+ OIC_LOG(INFO, TAG,"Found token");
LL_FOREACH (serverRequestList, out)
{
- OC_LOG(INFO, TAG,PCF("comparing tokens"));
- OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, CA_MAX_TOKEN_LEN);
- OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->requestToken, CA_MAX_TOKEN_LEN);
- if(memcmp(out->requestToken, token, CA_MAX_TOKEN_LEN) == 0)
+ OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->requestToken, tokenLength);
+ if(memcmp(out->requestToken, token, tokenLength) == 0)
{
return out;
}
}
- OC_LOG(INFO, TAG, PCF("Server Request not found!!"));
+ OIC_LOG(ERROR, TAG, "Server Request not found!!");
return NULL;
}
+/**
+ * Get a server request from the server request list using the specified handle
+ *
+ * @param handle - handle of server request
+ * @return
+ * OCServerRequest*
+ */
OCServerRequest * GetServerRequestUsingHandle (const OCServerRequest * handle)
{
OCServerRequest * out = NULL;
return out;
}
}
- OC_LOG(INFO, TAG, PCF("Server Request not found!!"));
+ OIC_LOG(ERROR, TAG, "Server Request not found!!");
return NULL;
}
+/**
+ * Get a server response from the server response list using the specified handle
+ *
+ * @param handle - handle of server response
+ *
+ * @return
+ * OCServerResponse*
+ */
OCServerResponse * GetServerResponseUsingHandle (const OCServerRequest * handle)
{
OCServerResponse * out = NULL;
return out;
}
}
- OC_LOG(INFO, TAG, PCF("Server Response not found!!"));
+ OIC_LOG(ERROR, TAG, "Server Response not found!!");
return NULL;
}
OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
- uint8_t delayedResNeeded, uint8_t secured, uint8_t notificationFlag, OCMethod method,
+ uint8_t delayedResNeeded, uint8_t notificationFlag, OCMethod method,
uint8_t numRcvdVendorSpecificHeaderOptions, uint32_t observationOption,
- OCQualityOfService qos, unsigned char * query,
+ OCQualityOfService qos, char * query,
OCHeaderOption * rcvdVendorSpecificHeaderOptions,
- unsigned char * reqJSONPayload, CAToken_t * requestToken,
- OCDevAddr * requesterAddr, unsigned char * resourceUrl, size_t reqTotalSize,
- CAAddress_t *addressInfo, CAConnectivityType_t connectivityType)
+ uint8_t * payload, CAToken_t requestToken, uint8_t tokenLength,
+ char * resourceUrl, size_t reqTotalSize, OCPayloadFormat acceptFormat,
+ const OCDevAddr *devAddr)
{
+ if (!request)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
OCServerRequest * serverRequest = NULL;
- //Note: OCServerRequest includes 1 byte for the JSON Payload. payloadSize is calculated
- //as the required length of the string, so this will result in enough room for the
- //null terminator as well.
- serverRequest = (OCServerRequest *) OCCalloc(1, sizeof(OCServerRequest) + reqTotalSize - 1);
+ 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);
VERIFY_NON_NULL(serverRequest);
serverRequest->coapID = coapID;
serverRequest->delayedResNeeded = delayedResNeeded;
- serverRequest->secured = secured;
serverRequest->notificationFlag = notificationFlag;
serverRequest->method = method;
serverRequest->observationOption = observationOption;
serverRequest->observeResult = OC_STACK_ERROR;
serverRequest->qos = qos;
+ serverRequest->acceptFormat = acceptFormat;
serverRequest->ehResponseHandler = HandleSingleResponse;
serverRequest->numResponses = 1;
+
if(query)
{
- memcpy(serverRequest->query, query, strlen((const char *)query) + 1);
+ OICStrcpy(serverRequest->query, sizeof(serverRequest->query), query);
}
+
if(rcvdVendorSpecificHeaderOptions)
{
memcpy(serverRequest->rcvdVendorSpecificHeaderOptions, rcvdVendorSpecificHeaderOptions,
MAX_HEADER_OPTIONS * sizeof(OCHeaderOption));
}
- if(reqJSONPayload)
+ if(payload && reqTotalSize)
{
- // destination is at least 1 greater than the source, so a NULL always exists in the
+ // destination is at least 1 greater than the source, so a NULL always exists in the
// last character
- strncpy((char*)serverRequest->reqJSONPayload,
- (const char*)reqJSONPayload, reqTotalSize - 1);
+ memcpy(serverRequest->payload, payload, reqTotalSize);
+ serverRequest->payloadSize = reqTotalSize;
}
+
serverRequest->requestComplete = 0;
if(requestToken)
{
- serverRequest->requestToken = (CAToken_t)OCMalloc(CA_MAX_TOKEN_LEN+1);
- VERIFY_NON_NULL (serverRequest->requestToken);
- memset(serverRequest->requestToken, 0, CA_MAX_TOKEN_LEN + 1);
- memcpy(serverRequest->requestToken, *requestToken, CA_MAX_TOKEN_LEN);
- }
- if(requesterAddr)
- {
- memcpy(&serverRequest->requesterAddr, requesterAddr, sizeof(OCDevAddr));
+ // If tokenLength is zero, the return value depends on the
+ // particular library implementation (it may or may not be a null pointer).
+ if (tokenLength)
+ {
+ serverRequest->requestToken = (CAToken_t) OICMalloc(tokenLength);
+ VERIFY_NON_NULL(serverRequest->requestToken);
+ memcpy(serverRequest->requestToken, requestToken, tokenLength);
+ }
+
}
+ serverRequest->tokenLength = tokenLength;
+
if(resourceUrl)
{
- memcpy(serverRequest->resourceUrl, resourceUrl, strlen((const char *)resourceUrl) + 1);
- }
- if (addressInfo)
- {
- serverRequest->addressInfo = *addressInfo;
+ OICStrcpy(serverRequest->resourceUrl, sizeof(serverRequest->resourceUrl),
+ resourceUrl);
}
- serverRequest->connectivityType = connectivityType;
+
+ 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;
exit:
if (serverRequest)
{
- OCFree(serverRequest);
+ OICFree(serverRequest);
serverRequest = NULL;
}
*request = NULL;
return OC_STACK_NO_MEMORY;
}
-OCStackResult AddServerResponse (OCServerResponse ** response, OCRequestHandle requestHandle)
-{
- OCServerResponse * serverResponse = NULL;
-
- serverResponse = (OCServerResponse *) OCCalloc(1, sizeof(OCServerResponse));
- VERIFY_NON_NULL(serverResponse);
-
- serverResponse->payload = (unsigned char *) OCMalloc(MAX_RESPONSE_LENGTH);
- VERIFY_NON_NULL(serverResponse->payload);
- memset(serverResponse->payload, 0, MAX_RESPONSE_LENGTH);
-
- serverResponse->remainingPayloadSize = MAX_RESPONSE_LENGTH;
- serverResponse->requestHandle = requestHandle;
-
- *response = serverResponse;
- OC_LOG(INFO, TAG, PCF("Server Response Added!!"));
- LL_APPEND (serverResponseList, serverResponse);
- return OC_STACK_OK;
-
-exit:
- if (serverResponse)
- {
- OCFree(serverResponse);
- serverResponse = NULL;
- }
- *response = NULL;
- return OC_STACK_NO_MEMORY;
-}
-
-// Form the OCEntityHandlerRequest struct
-OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * entityHandlerRequest, OCRequestHandle request,
- OCMethod method, OCResourceHandle resource, unsigned char * queryBuf, unsigned char * bufReqPayload,
- uint8_t numVendorOptions, OCHeaderOption * vendorOptions, OCObserveAction observeAction,
+OCStackResult FormOCEntityHandlerRequest(
+ OCEntityHandlerRequest * entityHandlerRequest,
+ OCRequestHandle request,
+ OCMethod method,
+ OCDevAddr *endpoint,
+ OCResourceHandle resource,
+ char * queryBuf,
+ OCPayloadType payloadType,
+ uint8_t * payload,
+ size_t payloadSize,
+ uint8_t numVendorOptions,
+ OCHeaderOption * vendorOptions,
+ OCObserveAction observeAction,
OCObservationId observeID)
{
if (entityHandlerRequest)
{
- memset(entityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
+ entityHandlerRequest->resource = (OCResourceHandle) resource;
entityHandlerRequest->requestHandle = request;
entityHandlerRequest->method = method;
- entityHandlerRequest->resource = (OCResourceHandle) resource;
+ entityHandlerRequest->devAddr = *endpoint;
entityHandlerRequest->query = queryBuf;
- entityHandlerRequest->reqJSONPayload = bufReqPayload;
- entityHandlerRequest->numRcvdVendorSpecificHeaderOptions = numVendorOptions;
- entityHandlerRequest->rcvdVendorSpecificHeaderOptions = vendorOptions;
-
entityHandlerRequest->obsInfo.action = observeAction;
entityHandlerRequest->obsInfo.obsId = observeID;
- return OC_STACK_OK;
- }
- return OC_STACK_INVALID_PARAM;
-}
-
-void FindAndDeleteServerResponse(OCServerResponse * serverResponse)
-{
- OCServerResponse* tmp;
- if(serverResponse)
- {
- LL_FOREACH(serverResponseList, tmp)
+ if(payload && payloadSize)
{
- if (serverResponse == tmp)
+ if(OCParsePayload(&entityHandlerRequest->payload, payloadType,
+ payload, payloadSize) != OC_STACK_OK)
{
- DeleteServerResponse(tmp);
- return;
+ return OC_STACK_ERROR;
}
}
- }
-}
+ else
+ {
+ entityHandlerRequest->payload = NULL;
+ }
-void DeleteServerResponse(OCServerResponse * serverResponse)
-{
- if(serverResponse) {
- LL_DELETE(serverResponseList, serverResponse);
- OCFree(serverResponse->payload);
- OCFree(serverResponse);
- OC_LOG(INFO, TAG, PCF("Server Response Removed!!"));
+ entityHandlerRequest->numRcvdVendorSpecificHeaderOptions = numVendorOptions;
+ entityHandlerRequest->rcvdVendorSpecificHeaderOptions = vendorOptions;
+
+ return OC_STACK_OK;
}
+
+ return OC_STACK_INVALID_PARAM;
}
+/**
+ * Find a server request in the server request list and delete
+ *
+ * @param serverRequest - server request to find and delete
+ */
void FindAndDeleteServerRequest(OCServerRequest * serverRequest)
{
OCServerRequest* tmp;
}
}
-void DeleteServerRequest(OCServerRequest * serverRequest)
+CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result, OCMethod method)
{
- if(serverRequest) {
- LL_DELETE(serverRequestList, serverRequest);
- OCFree(serverRequest);
- serverRequest = NULL;
- OC_LOG(INFO, TAG, PCF("Server Request Removed!!"));
- }
-}
+ CAResponseResult_t caResult;
-OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
-{
- OCStackResult result = OC_STACK_ERROR;
- CARemoteEndpoint_t responseEndpoint = {0};
- CAResponseInfo_t responseInfo = {0};
- CAHeaderOption_t* optionsPointer;
-
- OC_LOG_V(INFO, TAG, "Inside HandleSingleResponse: %s", ehResponse->payload);
-
- OCServerRequest *serverRequest = (OCServerRequest *)ehResponse->requestHandle;
-
- // Copy the address
- responseEndpoint.resourceUri = (CAURI_t) serverRequest->resourceUrl;
- responseEndpoint.addressInfo = serverRequest->addressInfo;
- responseEndpoint.connectivityType = serverRequest->connectivityType;
- responseEndpoint.isSecured = (CABool_t) serverRequest->secured;
-
- // Copy the info
- switch (ehResponse->ehResult)
+ switch (result)
{
case OC_EH_OK:
- responseInfo.result = 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:
- responseInfo.result = CA_BAD_REQ;
+ caResult = CA_BAD_REQ;
break;
case OC_EH_RESOURCE_CREATED:
- responseInfo.result = CA_CREATED;
+ caResult = CA_CREATED;
break;
case OC_EH_RESOURCE_DELETED:
- responseInfo.result = CA_DELETED;
+ caResult = CA_DELETED;
break;
case OC_EH_SLOW:
- responseInfo.result = CA_SUCCESS;
+ caResult = CA_CONTENT;
break;
case OC_EH_FORBIDDEN:
- responseInfo.result = CA_BAD_REQ;
+ caResult = CA_UNAUTHORIZED_REQ;
+ break;
+ case OC_EH_RESOURCE_NOT_FOUND:
+ caResult = CA_NOT_FOUND;
break;
default:
- responseInfo.result = CA_BAD_REQ;
+ caResult = CA_BAD_REQ;
break;
}
+ return caResult;
+}
+
- // TODO-CA: Need to do something with a slow response if a confirmed request was sent
- // from client
+/**
+ * Handler function for sending a response from a single resource
+ *
+ * @param ehResponse - pointer to the response from the resource
+ *
+ * @return
+ * OCStackResult
+ */
+OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
+{
+ OCStackResult result = OC_STACK_ERROR;
+ CAEndpoint_t responseEndpoint = {.adapter = CA_DEFAULT_ADAPTER};
+ CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
+ CAHeaderOption_t* optionsPointer = NULL;
- // TODO-CA: Need to handle CA_MSG_RESET and CA_MSG_ACKNOWLEDGE
- switch (serverRequest->qos)
+ if(!ehResponse || !ehResponse->requestHandle)
{
- case OC_LOW_QOS:
- responseInfo.info.type = CA_MSG_NONCONFIRM;
- break;
- case OC_MEDIUM_QOS:
- responseInfo.info.type = CA_MSG_NONCONFIRM;
- break;
- case OC_HIGH_QOS:
- responseInfo.info.type = CA_MSG_CONFIRM;
- break;
- case OC_NA_QOS:
- responseInfo.info.type = CA_MSG_NONCONFIRM;
- break;
- default:
- responseInfo.info.type = CA_MSG_NONCONFIRM;
- break;
+ OIC_LOG(ERROR, TAG, "ehResponse/requestHandle is NULL");
+ return OC_STACK_ERROR;
}
- responseInfo.info.token = (CAToken_t)OCMalloc(CA_MAX_TOKEN_LEN+1);
- if (!responseInfo.info.token)
+ OCServerRequest *serverRequest = (OCServerRequest *)ehResponse->requestHandle;
+
+ CopyDevAddrToEndpoint(&serverRequest->devAddr, &responseEndpoint);
+
+ responseInfo.info.resourceUri = serverRequest->resourceUrl;
+ responseInfo.result = ConvertEHResultToCAResult(ehResponse->ehResult, serverRequest->method);
+
+ if(serverRequest->notificationFlag && serverRequest->qos == OC_HIGH_QOS)
{
- OC_LOG(FATAL, TAG, "Response Info Token is NULL");
- return result;
+ responseInfo.info.type = CA_MSG_CONFIRM;
}
- memset(responseInfo.info.token, 0, CA_MAX_TOKEN_LEN + 1);
- memcpy(responseInfo.info.token, serverRequest->requestToken, CA_MAX_TOKEN_LEN);
-
- if(serverRequest->observeResult == OC_STACK_OK)
+ else if(serverRequest->notificationFlag && serverRequest->qos != OC_HIGH_QOS)
{
- responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions + 1;
+ responseInfo.info.type = CA_MSG_NONCONFIRM;
+ }
+ else if(!serverRequest->notificationFlag && !serverRequest->slowFlag &&
+ serverRequest->qos == OC_HIGH_QOS)
+ {
+ responseInfo.info.type = CA_MSG_ACKNOWLEDGE;
+ }
+ else if(!serverRequest->notificationFlag && serverRequest->slowFlag &&
+ serverRequest->qos == OC_HIGH_QOS)
+ {
+ responseInfo.info.type = CA_MSG_CONFIRM;
+ }
+ else if(!serverRequest->notificationFlag)
+ {
+ responseInfo.info.type = CA_MSG_NONCONFIRM;
}
else
{
- responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions;
+ OIC_LOG(ERROR, TAG, "default responseInfo type is NON");
+ responseInfo.info.type = CA_MSG_NONCONFIRM;
}
- responseInfo.info.options = (CAHeaderOption_t *)
- malloc(sizeof(CAHeaderOption_t) * responseInfo.info.numOptions);
+ char rspToken[CA_MAX_TOKEN_LEN + 1] = {};
+ responseInfo.info.messageId = serverRequest->coapID;
+ responseInfo.info.token = (CAToken_t)rspToken;
- optionsPointer = responseInfo.info.options;
+ memcpy(responseInfo.info.token, serverRequest->requestToken, serverRequest->tokenLength);
+ responseInfo.info.tokenLength = serverRequest->tokenLength;
if(serverRequest->observeResult == OC_STACK_OK)
{
responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions + 1;
}
+ else
+ {
+ responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions;
+ }
- // TODO-CA Revisit this logic
- if(serverRequest->observeResult == OC_STACK_OK)
+ if(responseInfo.info.numOptions > 0)
{
- 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));
+ responseInfo.info.options = (CAHeaderOption_t *)
+ OICCalloc(responseInfo.info.numOptions,
+ sizeof(CAHeaderOption_t));
- // Point to the next header option before copying vender specific header options
- optionsPointer += 1;
- }
+ if(!responseInfo.info.options)
+ {
+ OIC_LOG(FATAL, TAG, "Memory alloc for options failed");
+ return OC_STACK_NO_MEMORY;
+ }
- if (ehResponse->numSendVendorSpecificHeaderOptions)
+ optionsPointer = responseInfo.info.options;
+
+ // TODO: This exposes CoAP specific details. At some point, this should be
+ // re-factored and handled in the CA layer.
+ if(serverRequest->observeResult == OC_STACK_OK)
+ {
+ responseInfo.info.options[0].protocolID = CA_COAP_ID;
+ responseInfo.info.options[0].optionID = COAP_OPTION_OBSERVE;
+ responseInfo.info.options[0].optionLength = 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;
+ }
+
+ if (ehResponse->numSendVendorSpecificHeaderOptions)
+ {
+ memcpy(optionsPointer, ehResponse->sendVendorSpecificHeaderOptions,
+ sizeof(OCHeaderOption) *
+ ehResponse->numSendVendorSpecificHeaderOptions);
+ }
+ }
+ else
{
- memcpy(optionsPointer, ehResponse->sendVendorSpecificHeaderOptions,
- sizeof(OCHeaderOption) * ehResponse->numSendVendorSpecificHeaderOptions);
+ responseInfo.info.options = NULL;
}
- // Allocate memory for the payload.
- char *payload = (char *)OCMalloc(MAX_RESPONSE_LENGTH);
- if(!payload)
+ 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)
{
- return OC_STACK_NO_MEMORY;
+ if (ehResponse->payload->type == PAYLOAD_TYPE_PRESENCE)
+ {
+ responseInfo.isMulticast = true;
+ }
+ else
+ {
+ responseInfo.isMulticast = false;
+ }
+
+ switch(serverRequest->acceptFormat)
+ {
+ 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;
+ }
}
- memset(payload, 0, MAX_RESPONSE_LENGTH);
- // Put the JSON prefix and suffix around the payload
- strcpy(payload, (const char *)OC_JSON_PREFIX);
- strcat(payload, (const char *)ehResponse->payload);
- strcat(payload, (const char *)OC_JSON_SUFFIX);
- responseInfo.info.payload = (CAPayload_t)payload;
- CAResult_t caResult = CASendResponse(&responseEndpoint, &responseInfo);
- if(caResult != CA_STATUS_OK)
+#ifdef WITH_PRESENCE
+ CATransportAdapter_t CAConnTypes[] = {
+ CA_ADAPTER_IP,
+ CA_ADAPTER_GATT_BTLE,
+ CA_ADAPTER_RFCOMM_BTEDR,
+ CA_ADAPTER_NFC
+#ifdef RA_ADAPTER
+ , CA_ADAPTER_REMOTE_ACCESS
+#endif
+ , CA_ADAPTER_TCP
+ };
+
+ size_t size = sizeof(CAConnTypes)/ sizeof(CATransportAdapter_t);
+
+ CATransportAdapter_t adapter = responseEndpoint.adapter;
+ // Default adapter, try to send response out on all adapters.
+ if (adapter == CA_DEFAULT_ADAPTER)
{
- OC_LOG(ERROR, TAG, PCF("CASendResponse error"));
+ adapter =
+ (CATransportAdapter_t)(
+ CA_ADAPTER_IP |
+ CA_ADAPTER_GATT_BTLE |
+ CA_ADAPTER_RFCOMM_BTEDR |
+ CA_ADAPTER_NFC
+#ifdef RA_ADAP
+ | CA_ADAPTER_REMOTE_ACCESS
+#endif
+ | CA_ADAPTER_TCP
+ );
}
- else
+
+ result = OC_STACK_OK;
+ OCStackResult tempResult = OC_STACK_OK;
+
+ for(size_t i = 0; i < size; i++ )
{
- result = OC_STACK_OK;
+ responseEndpoint.adapter = (CATransportAdapter_t)(adapter & CAConnTypes[i]);
+ if(responseEndpoint.adapter)
+ {
+ //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
+ tempResult = OCSendResponse(&responseEndpoint, &responseInfo);
+ }
+ if(OC_STACK_OK != tempResult)
+ {
+ result = tempResult;
+ }
}
+#else
- OCFree(payload);
+ 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);
+
+ result = OCSendResponse(&responseEndpoint, &responseInfo);
+#endif
+
+ OICFree(responseInfo.info.payload);
+ OICFree(responseInfo.info.options);
//Delete the request
FindAndDeleteServerRequest(serverRequest);
return result;
}
+/**
+ * Handler function for sending a response from multiple resources, such as a collection.
+ * Aggregates responses from multiple resource until all responses are received then sends the
+ * concatenated response
+ *
+ * TODO: Need to add a timeout in case a (remote?) resource does not respond
+ *
+ * @param ehResponse - pointer to the response from the resource
+ *
+ * @return
+ * OCStackResult
+ */
OCStackResult HandleAggregateResponse(OCEntityHandlerResponse * ehResponse)
{
- OCStackResult stackRet = OC_STACK_ERROR;
- OCServerRequest * serverRequest = NULL;
- OCServerResponse * serverResponse = NULL;
+ if(!ehResponse || !ehResponse->payload)
+ {
+ OIC_LOG(ERROR, TAG, "HandleAggregateResponse invalid parameters");
+ return OC_STACK_INVALID_PARAM;
+ }
- OC_LOG_V(INFO, TAG, "Inside HandleAggregateResponse: %s", ehResponse->payload);
+ 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);
- VERIFY_NON_NULL(serverResponse->payload);
}
- if((serverResponse->remainingPayloadSize >= ehResponse->payloadSize + 1 &&
- serverRequest->numResponses == 1) ||
- (serverResponse->remainingPayloadSize >= ehResponse->payloadSize + 2 &&
- serverRequest->numResponses > 1))
+ if(ehResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
{
- OC_LOG(INFO, TAG, PCF("There is room in response buffer"));
- // append
- snprintf((char *)serverResponse->payload, serverResponse->remainingPayloadSize, "%s%s", (char *)serverResponse->payload, (char *)ehResponse->payload);
- OC_LOG_V(INFO, TAG, "Current aggregated response ...%s", serverResponse->payload);
- serverResponse->remainingPayloadSize -= ehResponse->payloadSize;
- (serverRequest->numResponses)--;
- if(serverRequest->numResponses == 0)
- {
- OC_LOG(INFO, TAG, PCF("This is the last response fragment"));
- ehResponse->payload = serverResponse->payload;
- ehResponse->payloadSize = strlen((char *) serverResponse->payload) + 1;
- stackRet = HandleSingleResponse(ehResponse);
- //Delete the request and response
- FindAndDeleteServerRequest(serverRequest);
- FindAndDeleteServerResponse(serverResponse);
- }
- else
- {
- OC_LOG(INFO, TAG, PCF("More response fragment to come"));
- // TODO: we should consider using strcat rather than setting a char by char here!
- snprintf((char *)serverResponse->payload, serverResponse->remainingPayloadSize, "%s%c", (char *)serverResponse->payload,OC_JSON_SEPARATOR);
- OC_LOG_V(INFO, TAG, "Current aggregated response ...%s", serverResponse->payload);
- (serverResponse->remainingPayloadSize)--;
- stackRet = OC_STACK_OK;
- }
+ stackRet = OC_STACK_ERROR;
+ 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 = (OCPayload *)newPayload;
}
else
{
- OC_LOG(INFO, TAG, PCF("No room in response buffer"));
+ OCRepPayloadAppend((OCRepPayload*)serverResponse->payload,
+ (OCRepPayload*)newPayload);
+ }
+
+
+ (serverRequest->numResponses)--;
+
+ if(serverRequest->numResponses == 0)
+ {
+ OIC_LOG(INFO, TAG, "This is the last response fragment");
+ ehResponse->payload = serverResponse->payload;
+ stackRet = HandleSingleResponse(ehResponse);
//Delete the request and response
FindAndDeleteServerRequest(serverRequest);
FindAndDeleteServerResponse(serverResponse);
- stackRet = OC_STACK_NO_MEMORY;
+ }
+ else
+ {
+ OIC_LOG(INFO, TAG, "More response fragments to come");
+ stackRet = OC_STACK_OK;
}
}
exit:
return stackRet;
}
+