//-----------------------------------------------------------------------------
#define _POSIX_C_SOURCE 200112L
#include <string.h>
+#include <ctype.h>
#include "ocstack.h"
#include "ocstackinternal.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
//-----------------------------------------------------------------------------
//TODO: we should allow the server to define this
#define MAX_OBSERVE_AGE (0x2FFFFUL)
+//=============================================================================
+// 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
//-----------------------------------------------------------------------------
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)
{
strlen(endPoint->addressInfo.IP.ipAddress) + 1);
// Grabs the first three numbers from the IPv4 address and replaces dots
- for(int i=0; i<3; i++)
+ for(int i=0; i<4; i++)
{
- if(i==0)
- {
- tok = strtok(cpAddress, ".");
- }
- else
- {
- tok = strtok(NULL, ".");
- }
+ tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
+
if(!tok)
{
ret = OC_STACK_ERROR;
goto exit;
}
address.addr[i] = atoi(tok);
- cpAddress[strlen(cpAddress)]='.'; // Replaces the dot here.
}
- // Grabs the last number from the IPv4 address - has no dot to replace
- tok = strtok(NULL, ".");
- if(!tok)
- {
- ret = OC_STACK_ERROR;
- goto exit;
- }
- address.addr[3] = atoi(tok);
memcpy(&address.addr[4], &endPoint->addressInfo.IP.port, sizeof(uint32_t));
if(response)
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(payload, "[:]}");
+ tok = strtok_r(payload, "[:]}", &savePtr);
payload[strlen(payload)] = ':';
- tok = strtok(NULL, "[:]}");
+ tok = strtok_r(NULL, "[:]}", &savePtr);
payload[strlen((char *)payload)] = ':';
*seqNum = (uint32_t) atoi(tok);
- tok = strtok(NULL, "[:]}");
+ tok = strtok_r(NULL, "[:]}", &savePtr);
*maxAge = (uint32_t) atoi(tok);
- tok = strtok(NULL, "[:]}");
+ tok = strtok_r(NULL, "[:]}",&savePtr);
if(tok)
{
if(responseInfo->info.numOptions > 0)
{
int start = 0;
- //First option always with option ID is COAP_OPTION_OBSERVE if it is available.
+ //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),
return;
}
- OCServerProtocolRequest serverRequest;
+ OCServerProtocolRequest serverRequest = {};
- memset (&serverRequest, 0, sizeof(OCServerProtocolRequest));
OC_LOG_V(INFO, TAG, PCF("***** Endpoint URI ***** : %s\n"), (char*)endPoint->resourceUri);
char * newUri = (char *)endPoint->resourceUri;
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);
- //copy URI
- memcpy (&(serverRequest.resourceUrl), newUri, strlen(newUri));
+ 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)
{
- memcpy (&(serverRequest.query), query, strlen((char*)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)
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)OCMalloc(CA_MAX_TOKEN_LEN+1);
+ 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;
}
- memset(serverRequest.requestToken, 0, CA_MAX_TOKEN_LEN + 1);
memcpy(serverRequest.requestToken, requestInfo->info.token, CA_MAX_TOKEN_LEN);
if (requestInfo->info.type == CA_MSG_CONFIRM)
{
OC_LOG(ERROR, TAG,
PCF("The request info numOptions is greater than MAX_HEADER_OPTIONS"));
+ OCFree(serverRequest.requestToken);
return;
}
serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
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)
{
result = OC_STACK_INVALID_PARAM;
goto exit;
}
- tok = strtok((char *)bufRes, "[:]}");
+ char * savePtr;
+ tok = strtok_r((char *)bufRes, "[:]}", &savePtr);
bufRes[strlen((char *)bufRes)] = ':';
- tok = strtok(NULL, "[:]}");
+ 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(NULL, "[:]}");
+ 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(NULL, "[:]}");
+ tok = strtok_r(NULL, "[:]}", &savePtr);
if(tok)
{
resourceTypeName = (char *)OCMalloc(strlen(tok));
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);
}
/**
- * 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
CAToken_t token = NULL;
CAInfo_t requestData;
CARequestInfo_t requestInfo;
- CAGroupEndpoint_t grpEnd;
+ CAGroupEndpoint_t grpEnd = {0};
// To track if memory is allocated for additional header options
uint8_t hdrOptionMemAlloc = 0;
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:
memset(&requestData, 0, sizeof(CAInfo_t));
memset(&requestInfo, 0, sizeof(CARequestInfo_t));
- memset(&grpEnd, 0, sizeof(CAGroupEndpoint_t));
switch (method)
{
case OC_REST_GET:
{
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;
- }
+
+ 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)
if(OC_PRESENCE_UNINITIALIZED == presenceState)
{
- OCDevAddr multiCastAddr;
presenceState = OC_PRESENCE_INITIALIZED;
- OCBuildIPv4Address(224, 0, 1, 187, 5683, &multiCastAddr);
-
CAAddress_t addressInfo;
strncpy(addressInfo.IP.ipAddress, "224.0.1.187", CA_IPADDR_SIZE);
addressInfo.IP.port = 5683;
}
AddObserver(OC_PRESENCE_URI, NULL, 0, &caToken,
- &multiCastAddr, (OCResource *)presenceResource.handle, OC_LOW_QOS,
+ (OCResource *)presenceResource.handle, OC_LOW_QOS,
&addressInfo, CA_WIFI);
}
/**
* 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
// 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));
{
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;
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;
+}
+