//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
+#define _POSIX_C_SOURCE 200112L
+#include <string.h>
+#include <ctype.h>
+
#include "ocstack.h"
#include "ocstackinternal.h"
#include "ocresourcehandler.h"
#include "occlientcb.h"
#include "ocobserve.h"
#include "ocrandom.h"
-#include "debug.h"
-#include "occoap.h"
#include "ocmalloc.h"
#include "ocserverrequest.h"
+#include "ocsecurityinternal.h"
+
+#include "cacommon.h"
+#include "cainterface.h"
+
+#ifdef WITH_ARDUINO
+#include "Time.h"
+#else
+#include <sys/time.h>
+#endif
+#include "coap_time.h"
+#include "utlist.h"
+#include "pdu.h"
+
+#ifndef ARDUINO
+#include <arpa/inet.h>
+#endif
+
//-----------------------------------------------------------------------------
// Typedefs
//-----------------------------------------------------------------------------
typedef enum {
- OC_STACK_UNINITIALIZED = 0, OC_STACK_INITIALIZED
+ OC_STACK_UNINITIALIZED = 0, OC_STACK_INITIALIZED, OC_STACK_UNINIT_IN_PROGRESS
} OCStackState;
-
#ifdef WITH_PRESENCE
typedef enum {
OC_PRESENCE_UNINITIALIZED = 0, OC_PRESENCE_INITIALIZED
OCMode myStackMode;
OCDeviceEntityHandler defaultDeviceHandler;
+OCStackResult getQueryFromUri(const char * uri, unsigned char** resourceType, char ** newURI);
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
#define TAG PCF("OCStack")
+#define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
+ {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
#define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
TAG, PCF(#arg " is NULL")); return (retVal); } }
+#define VERIFY_NON_NULL_V(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
+ goto exit;} }
//TODO: we should allow the server to define this
#define MAX_OBSERVE_AGE (0x2FFFFUL)
-//-----------------------------------------------------------------------------
-// Externs
-//-----------------------------------------------------------------------------
-extern void DeinitOCSecurityInfo();
+
+//=============================================================================
+// Helper Functions
+//=============================================================================
+static uint32_t GetTime(float afterSeconds)
+{
+ coap_tick_t now;
+ coap_ticks(&now);
+ return now + (uint32_t)(afterSeconds * COAP_TICKS_PER_SECOND);
+}
+
+static OCStackResult FormOCResponse(OCResponse * * responseLoc,
+ ClientCB * cbNode,
+ uint32_t maxAge,
+ unsigned char * fullUri,
+ unsigned char * rcvdUri,
+ CAToken_t * rcvdToken,
+ OCClientResponse * clientResponse,
+ unsigned char * bufRes)
+{
+ OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse));
+ if (!response)
+ {
+ return OC_STACK_NO_MEMORY;
+ }
+ response->cbNode = cbNode;
+ response->maxAge = maxAge;
+ response->fullUri = fullUri;
+ response->rcvdUri = rcvdUri;
+ response->rcvdToken = rcvdToken;
+ response->clientResponse = clientResponse;
+ response->bufRes = bufRes;
+
+ *responseLoc = response;
+ return OC_STACK_OK;
+}
+
+/// This method is used to create the IPv4 dev_addr structure.
+/// TODO: Remove in future. Temporary helper function.
+/// Builds a socket interface address using IP address and port number
+static int32_t OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
+ uint16_t port, OCDevAddr *ipAddr)
+{
+ if ( !ipAddr ) {
+ OC_LOG(FATAL, TAG, "Invalid argument");
+ return 1;
+ }
+
+ ipAddr->addr[0] = a;
+ ipAddr->addr[1] = b;
+ ipAddr->addr[2] = c;
+ ipAddr->addr[3] = d;
+ *((uint16_t*)&(ipAddr->addr[4])) = port;
+
+ return 0;
+}
//-----------------------------------------------------------------------------
// Internal API function
// This internal function is called to update the stack with the status of
// observers and communication failures
-OCStackResult OCStackFeedBack(OCCoAPToken * token, uint8_t status)
+OCStackResult OCStackFeedBack(CAToken_t * token, uint8_t status)
{
OCStackResult result = OC_STACK_ERROR;
ResourceObserver * observer = NULL;
//observer is still interested
OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
notifications, reset the failedCount"));
- observer = GetObserverUsingToken(token);
+ observer = GetObserverUsingToken (token);
if(observer)
{
observer->forceHighQos = 0;
case OC_OBSERVER_FAILED_COMM:
//observer is not reachable
OC_LOG(DEBUG, TAG, PCF("observer is unreachable"));
- observer = GetObserverUsingToken(token);
+ observer = GetObserverUsingToken (token);
if(observer)
{
if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
return result;
}
+OCStackResult CAToOCStackResult(CAResponseResult_t caCode)
+{
+ OCStackResult ret = OC_STACK_ERROR;
+
+ switch(caCode)
+ {
+ case CA_SUCCESS:
+ ret = OC_STACK_OK;
+ break;
+ case CA_CREATED:
+ ret = OC_STACK_RESOURCE_CREATED;
+ break;
+ case CA_DELETED:
+ ret = OC_STACK_RESOURCE_DELETED;
+ break;
+ case CA_BAD_REQ:
+ ret = OC_STACK_INVALID_QUERY;
+ break;
+ case CA_BAD_OPT:
+ ret = OC_STACK_INVALID_OPTION;
+ break;
+ case CA_NOT_FOUND:
+ ret = OC_STACK_NO_RESOURCE;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+OCStackResult OCToCAConnectivityType(OCConnectivityType ocConType, CAConnectivityType_t* caConType)
+{
+ OCStackResult ret = OC_STACK_OK;
+
+ switch(ocConType)
+ {
+ case OC_ETHERNET:
+ *caConType = CA_ETHERNET;
+ break;
+ case OC_WIFI:
+ *caConType = CA_WIFI;
+ break;
+ case OC_EDR:
+ *caConType = CA_EDR;
+ break;
+ case OC_LE:
+ *caConType = CA_LE;
+ break;
+ case OC_ALL:
+ // Currently OC_ALL represents WIFI and ETHERNET
+ // Add other connectivity types as they are enabled in future
+ *caConType = (CAConnectivityType_t) (CA_WIFI|CA_ETHERNET);
+ break;
+ default:
+ ret = OC_STACK_INVALID_PARAM;
+ break;
+ }
+ return ret;
+}
+
+OCStackResult CAToOCConnectivityType(CAConnectivityType_t caConType, OCConnectivityType *ocConType)
+{
+ OCStackResult ret = OC_STACK_OK;
+
+ switch(caConType)
+ {
+ case CA_ETHERNET:
+ *ocConType = OC_ETHERNET;
+ break;
+ case CA_WIFI:
+ *ocConType = OC_WIFI;
+ break;
+ case CA_EDR:
+ *ocConType = OC_EDR;
+ break;
+ case CA_LE:
+ *ocConType = OC_LE;
+ break;
+ default:
+ ret = OC_STACK_INVALID_PARAM;
+ break;
+ }
+ return ret;
+}
+
+// update response.addr appropriately from endPoint.addressInfo
+OCStackResult UpdateResponseAddr(OCClientResponse *response, const CARemoteEndpoint_t* endPoint)
+{
+ OCStackResult ret = OC_STACK_ERROR;
+ static OCDevAddr address = {0};
+ char * tok = NULL;
+ char * savePtr = NULL;
+ char * cpAddress = (char *) OCMalloc(strlen(endPoint->addressInfo.IP.ipAddress) + 1);
+ if(!cpAddress)
+ {
+ ret = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ memcpy(cpAddress, endPoint->addressInfo.IP.ipAddress,
+ strlen(endPoint->addressInfo.IP.ipAddress) + 1);
+
+ // Grabs the first three numbers from the IPv4 address and replaces dots
+ for(int i=0; i<4; i++)
+ {
+ tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
+
+ if(!tok)
+ {
+ ret = OC_STACK_ERROR;
+ goto exit;
+ }
+ address.addr[i] = atoi(tok);
+ }
+
+ memcpy(&address.addr[4], &endPoint->addressInfo.IP.port, sizeof(uint32_t));
+
+ if(response)
+ {
+ response->addr = &address;
+ ret = CAToOCConnectivityType(endPoint->connectivityType, &(response->connType));
+ }
+ else
+ {
+ OC_LOG(ERROR, TAG, PCF("OCClientResponse is NULL!"));
+ }
+exit:
+ OCFree(cpAddress);
+ return ret;
+}
+
+void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType)
+{
+ char * tok = NULL;
+ char * savePtr;
+ // The format of the payload is {"oc":[%u:%u:%s]}
+ // %u : sequence number,
+ // %u : max age
+ // %s : Resource Type (Optional)
+ tok = strtok_r(payload, "[:]}", &savePtr);
+ payload[strlen(payload)] = ':';
+ tok = strtok_r(NULL, "[:]}", &savePtr);
+ payload[strlen((char *)payload)] = ':';
+ *seqNum = (uint32_t) atoi(tok);
+ tok = strtok_r(NULL, "[:]}", &savePtr);
+ *maxAge = (uint32_t) atoi(tok);
+ tok = strtok_r(NULL, "[:]}",&savePtr);
+
+ if(tok)
+ {
+ *resType = (char *)OCMalloc(strlen(tok));
+ if(!*resType)
+ {
+ return;
+ }
+ payload[strlen((char *)payload)] = ':';
+ strcpy(*resType, tok);
+ OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s", *resType);
+ }
+ payload[strlen((char *)payload)] = ']';
+}
+
+OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
+ const CAResponseInfo_t* responseInfo)
+{
+ OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
+ ClientCB * cbNode = NULL;
+ char *resourceTypeName = NULL;
+ OCClientResponse response;
+ OCStackResult result = OC_STACK_ERROR;
+ uint32_t lowerBound = 0;
+ uint32_t higherBound = 0;
+ uint32_t maxAge = 0;
+
+ char *fullUri = NULL;
+ char *ipAddress = NULL;
+ int presenceSubscribe = 0;
+ int multicastPresenceSubscribe = 0;
+
+ if (responseInfo->result != CA_SUCCESS)
+ {
+ OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result);
+ return OC_STACK_ERROR;
+ }
+
+ fullUri = (char *) OCMalloc(MAX_URI_LENGTH );
+
+ if(NULL == fullUri)
+ {
+ OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for fullUri"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+
+ ipAddress = (char *) OCMalloc(strlen(endPoint->addressInfo.IP.ipAddress) + 1);
+
+ if(NULL == ipAddress)
+ {
+ OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for ipAddress"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+
+ strncpy(ipAddress, endPoint->addressInfo.IP.ipAddress,
+ strlen(endPoint->addressInfo.IP.ipAddress));
+ ipAddress[strlen(endPoint->addressInfo.IP.ipAddress)] = '\0';
+
+ snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", ipAddress, endPoint->addressInfo.IP.port,
+ OC_PRESENCE_URI);
+
+ cbNode = GetClientCB(NULL, NULL, (unsigned char *) fullUri);
+
+ if(cbNode)
+ {
+ presenceSubscribe = 1;
+ }
+ else
+ {
+ snprintf(fullUri, MAX_URI_LENGTH, "%s%s", OC_MULTICAST_IP, endPoint->resourceUri);
+ cbNode = GetClientCB(NULL, NULL, (unsigned char *) fullUri);
+ if(cbNode)
+ {
+ multicastPresenceSubscribe = 1;
+ }
+ }
+
+ if(!presenceSubscribe && !multicastPresenceSubscribe)
+ {
+ OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
+ ------------ ignoring"));
+ goto exit;
+ }
+
+ // No payload to the application in case of presence
+ response.resJSONPayload = NULL;
+ response.result = OC_STACK_OK;
+
+ result = UpdateResponseAddr(&response, endPoint);
+ if(result != OC_STACK_OK)
+ {
+ goto exit;
+ }
+
+ if(responseInfo->info.payload)
+ {
+ parsePresencePayload(responseInfo->info.payload,
+ &(response.sequenceNumber),
+ &maxAge,
+ &resourceTypeName);
+ }
+
+ if(maxAge == 0)
+ {
+ OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
+ response.result = OC_STACK_PRESENCE_STOPPED;
+ if(cbNode->presence)
+ {
+ OCFree(cbNode->presence->timeOut);
+ OCFree(cbNode->presence);
+ cbNode->presence = NULL;
+ }
+ }
+ else if(presenceSubscribe)
+ {
+ if(!cbNode->presence)
+ {
+ cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
+ VERIFY_NON_NULL_V(cbNode->presence);
+ cbNode->presence->timeOut = NULL;
+ cbNode->presence->timeOut = (uint32_t *)
+ OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
+ if(!(cbNode->presence->timeOut)){
+ OCFree(cbNode->presence);
+ result = OC_STACK_NO_MEMORY;
+ }
+ }
+
+ OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %u", GetTime(0));
+ cbNode->presence->TTL = maxAge;
+ for(int index = 0; index < PresenceTimeOutSize; index++)
+ {
+ lowerBound = GetTime(((float)(PresenceTimeOut[index])
+ /(float)100)*(float)cbNode->presence->TTL);
+ higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
+ /(float)100)*(float)cbNode->presence->TTL);
+ cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
+ OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout %d", lowerBound);
+ OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
+ OC_LOG_V(DEBUG, TAG, "----------------timeOut entry %d",
+ cbNode->presence->timeOut[index]);
+ }
+ cbNode->presence->TTLlevel = 0;
+ OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
+ if(cbNode->sequenceNumber == response.sequenceNumber)
+ {
+ OC_LOG(INFO, TAG, PCF("===============No presence change"));
+ goto exit;
+ }
+ OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack"));
+ cbNode->sequenceNumber = response.sequenceNumber;
+
+ // Ensure that a filter is actually applied.
+ if(resourceTypeName && cbNode->filterResourceType)
+ {
+ if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
+ {
+ goto exit;
+ }
+ }
+ }
+ else
+ {
+ // This is the multicast case
+
+ OCMulticastNode* mcNode = NULL;
+ mcNode = GetMCPresenceNode((const unsigned char *)fullUri);
+
+ if(mcNode != NULL)
+ {
+ if(mcNode->nonce == response.sequenceNumber)
+ {
+ OC_LOG(INFO, TAG, PCF("===============No presence change (Multicast)"));
+ goto exit;
+ }
+ mcNode->nonce = response.sequenceNumber;
+ }
+ else
+ {
+ uint32_t uriLen = strlen((char*)fullUri);
+ unsigned char* uri = (unsigned char *) OCMalloc(uriLen + 1);
+ if(uri)
+ {
+ memcpy(uri, fullUri, (uriLen + 1));
+ }
+ else
+ {
+ OC_LOG(INFO, TAG,
+ PCF("===============No Memory for URI to store in the presence node"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ result = AddMCPresenceNode(&mcNode, (unsigned char*) uri, response.sequenceNumber);
+ if(result == OC_STACK_NO_MEMORY)
+ {
+ OC_LOG(INFO, TAG,
+ PCF("===============No Memory for Multicast Presence Node"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ }
+
+ // Ensure that a filter is actually applied.
+ if(resourceTypeName && cbNode->filterResourceType)
+ {
+ if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
+ {
+ goto exit;
+ }
+ }
+ }
+
+ cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &response);
+
+ if (cbResult == OC_STACK_DELETE_TRANSACTION)
+ {
+ FindAndDeleteClientCB(cbNode);
+ }
+
+exit:
+OCFree(fullUri);
+OCFree(ipAddress);
+OCFree(resourceTypeName);
+return result;
+}
+
+
+//This function will be called back by CA layer when a response is received
+void HandleCAResponses(const CARemoteEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo)
+{
+ OC_LOG(INFO, TAG, PCF("Enter HandleCAResponses"));
+
+ OCStackApplicationResult appResult = OC_STACK_DELETE_TRANSACTION;
+
+ if(NULL == endPoint)
+ {
+ OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
+ return;
+ }
+
+ if(NULL == responseInfo)
+ {
+ OC_LOG(ERROR, TAG, PCF("responseInfo is NULL"));
+ return;
+ }
+
+ if(strcmp(endPoint->resourceUri, OC_PRESENCE_URI) == 0)
+ {
+ HandlePresenceResponse(endPoint, responseInfo);
+ return;
+ }
+
+ ClientCB *cbNode = GetClientCB((CAToken_t *)&(responseInfo->info.token), NULL, NULL);
+
+ if (cbNode)
+ {
+ OC_LOG(INFO, TAG, PCF("Calling into application address space"));
+ OCClientResponse response;
+
+ OCStackResult result = UpdateResponseAddr(&response, endPoint);
+ if(result != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
+ return;
+ }
+
+ response.result = CAToOCStackResult(responseInfo->result);
+ response.resJSONPayload = (unsigned char*)responseInfo->info.payload;
+ response.numRcvdVendorSpecificHeaderOptions = 0;
+ if(responseInfo->info.numOptions > 0)
+ {
+ int start = 0;
+ //First option always with option ID is OC_COAP_OPTION_OBSERVE if it is available.
+ if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE)
+ {
+ memcpy (&(response.sequenceNumber),
+ &(responseInfo->info.options[0].optionData), sizeof(uint32_t));
+ response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions - 1;
+ start = 1;
+ }
+ else
+ {
+ response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions;
+ }
+
+ if(response.numRcvdVendorSpecificHeaderOptions > MAX_HEADER_OPTIONS)
+ {
+ OC_LOG(ERROR, TAG, PCF("#header options are more than MAX_HEADER_OPTIONS"));
+ return;
+ }
+
+ for (uint8_t i = start; i < responseInfo->info.numOptions; i++)
+ {
+ memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]),
+ &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
+ }
+ }
+ appResult = cbNode->callBack(cbNode->context,
+ cbNode->handle, &response);
+ if (appResult == OC_STACK_DELETE_TRANSACTION)
+ {
+ FindAndDeleteClientCB(cbNode);
+ }
+ }
+ OC_LOG_V(INFO, TAG, PCF("Received payload: %s\n"), (char*)responseInfo->info.payload);
+ OC_LOG(INFO, TAG, PCF("Exit HandleCAResponses"));
+}
+
+//This function will be called back by CA layer when a request is received
+void HandleCARequests(const CARemoteEndpoint_t* endPoint, const CARequestInfo_t* requestInfo)
+{
+ OC_LOG(INFO, TAG, PCF("Enter HandleCARequests"));
+ if(!endPoint)
+ {
+ OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
+ return;
+ }
+
+ if(!requestInfo)
+ {
+ OC_LOG(ERROR, TAG, PCF("requestInfo is NULL"));
+ return;
+ }
+
+ OCStackResult requestResult = OC_STACK_ERROR;
+
+ if(myStackMode == OC_CLIENT)
+ {
+ //TODO: should the client be responding to requests?
+ return;
+ }
+
+ OCServerProtocolRequest serverRequest = {};
+
+ OC_LOG_V(INFO, TAG, PCF("***** Endpoint URI ***** : %s\n"), (char*)endPoint->resourceUri);
+
+ char * newUri = (char *)endPoint->resourceUri;
+ unsigned char * query = NULL;
+ getQueryFromUri(endPoint->resourceUri, &query, &newUri);
+ OC_LOG_V(INFO, TAG, PCF("**********URI without query ****: %s\n"), newUri);
+ OC_LOG_V(INFO, TAG, PCF("**********Query ****: %s\n"), query);
+ if(strlen(newUri) < MAX_URI_LENGTH)
+ {
+ //copy URI
+ memcpy (&(serverRequest.resourceUrl), newUri, strlen(newUri));
+ }
+ else
+ {
+ OC_LOG(ERROR, TAG, PCF("URI length exceeds MAX_URI_LENGTH."));
+ return;
+ }
+ //copy query
+ if(query)
+ {
+ if(strlen((char*)query) < MAX_QUERY_LENGTH)
+ {
+ memcpy (&(serverRequest.query), query, strlen((char*)query));
+ }
+ else
+ {
+ OC_LOG(ERROR, TAG, PCF("Query length exceeds MAX_QUERY_LENGTH."));
+ return;
+ }
+ }
+ //copy request payload
+ if (requestInfo->info.payload)
+ {
+ serverRequest.reqTotalSize = strlen(requestInfo->info.payload) + 1;
+ memcpy (&(serverRequest.reqJSONPayload), requestInfo->info.payload,
+ strlen(requestInfo->info.payload));
+ serverRequest.reqTotalSize = strlen((const char *)requestInfo->info.payload) + 1;
+ }
+ else
+ {
+ serverRequest.reqTotalSize = 1;
+ }
+
+ switch (requestInfo->method)
+ {
+ case CA_GET:
+ {
+ serverRequest.method = OC_REST_GET;
+ break;
+ }
+ case CA_PUT:
+ {
+ serverRequest.method = OC_REST_PUT;
+ break;
+ }
+ case CA_POST:
+ {
+ serverRequest.method = OC_REST_POST;
+ break;
+ }
+ case CA_DELETE:
+ {
+ serverRequest.method = OC_REST_DELETE;
+ break;
+ }
+ default:
+ {
+ OC_LOG(ERROR, TAG, PCF("Received CA method %d not supported"));
+ return;
+ }
+ }
+
+ OC_LOG_V(INFO, TAG, "HandleCARequests: CA token length = %d", CA_MAX_TOKEN_LEN);
+ OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token, CA_MAX_TOKEN_LEN);
+
+ serverRequest.requestToken = (CAToken_t)OCCalloc(1, CA_MAX_TOKEN_LEN+1);
+ // Module Name
+ if (!serverRequest.requestToken)
+ {
+ OC_LOG(FATAL, TAG, "Server Request Token is NULL");
+ return;
+ }
+ memcpy(serverRequest.requestToken, requestInfo->info.token, CA_MAX_TOKEN_LEN);
+
+ if (requestInfo->info.type == CA_MSG_CONFIRM)
+ {
+ serverRequest.qos = OC_HIGH_QOS;
+ }
+ else if (requestInfo->info.type == CA_MSG_NONCONFIRM)
+ {
+ serverRequest.qos = OC_LOW_QOS;
+ }
+ else if (requestInfo->info.type == CA_MSG_ACKNOWLEDGE)
+ {
+ // TODO-CA: Need to handle this
+ }
+ else if (requestInfo->info.type == CA_MSG_RESET)
+ {
+ // TODO-CA: Need to handle this
+ }
+ // CA does not need the following 3 fields
+ serverRequest.coapID = 0;
+ serverRequest.delayedResNeeded = 0;
+ serverRequest.secured = endPoint->isSecured;
+
+ // copy the address
+ serverRequest.addressInfo = endPoint->addressInfo;
+ serverRequest.connectivityType = endPoint->connectivityType;
+
+ // copy vendor specific header options
+ // TODO-CA: CA is including non-vendor header options as well, like observe.
+ // Need to filter those out
+ uint8_t tempNum = (requestInfo->info.numOptions);
+ GetObserveHeaderOption(&serverRequest.observationOption, requestInfo->info.options, &tempNum);
+ if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS)
+ {
+ OC_LOG(ERROR, TAG,
+ PCF("The request info numOptions is greater than MAX_HEADER_OPTIONS"));
+ OCFree(serverRequest.requestToken);
+ return;
+ }
+ serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
+ if (serverRequest.numRcvdVendorSpecificHeaderOptions)
+ {
+ memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
+ sizeof(CAHeaderOption_t)*tempNum);
+ }
+
+ requestResult = HandleStackRequests (&serverRequest);
+ if(requestResult != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("HandleStackRequests failed"));
+ }
+ OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
+}
+
//This function will be called back by occoap layer when a request is received
OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
{
OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
-
OCStackResult result = OC_STACK_ERROR;
ResourceHandling resHandling;
OCResource *resource;
+ if(!protocolRequest)
+ {
+ OC_LOG(ERROR, TAG, PCF("protocolRequest is NULL"));
+ return OC_STACK_INVALID_PARAM;
+ }
OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken);
if(!request)
protocolRequest->observationOption, protocolRequest->qos,
protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
protocolRequest->reqJSONPayload, &protocolRequest->requestToken,
- &protocolRequest->requesterAddr, protocolRequest->resourceUrl,
- protocolRequest->reqTotalSize);
+ protocolRequest->resourceUrl,protocolRequest->reqTotalSize,
+ &protocolRequest->addressInfo, protocolRequest->connectivityType);
if (OC_STACK_OK != result)
{
OC_LOG(ERROR, TAG, PCF("Error adding server request"));
}
//This function will be called back by occoap layer when a response is received
-void HandleStackResponses(OCResponse * response)
+OCStackResult HandleStackResponses(OCResponse * response)
{
- OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION;
OC_LOG(INFO, TAG, PCF("Entering HandleStackResponses (OCStack Layer)"));
+ OCStackResult result = OC_STACK_OK;
+ OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
+ uint8_t isObserveNotification = 0;
+ ClientCB * cbNode = NULL;
+ if(!response)
+ {
+ OC_LOG(ERROR, TAG, PCF("response is NULL"));
+ return OC_STACK_INVALID_PARAM;
+ }
+#ifdef WITH_PRESENCE
+ uint8_t isPresenceNotification = 0;
+ uint8_t isMulticastPresence = 0;
+ char * resourceTypeName = NULL;
+ uint32_t lowerBound = 0;
+ uint32_t higherBound = 0;
+ char * tok = NULL;
+ unsigned char * bufRes = response->bufRes;
+#endif // WITH_PRESENCE
- if (response->cbNode)
+ cbNode = response->cbNode;
+ if(!cbNode)
{
- OC_LOG(INFO, TAG, PCF("Calling into application address space"));
- result = response->cbNode->callBack(response->cbNode->context,
- response->cbNode->handle, response->clientResponse);
- if (result == OC_STACK_DELETE_TRANSACTION ||
+ cbNode = GetClientCB(response->rcvdToken, NULL, NULL);
+ }
+
+ if(response->clientResponse->sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER)
+ {
+ isObserveNotification = 1;
+ OC_LOG(INFO, TAG, PCF("Received an observe notification"));
+ }
+
+ OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u",
+ response->clientResponse->sequenceNumber);
+ OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", response->maxAge);
+ OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
+
+#ifdef WITH_PRESENCE
+ if(!strcmp((char *)response->rcvdUri, (char *)OC_PRESENCE_URI)){
+ isPresenceNotification = 1;
+ if(!bufRes)
+ {
+ result = OC_STACK_INVALID_PARAM;
+ goto exit;
+ }
+ char * savePtr;
+ tok = strtok_r((char *)bufRes, "[:]}", &savePtr);
+ bufRes[strlen((char *)bufRes)] = ':';
+ tok = strtok_r(NULL, "[:]}", &savePtr);
+ bufRes[strlen((char *)bufRes)] = ':';
+ response->clientResponse->sequenceNumber = (uint32_t )atoi(tok);
+ OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", response->clientResponse->sequenceNumber);
+ tok = strtok_r(NULL, "[:]}", &savePtr);
+ response->maxAge = (uint32_t )atoi(tok);
+ OC_LOG_V(DEBUG, TAG, "The received TTL is %u", response->maxAge);
+ tok = strtok_r(NULL, "[:]}", &savePtr);
+ if(tok)
+ {
+ resourceTypeName = (char *)OCMalloc(strlen(tok));
+ if(!resourceTypeName)
+ {
+ goto exit;
+ }
+ bufRes[strlen((char *)bufRes)] = ':';
+ strcpy(resourceTypeName, tok);
+ OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s",
+ resourceTypeName);
+ }
+ bufRes[strlen((char *)bufRes)] = ']';
+ }
+
+ // Check if the application subcribed for presence
+ if(!cbNode)
+ {
+ cbNode = GetClientCB(NULL, NULL, response->fullUri);
+ }
+
+ // Check if application subscribed for multicast presence
+ if(!cbNode)
+ {
+ snprintf((char *)response->fullUri, MAX_URI_LENGTH, "%s%s",
+ OC_MULTICAST_IP, response->rcvdUri);
+ cbNode = GetClientCB(NULL, NULL, response->fullUri);
+ if(cbNode)
+ {
+ isMulticastPresence = 1;
+ isPresenceNotification = 0;
+ }
+ }
+
+ if(cbNode && isPresenceNotification)
+ {
+ OC_LOG(INFO, TAG, PCF("Received a presence notification"));
+ if(!cbNode->presence)
+ {
+ cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
+ VERIFY_NON_NULL_V(cbNode->presence);
+ cbNode->presence->timeOut = NULL;
+ cbNode->presence->timeOut = (uint32_t *)
+ OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
+ if(!(cbNode->presence->timeOut)){
+ OCFree(cbNode->presence);
+ result = OC_STACK_NO_MEMORY;
+ }
+ }
+ if(response->maxAge == 0)
+ {
+ OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
+ response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
+ if(cbNode->presence)
+ {
+ OCFree(cbNode->presence->timeOut);
+ OCFree(cbNode->presence);
+ cbNode->presence = NULL;
+ }
+ }
+ else
+ {
+ OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %d", GetTime(0));
+ cbNode->presence->TTL = response->maxAge;
+ for(int index = 0; index < PresenceTimeOutSize; index++)
+ {
+ lowerBound = GetTime(((float)(PresenceTimeOut[index])
+ /(float)100)*(float)cbNode->presence->TTL);
+ higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
+ /(float)100)*(float)cbNode->presence->TTL);
+ cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
+ OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout %d", lowerBound);
+ OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
+ OC_LOG_V(DEBUG, TAG, "----------------timeOut entry %d",
+ cbNode->presence->timeOut[index]);
+ }
+ cbNode->presence->TTLlevel = 0;
+ OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
+ if(cbNode->sequenceNumber == response->clientResponse->sequenceNumber)
+ {
+ OC_LOG(INFO, TAG, PCF("===============No presence change"));
+ goto exit;
+ }
+ OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack"));
+ cbNode->sequenceNumber = response->clientResponse->sequenceNumber;;
+ }
+
+ // Ensure that a filter is actually applied.
+ if(resourceTypeName && cbNode->filterResourceType)
+ {
+ if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
+ {
+ goto exit;
+ }
+ }
+ }
+ else if(cbNode && isMulticastPresence)
+ {
+ // Check if the same nonce for a given host
+ OCMulticastNode* mcNode = NULL;
+ mcNode = GetMCPresenceNode(response->fullUri);
+
+ if(response->maxAge == 0)
+ {
+ OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
+ response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
+ if(cbNode->presence)
+ {
+ OCFree(cbNode->presence->timeOut);
+ OCFree(cbNode->presence);
+ cbNode->presence = NULL;
+ }
+ }
+ else if(mcNode != NULL)
+ {
+ if(mcNode->nonce == response->clientResponse->sequenceNumber)
+ {
+ OC_LOG(INFO, TAG, PCF("===============No presence change (Multicast)"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ mcNode->nonce = response->clientResponse->sequenceNumber;
+ }
+ else
+ {
+ uint32_t uriLen = strlen((char*)response->fullUri);
+ unsigned char* uri = (unsigned char *) OCMalloc(uriLen + 1);
+ if(uri)
+ {
+ memcpy(uri, response->fullUri, (uriLen + 1));
+ }
+ else
+ {
+ OC_LOG(INFO, TAG,
+ PCF("===============No Memory for URI to store in the presence node"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ result = AddMCPresenceNode(&mcNode, (unsigned char*) uri,
+ response->clientResponse->sequenceNumber);
+ if(result == OC_STACK_NO_MEMORY)
+ {
+ OC_LOG(INFO, TAG,
+ PCF("===============No Memory for Multicast Presence Node"));
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ }
+
+ // Ensure that a filter is actually applied.
+ if(resourceTypeName && cbNode->filterResourceType)
+ {
+ if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
+ {
+ goto exit;
+ }
+ }
+ }
+
+ else if(!cbNode && isPresenceNotification)
+ {
+ OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
+ ------------ ignoring"));
+ }
+ #endif // WITH_PRESENCE
+
+ if(cbNode)
+ {
+ if(isObserveNotification)
+ {
+ OC_LOG(INFO, TAG, PCF("Received an observe notification"));
+ //TODO: check the standard for methods to detect wrap around condition
+ if(cbNode->method == OC_REST_OBSERVE &&
+ (response->clientResponse->sequenceNumber <= cbNode->sequenceNumber ||
+ (response->clientResponse->sequenceNumber > cbNode->sequenceNumber &&
+ response->clientResponse->sequenceNumber ==
+ MAX_SEQUENCE_NUMBER)))
+ {
+ OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
+ Ignoring Incoming:%d Against Current:%d.",
+ response->clientResponse->sequenceNumber, cbNode->sequenceNumber);
+ goto exit;
+ }
+ if(response->clientResponse->sequenceNumber > cbNode->sequenceNumber){
+ cbNode->sequenceNumber = response->clientResponse->sequenceNumber;
+ }
+ }
+
+ response->clientResponse->resJSONPayload = bufRes;
+
+ cbResult = cbNode->callBack(cbNode->context, cbNode->handle, response->clientResponse);
+
+ if (cbResult == OC_STACK_DELETE_TRANSACTION ||
response->clientResponse->result == OC_STACK_COMM_ERROR ||
- response->clientResponse->result == OC_STACK_RESOURCE_DELETED)
+ (response->clientResponse->result == OC_STACK_RESOURCE_DELETED &&
+ !isPresenceNotification && !isMulticastPresence))
{
- FindAndDeleteClientCB(response->cbNode);
+ FindAndDeleteClientCB(cbNode);
}
}
+ else
+ {
+ result = OC_STACK_ERROR;
+ }
+
+ exit:
+ #ifdef WITH_PRESENCE
+ OCFree(resourceTypeName);
+ #endif
+ return result;
}
int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
static OCStackResult verifyUriQueryLength(const char * inputUri,
uint16_t uriLen);
static uint8_t OCIsPacketTransferRequired(const char *request, const char *response, uint16_t size);
-OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI);
+OCStackResult getResourceType(const char * query, unsigned char** resourceType);
//-----------------------------------------------------------------------------
// Public APIs
OCStackResult result = OC_STACK_ERROR;
OC_LOG(INFO, TAG, PCF("Entering OCInit"));
+ // Validate mode
+ if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
+ {
+ OC_LOG(ERROR, TAG, PCF("Invalid mode"));
+ return OC_STACK_ERROR;
+ }
+
if (ipAddr)
{
OC_LOG_V(INFO, TAG, "IP Address = %s", ipAddr);
}
- switch (mode)
+ OCSeedRandom();
+ CAInitialize();
+ //It is ok to select network to CA_WIFI for now
+#ifdef WITH_ARDUINO
+ CAResult_t caResult = CASelectNetwork(CA_ETHERNET);
+#else
+ CAResult_t caResult = CASelectNetwork(CA_WIFI|CA_ETHERNET);
+#endif
+ if(caResult == CA_STATUS_OK)
{
- case OC_CLIENT:
- OC_LOG(INFO, TAG, PCF("Client mode"));
- break;
- case OC_SERVER:
- OC_LOG(INFO, TAG, PCF("Server mode"));
- break;
- case OC_CLIENT_SERVER:
- OC_LOG(INFO, TAG, PCF("Client-server mode"));
- break;
- default:
- OC_LOG(ERROR, TAG, PCF("Invalid mode"));
- return OC_STACK_ERROR;
- break;
+ OC_LOG(INFO, TAG, PCF("CASelectNetwork to WIFI"));
+ CARegisterHandler(HandleCARequests, HandleCAResponses);
+ {
+ OC_LOG(INFO, TAG, PCF("CARegisterHandler..."));
+ stackState = OC_STACK_INITIALIZED;
+ result = OC_STACK_OK;
+ switch (mode)
+ {
+ case OC_CLIENT:
+ caResult = CAStartDiscoveryServer();
+ OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
+ break;
+ case OC_SERVER:
+ caResult = CAStartListeningServer();
+ OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
+ break;
+ case OC_CLIENT_SERVER:
+ caResult = CAStartListeningServer();
+ if(caResult == CA_STATUS_OK)
+ {
+ caResult = CAStartDiscoveryServer();
+ }
+ OC_LOG(INFO, TAG, PCF("Client-server mode"));
+ break;
+ default:
+ OC_LOG(ERROR, TAG, PCF("Invalid mode"));
+ return OC_STACK_ERROR;
+ break;
+ }
+
+ }
+ if (caResult == CA_STATUS_OK)
+ {
+ result = OC_STACK_OK;
+ }
+ else
+ {
+ result = OC_STACK_ERROR;
+ }
}
- myStackMode = mode;
+ myStackMode = mode;
defaultDeviceHandler = NULL;
+#if defined(__WITH_DTLS__)
+ caResult = CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials);
+ result = (caResult == CA_STATUS_OK) ? OC_STACK_OK : OC_STACK_ERROR;
+#endif // (__WITH_DTLS__)
+
#ifdef WITH_PRESENCE
PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
#endif // WITH_PRESENCE
- // Make call to OCCoAP layer
- result = OCInitCoAP(ipAddr, (uint16_t) port, myStackMode);
if (result == OC_STACK_OK)
{
stackState = OC_STACK_INITIALIZED;
OC_LOG(INFO, TAG, PCF("Entering OCStop"));
- if (stackState != OC_STACK_INITIALIZED)
+ if (stackState == OC_STACK_UNINIT_IN_PROGRESS)
+ {
+ OC_LOG(DEBUG, TAG, PCF("Stack already stopping, exiting"));
+ return OC_STACK_OK;
+ }
+ else if (stackState != OC_STACK_INITIALIZED)
{
OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
return OC_STACK_ERROR;
}
+ stackState = OC_STACK_UNINIT_IN_PROGRESS;
+
#ifdef WITH_PRESENCE
// Ensure that the TTL associated with ANY and ALL presence notifications originating from
// here send with the code "OC_STACK_PRESENCE_STOPPED" result.
// Free memory dynamically allocated for resources
deleteAllResources();
+ DeleteDeviceInfo();
+ CATerminate();
+ //CATerminate does not return any error code. It is OK to assign result to OC_STACK_OK.
+ result = OC_STACK_OK;
- // Make call to OCCoAP layer
- if (OCStopCoAP() == OC_STACK_OK)
+ if (result == OC_STACK_OK)
{
// Remove all observers
DeleteObserverList();
stackState = OC_STACK_UNINITIALIZED;
result = OC_STACK_OK;
} else {
+ stackState = OC_STACK_INITIALIZED;
result = OC_STACK_ERROR;
}
}
/**
+ * Map OCQualityOfService to CAMessageType
+ *
+ * @param OCQualityOfService - Input qos.
+ *
+ * Returns CA message type for a given qos.
+ */
+CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos)
+{
+ switch (qos)
+ {
+ case OC_HIGH_QOS:
+ return CA_MSG_CONFIRM;
+ case OC_LOW_QOS:
+ case OC_MEDIUM_QOS:
+ case OC_NA_QOS:
+ default:
+ return CA_MSG_NONCONFIRM;
+ }
+}
+
+/**
* Verify the lengths of the URI and the query separately
*
* @param inputUri - Input URI and query.
}
/**
- * Discover or Perform requests on a specified resource (specified by that Resource's respective URI).
+ * Discover or Perform requests on a specified resource
+ * (specified by that Resource's respective URI).
*
- * @param handle - @ref OCDoHandle to refer to the request sent out on behalf of calling this API.
+ * @param handle - @ref OCDoHandle to refer to the request sent out on behalf of
+ * calling this API.
* @param method - @ref OCMethod to perform on the resource
* @param requiredUri - URI of the resource to interact with
* @param referenceUri - URI of the reference resource
* OC_STACK_INVALID_CALLBACK - invalid callback function pointer
* OC_STACK_INVALID_METHOD - invalid resource method
* OC_STACK_INVALID_URI - invalid required or reference URI
+ *
+ * Note: IN case of CA, when using multicast, the required URI should not contain IP address.
+ * Instead, it just contains the URI to the resource such as "/oc/core".
*/
-
OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
- const char *referenceUri, const char *request,
- OCQualityOfService qos, OCCallbackData *cbData,
- OCHeaderOption * options, uint8_t numOptions)
+ const char *referenceUri, const char *request, OCConnectivityType conType,
+ OCQualityOfService qos, OCCallbackData *cbData,
+ OCHeaderOption * options, uint8_t numOptions)
{
OCStackResult result = OC_STACK_ERROR;
- OCCoAPToken token;
ClientCB *clientCB = NULL;
unsigned char * requestUri = NULL;
unsigned char * resourceType = NULL;
+ unsigned char * query = NULL;
char * newUri = (char *)requiredUri;
(void) referenceUri;
+ CARemoteEndpoint_t* endpoint = NULL;
+ CAResult_t caResult;
+ CAToken_t token = NULL;
+ CAInfo_t requestData;
+ CARequestInfo_t requestInfo;
+ CAGroupEndpoint_t grpEnd = {0};
+
+ // To track if memory is allocated for additional header options
+ uint8_t hdrOptionMemAlloc = 0;
OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
- TODO ("Need to form the final query by concatenating require and reference URI's");
+ //TODO ("Need to form the final query by concatenating require and reference URI's");
VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
uint16_t uriLen = strlen(requiredUri);
- // ToDo: We should also check if the requiredUri has a mutlicast address, then qos has to be OC_Low_QOS
+ // ToDo: We should also check if the requiredUri has a mutlicast address,
+ // then qos has to be OC_Low_QOS
switch (method)
{
case OC_REST_GET:
#ifdef WITH_PRESENCE
if(method == OC_REST_PRESENCE)
{
- result = getResourceType(requiredUri, &resourceType, &newUri);
- if(resourceType) {
- OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
+ result = getQueryFromUri(requiredUri, &query, &newUri);
+ if(query)
+ {
+ result = getResourceType((char *) query, &resourceType);
+ if(resourceType)
+ {
+ OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
+ }
+ else
+ {
+ OC_LOG(DEBUG, TAG, PCF("Resource type is NULL."));
+ }
}
else
{
- OC_LOG(DEBUG, TAG, "Got Resource Type is NULL.");
+ OC_LOG(DEBUG, TAG, PCF("Query string is NULL."));
}
if(result != OC_STACK_OK)
{
goto exit;
}
- // Generate token which will be used by OCStack to match responses received
- // with the request
- OCGenerateCoAPToken(&token);
+ memset(&requestData, 0, sizeof(CAInfo_t));
+ memset(&requestInfo, 0, sizeof(CARequestInfo_t));
+ switch (method)
+ {
+ case OC_REST_GET:
+ case OC_REST_OBSERVE:
+ case OC_REST_OBSERVE_ALL:
+ case OC_REST_CANCEL_OBSERVE:
+ {
+ requestInfo.method = CA_GET;
+ break;
+ }
+ case OC_REST_PUT:
+ {
+ requestInfo.method = CA_PUT;
+ break;
+ }
+ case OC_REST_POST:
+ {
+ requestInfo.method = CA_POST;
+ break;
+ }
+ case OC_REST_DELETE:
+ {
+ requestInfo.method = CA_DELETE;
+ break;
+ }
+ #ifdef WITH_PRESENCE
+ case OC_REST_PRESENCE:
+ {
+ // Replacing method type with GET because "presence"
+ // is a stack layer only implementation.
+ requestInfo.method = CA_GET;
+ break;
+ }
+ #endif
+ default:
+ result = OC_STACK_INVALID_METHOD;
+ goto exit;
+ }
+
+ //High QoS is not supported
+ if(qos == OC_HIGH_QOS)
+ {
+ result = OC_STACK_INVALID_PARAM;
+ goto exit;
+ }
+
+ // create token
+ caResult = CAGenerateToken(&token);
+ if (caResult != CA_STATUS_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
+ CADestroyToken(token);
+ goto exit;
+ }
- if((result = AddClientCB(&clientCB, cbData, &token, handle, method, requestUri, resourceType))
- != OC_STACK_OK)
+ requestData.type = qualityOfServiceToMessageType(qos);
+ requestData.token = token;
+ if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
{
- result = OC_STACK_NO_MEMORY;
+ result = CreateObserveHeaderOption (&(requestData.options), options,
+ numOptions, OC_OBSERVE_REGISTER);
+ if (result != OC_STACK_OK)
+ {
+ goto exit;
+ }
+ hdrOptionMemAlloc = 1;
+ requestData.numOptions = numOptions + 1;
+ }
+ else
+ {
+ requestData.options = (CAHeaderOption_t*)options;
+ requestData.numOptions = numOptions;
+ }
+ requestData.payload = (char *)request;
+
+ requestInfo.info = requestData;
+
+ CAConnectivityType_t caConType;
+
+ result = OCToCAConnectivityType((OCConnectivityType) conType, &caConType);
+ if (result != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
+ goto exit;
+ }
+
+ // send request
+ if(conType == OC_ALL)
+ {
+ grpEnd.connectivityType = caConType;
+
+ grpEnd.resourceUri = (CAURI_t) OCMalloc(uriLen + 1);
+ if(!grpEnd.resourceUri)
+ {
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
+ strncpy(grpEnd.resourceUri, requiredUri, (uriLen + 1));
+
+ caResult = CASendRequestToAll(&grpEnd, &requestInfo);
+ }
+ else
+ {
+ caResult = CACreateRemoteEndpoint(newUri, caConType, &endpoint);
+
+ if (caResult != CA_STATUS_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
+ goto exit;
+ }
+
+ caResult = CASendRequest(endpoint, &requestInfo);
+ }
+
+ if (caResult != CA_STATUS_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("CASendRequest"));
goto exit;
}
- // Make call to OCCoAP layer
- result = OCDoCoAPResource(method, qos, &token, newUri, request, options, numOptions);
+ if((result = AddClientCB(&clientCB, cbData, &token, handle, method,
+ requestUri, resourceType)) != OC_STACK_OK)
+ {
+ result = OC_STACK_NO_MEMORY;
+ goto exit;
+ }
exit:
if(newUri != requiredUri)
OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
FindAndDeleteClientCB(clientCB);
}
+ CADestroyRemoteEndpoint(endpoint);
+ OCFree(grpEnd.resourceUri);
+ if (hdrOptionMemAlloc)
+ {
+ OCFree(requestData.options);
+ }
return result;
}
* OC_STACK_INVALID_PARAM - The handle provided is invalid.
*/
OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
- uint8_t numOptions) {
+ uint8_t numOptions)
+{
/*
* This ftn is implemented one of two ways in the case of observation:
*
* Remove the callback associated on client side.
*/
OCStackResult ret = OC_STACK_OK;
+ CARemoteEndpoint_t* endpoint = NULL;
+ CAResult_t caResult;
+ CAInfo_t requestData;
+ CARequestInfo_t requestInfo;
+ // Track if memory is allocated for additional header options
+ uint8_t hdrOptionMemAlloc = 0;
if(!handle) {
return OC_STACK_INVALID_PARAM;
{
case OC_REST_OBSERVE:
case OC_REST_OBSERVE_ALL:
- if(qos == OC_HIGH_QOS)
+ //TODO-CA : Why CA_WIFI alone?
+ caResult = CACreateRemoteEndpoint((char *)clientCB->requestUri, CA_WIFI,
+ &endpoint);
+ if (caResult != CA_STATUS_OK)
{
- ret = OCDoCoAPResource(OC_REST_CANCEL_OBSERVE, qos,
- &(clientCB->token), (const char *) clientCB->requestUri, NULL, options,
- numOptions);
+ OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
+ return OC_STACK_ERROR;
}
- else
+
+ memset(&requestData, 0, sizeof(CAInfo_t));
+ requestData.type = qualityOfServiceToMessageType(qos);
+ requestData.token = clientCB->token;
+ if (CreateObserveHeaderOption (&(requestData.options),
+ options, numOptions, OC_OBSERVE_DEREGISTER) != OC_STACK_OK)
+ {
+ return OC_STACK_ERROR;
+ }
+ hdrOptionMemAlloc = 1;
+ requestData.numOptions = numOptions + 1;
+ memset(&requestInfo, 0, sizeof(CARequestInfo_t));
+ requestInfo.method = CA_GET;
+ requestInfo.info = requestData;
+ // send request
+ caResult = CASendRequest(endpoint, &requestInfo);
+ if (caResult != CA_STATUS_OK)
{
- FindAndDeleteClientCB(clientCB);
+ OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
+ }
+ if(caResult == CA_STATUS_OK)
+ {
+ ret = OC_STACK_OK;
}
- break;
#ifdef WITH_PRESENCE
case OC_REST_PRESENCE:
FindAndDeleteClientCB(clientCB);
return OC_STACK_INVALID_METHOD;
}
}
+ CADestroyRemoteEndpoint(endpoint);
+ if (hdrOptionMemAlloc)
+ {
+ OCFree(requestData.options);
+ }
+
return ret;
}
+
#ifdef WITH_PRESENCE
OCStackResult OCProcessPresence()
{
OCDevAddr dst;
OCClientResponse clientResponse;
OCResponse * response = NULL;
+ OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
LL_FOREACH(cbList, cbNode) {
if(OC_REST_PRESENCE == cbNode->method)
if(cbNode->presence)
{
uint32_t now = GetTime(0);
- OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
+ OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d",
+ cbNode->presence->TTLlevel);
OC_LOG_V(DEBUG, TAG, "----------------current ticks %d", now);
{
OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
&dst);
- result = FormOCClientResponse(&clientResponse, OC_STACK_PRESENCE_TIMEOUT,
- (OCDevAddr *) &dst, 0, NULL);
- if(result != OC_STACK_OK)
- {
- goto exit;
- }
- result = FormOCResponse(&response, cbNode, 0, &clientResponse);
+
+ clientResponse.sequenceNumber = 0;
+ clientResponse.result = OC_STACK_PRESENCE_TIMEOUT;
+ clientResponse.addr = (OCDevAddr *) &dst;
+ clientResponse.resJSONPayload = NULL;
+
+ result = FormOCResponse(&response, cbNode, 0, NULL, NULL,
+ &cbNode->token, &clientResponse, NULL);
if(result != OC_STACK_OK)
{
goto exit;
result = OC_STACK_INVALID_IP;
goto exit;
}
- HandleStackResponses(response);
+
+ cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse);
+ if (cbResult == OC_STACK_DELETE_TRANSACTION)
+ {
+ FindAndDeleteClientCB(cbNode);
+ }
}
+
if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
{
+ CAResult_t caResult;
+ CARemoteEndpoint_t* endpoint = NULL;
+ CAInfo_t requestData;
+ CARequestInfo_t requestInfo;
+
OC_LOG(DEBUG, TAG, PCF("time to test server presence =========="));
- OCCoAPToken token;
- OCGenerateCoAPToken(&token);
- result = OCDoCoAPResource(OC_REST_GET, OC_LOW_QOS,
- &token, (const char *)cbNode->requestUri, NULL, NULL, 0);
- if(result != OC_STACK_OK)
+
+ //TODO-CA : Why CA_WIFI alone?
+ caResult = CACreateRemoteEndpoint((char *)cbNode->requestUri, CA_WIFI,
+ &endpoint);
+
+ if (caResult != CA_STATUS_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
+ goto exit;
+ }
+
+ memset(&requestData, 0, sizeof(CAInfo_t));
+ requestData.type = CA_MSG_NONCONFIRM;
+ requestData.token = cbNode->token;
+
+ memset(&requestInfo, 0, sizeof(CARequestInfo_t));
+ requestInfo.method = CA_GET;
+ requestInfo.info = requestData;
+
+ caResult = CASendRequest(endpoint, &requestInfo);
+
+ if (caResult != CA_STATUS_OK)
{
+ OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
goto exit;
}
+
cbNode->presence->TTLlevel++;
- OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d", cbNode->presence->TTLlevel);
+ OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d",
+ cbNode->presence->TTLlevel);
}
}
}
}
return result;
}
-#endif
+#endif // WITH_PRESENCE
/**
* Called in main loop of OC client or server. Allows low-level processing of
* OC_STACK_OK - no errors
* OC_STACK_ERROR - stack process error
*/
-OCStackResult OCProcess() {
-
- OC_LOG(INFO, TAG, PCF("Entering OCProcess"));
+OCStackResult OCProcess()
+{
#ifdef WITH_PRESENCE
OCProcessPresence();
#endif
- OCProcessCoAP();
+ CAHandleRequestResponse();
return OC_STACK_OK;
}
if(OC_PRESENCE_UNINITIALIZED == presenceState)
{
- OCDevAddr multiCastAddr;
- OCCoAPToken token;
-
presenceState = OC_PRESENCE_INITIALIZED;
- OCGenerateCoAPToken(&token);
- OCBuildIPv4Address(224, 0, 1, 187, 5683, &multiCastAddr);
- //add the presence observer
- AddObserver(OC_PRESENCE_URI, NULL, 0, &token, &multiCastAddr,
- (OCResource *)presenceResource.handle, OC_LOW_QOS);
+
+ CAAddress_t addressInfo;
+ strncpy(addressInfo.IP.ipAddress, "224.0.1.187", CA_IPADDR_SIZE);
+ addressInfo.IP.port = 5683;
+
+ //TODO make sure there is no memory leak here since another copy
+ //of token is being created inside AddObserver
+ CAToken_t caToken = NULL;
+ CAResult_t caResult = CAGenerateToken(&caToken);
+ if (caResult != CA_STATUS_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
+ CADestroyToken(caToken);
+ return OC_STACK_ERROR;
+ }
+
+ AddObserver(OC_PRESENCE_URI, NULL, 0, &caToken,
+ (OCResource *)presenceResource.handle, OC_LOW_QOS,
+ &addressInfo, CA_WIFI);
}
// Each time OCStartPresence is called
return OC_STACK_OK;
}
+OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo)
+{
+ OC_LOG(INFO, TAG, PCF("Entering OCSetDeviceInfo"));
+
+ if(myStackMode == OC_CLIENT)
+ {
+ return OC_STACK_ERROR;
+ }
+
+ return SaveDeviceInfo(deviceInfo);
+}
+
/**
* Create a resource
*
- * @param handle - pointer to handle to newly created resource. Set by ocstack. Used to refer to resource
+ * @param handle - pointer to handle to newly created resource. Set by ocstack.
+ * Used to refer to resource
* @param resourceTypeName - name of resource type. Example: "core.led"
* @param resourceInterfaceName - name of resource interface. Example: "core.rw"
* @param uri - URI of the resource. Example: "/a/led"
* @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
* NULL for default entity handler
- * @param resourceProperties - properties supported by resource. Example: OC_DISCOVERABLE|OC_OBSERVABLE
+ * @param resourceProperties - properties supported by resource.
+ * Example: OC_DISCOVERABLE|OC_OBSERVABLE
*
* @return
* OC_STACK_OK - no errors
return result;
}
// Validate parameters
+ if(!uri || (strlen(uri) == 0))
+ {
+ OC_LOG(ERROR, TAG, PCF("URI is invalid"));
+ return OC_STACK_INVALID_URI;
+ }
// Is it presented during resource discovery?
- if (!handle || !resourceTypeName || !uri) {
+ if (!handle || !resourceTypeName) {
OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
return OC_STACK_INVALID_PARAM;
}
// TODO: Does resource attribute resentation really have to be maintained in stack?
// Is it presented during resource discovery?
- TODO ("Make sure that the resourcetypename doesn't already exist in the resource");
+ //TODO ("Make sure that the resourcetypename doesn't already exist in the resource");
// Create the resourcetype and insert it into the resource list
pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
// Validate parameters
VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
- TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
+ //TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
// Create the resourceinterface and insert it into the resource list
pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
return;
}
-#ifdef WITH_PRESENCE
/**
* Notify Presence subscribers that a resource has been modified
*
* @param qos - Quality Of Service
*
*/
+#ifdef WITH_PRESENCE
OCStackResult SendPresenceNotification(OCResourceType *resourceType)
{
OCResource *resPtr = NULL;
}
result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
+
return result;
}
-#endif
-
+#endif // WITH_PRESENCE
/**
* Notify observers that an observed value has changed.
*
else
{
// Normal response
-
// Get pointer to request info
serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
if(serverRequest)
{
OCDoHandle handle = NULL;
// Generate token here, it will be deleted when the transaction is deleted
- handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
+ handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
if (handle)
{
- OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
+ OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
}
return handle;
}
/**
- * Retrieves a resource type based upon a uri string if the uri string contains only just one
+ * Retrieves a resource type based upon a query ontains only just one
* resource attribute (and that has to be of type "rt").
*
- * @remark This API malloc's memory for the resource type and newURI. Do not malloc resourceType
- * or newURI before passing in.
+ * @remark This API malloc's memory for the resource type. Do not malloc resourceType
+ * before passing in.
*
- * @param uri - Valid URI for "requiredUri" parameter to OCDoResource API.
+ * @param query - The quert part of the URI
* @param resourceType - The resource type to be populated; pass by reference.
- * @param newURI - Return URI without resourceType appended to the end of it. This is used to
- * ensure that the uri parameter is not modified; pass by reference.
*
* @return
- * OC_STACK_INVALID_URI - Returns this if the URI is invalid/NULL.
* OC_STACK_INVALID_PARAM - Returns this if the resourceType parameter is invalid/NULL.
* OC_STACK_OK - Success
*/
-OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI)
+OCStackResult getResourceType(const char * query, unsigned char** resourceType)
+{
+ if(!query)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ OCStackResult result = OC_STACK_ERROR;
+
+ if(strncmp(query, "rt=", 3) == 0)
+ {
+ *resourceType = (unsigned char *) OCMalloc(strlen(query)-3);
+ if(!*resourceType)
+ {
+ result = OC_STACK_NO_MEMORY;
+ }
+
+ strcpy((char *)*resourceType, ((const char *)&query[3]));
+ result = OC_STACK_OK;
+ }
+
+ return result;
+}
+
+OCStackResult getQueryFromUri(const char * uri, unsigned char** query, char ** newURI)
{
if(!uri)
{
return OC_STACK_INVALID_URI;
}
- if(!resourceType || !newURI)
+ if(!query || !newURI)
{
return OC_STACK_INVALID_PARAM;
}
goto exit;
}
strcpy(tempURI, uri);
- leftToken = strtok((char *)tempURI, "?");
+ char* strTokPtr;
+ leftToken = strtok_r((char *)tempURI, "?", &strTokPtr);
+ //TODO-CA: This could be simplified. Clean up required.
while(leftToken != NULL)
{
- if(strncmp(leftToken, "rt=", 3) == 0)
+ if(strncmp(leftToken, "rt=", 3) == 0 || strncmp(leftToken, "if=", 3) == 0)
{
- *resourceType = (unsigned char *) OCMalloc(strlen(leftToken)-3);
- if(!*resourceType)
+ *query = (unsigned char *) OCMalloc(strlen(leftToken) + 1);
+ if(!*query)
{
+ OCFree(tempURI);
goto exit;
}
- strcpy((char *)*resourceType, ((const char *)&leftToken[3]));
+ strcpy((char *)*query, ((const char *)&leftToken[0]));
break;
}
- leftToken = strtok(NULL, "?");
+ leftToken = strtok_r(NULL, "?", &strTokPtr);
}
*newURI = tempURI;
exit:
return OC_STACK_NO_MEMORY;
}
+
+const ServerID OCGetServerInstanceID(void)
+{
+ static bool generated = false;
+ static ServerID sid;
+
+ if(generated)
+ {
+ return sid;
+ }
+
+ sid = OCGetRandom();
+ generated = true;
+ return sid;
+}
+
+const char* OCGetServerInstanceIDString(void)
+{
+ // max printed length of a base 10
+ // uint32 is 10 characters, so 11 includes null.
+ // This will change as the representation gets switched
+ // to another value
+ static char buffer[11];
+ int n = sprintf(buffer, "%u", OCGetServerInstanceID());
+ if (n < 0)
+ {
+ buffer[0]='\0';
+ }
+
+ return buffer;
+}
+
+/// Retrieve the IPv4 address embedded inside OCDev address data structure
+int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
+ uint8_t *c, uint8_t *d )
+{
+ if ( !ipAddr || !a || !b || !c || !d ) {
+ OC_LOG(FATAL, TAG, "Invalid argument");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ *a = ipAddr->addr[0];
+ *b = ipAddr->addr[1];
+ *c = ipAddr->addr[2];
+ *d = ipAddr->addr[3];
+
+ return OC_STACK_OK;
+}
+
+
+/// Retrieve the IPv4 address embedded inside OCDev address data structure
+int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
+{
+ if ( !ipAddr || !port ) {
+ OC_LOG(FATAL, TAG, "Invalid argument");
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ *port = *((uint16_t*)&ipAddr->addr[4]);
+
+ return OC_STACK_OK;
+}
+