//-----------------------------------------------------------------------------
#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
//-----------------------------------------------------------------------------
//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
//-----------------------------------------------------------------------------
case OC_ALL:
// Currently OC_ALL represents WIFI and ETHERNET
// Add other connectivity types as they are enabled in future
- *caConType = (CA_WIFI|CA_ETHERNET);
+ *caConType = (CAConnectivityType_t) (CA_WIFI|CA_ETHERNET);
break;
default:
ret = OC_STACK_INVALID_PARAM;
// update response.addr appropriately from endPoint.addressInfo
OCStackResult UpdateResponseAddr(OCClientResponse *response, const CARemoteEndpoint_t* endPoint)
{
- struct sockaddr_in sa;
- OCStackResult ret = OC_STACK_INVALID_PARAM;
+ 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);
- if (!endPoint)
+ // Grabs the first three numbers from the IPv4 address and replaces dots
+ for(int i=0; i<4; i++)
{
- OC_LOG(ERROR, TAG, PCF("CA Remote end-point is NULL!"));
- return ret;
+ tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
+
+ if(!tok)
+ {
+ ret = OC_STACK_ERROR;
+ goto exit;
+ }
+ address.addr[i] = atoi(tok);
}
- inet_pton(AF_INET, endPoint->addressInfo.IP.ipAddress, &(sa.sin_addr));
- sa.sin_port = htons(endPoint->addressInfo.IP.port);
- static OCDevAddr address;
- memcpy((void*)&address.addr, &(sa), sizeof(sa));
+
+ memcpy(&address.addr[4], &endPoint->addressInfo.IP.port, sizeof(uint32_t));
+
if(response)
{
response->addr = &address;
{
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(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)
{
snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", ipAddress, endPoint->addressInfo.IP.port,
OC_PRESENCE_URI);
- cbNode = GetClientCB(NULL, NULL, (unsigned char *)fullUri);
+ cbNode = GetClientCB(NULL, NULL, (unsigned char *) fullUri);
if(cbNode)
{
else
{
snprintf(fullUri, MAX_URI_LENGTH, "%s%s", OC_MULTICAST_IP, endPoint->resourceUri);
- cbNode = GetClientCB(NULL, NULL, (unsigned char *)fullUri);
+ cbNode = GetClientCB(NULL, NULL, (unsigned char *) fullUri);
if(cbNode)
{
multicastPresenceSubscribe = 1;
response.resJSONPayload = NULL;
response.result = OC_STACK_OK;
- UpdateResponseAddr(&response, endPoint);
+ result = UpdateResponseAddr(&response, endPoint);
+ if(result != OC_STACK_OK)
+ {
+ goto exit;
+ }
if(responseInfo->info.payload)
{
{
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;
}
- ClientCB *cbNode = GetClientCB(&(responseInfo->info.token), NULL, NULL);
+ ClientCB *cbNode = GetClientCB((CAToken_t *)&(responseInfo->info.token), NULL, NULL);
if (cbNode)
{
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),
&(responseInfo->info.options[i]), sizeof(OCHeaderOption));
}
}
- if (cbNode->callBack(cbNode->context,
- cbNode->handle, &response) == OC_STACK_DELETE_TRANSACTION)
+ appResult = cbNode->callBack(cbNode->context,
+ cbNode->handle, &response);
+ if (appResult == OC_STACK_DELETE_TRANSACTION)
{
FindAndDeleteClientCB(cbNode);
}
return;
}
+ OCStackResult requestResult = OC_STACK_ERROR;
+
if(myStackMode == OC_CLIENT)
{
//TODO: should the client be responding to requests?
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)
// copy vendor specific header options
// TODO-CA: CA is including non-vendor header options as well, like observe.
// Need to filter those out
- GetObserveHeaderOption(&serverRequest.observationOption,
- requestInfo->info.options, (uint8_t *)&(requestInfo->info.numOptions));
+ 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 = requestInfo->info.numOptions;
+ serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
if (serverRequest.numRcvdVendorSpecificHeaderOptions)
{
memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
- sizeof(CAHeaderOption_t)*requestInfo->info.numOptions);
+ sizeof(CAHeaderOption_t)*tempNum);
}
-
- if(HandleStackRequests (&serverRequest) != OC_STACK_OK)
+ requestResult = HandleStackRequests (&serverRequest);
+ if(requestResult != OC_STACK_OK)
{
OC_LOG(ERROR, TAG, PCF("HandleStackRequests failed"));
}
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);
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)
{
OC_LOG(INFO, TAG, PCF("CASelectNetwork to WIFI"));
}
/**
- * 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:
}
// create token
-
caResult = CAGenerateToken(&token);
if (caResult != CA_STATUS_OK)
{
CAConnectivityType_t caConType;
- result = OCToCAConnectivityType(conType, &caConType);
+ result = OCToCAConnectivityType((OCConnectivityType) conType, &caConType);
if (result != OC_STACK_OK)
{
OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
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);
{
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;
{
if(strncmp(leftToken, "rt=", 3) == 0 || strncmp(leftToken, "if=", 3) == 0)
{
- *query = (unsigned char *) OCMalloc(strlen(leftToken));
+ *query = (unsigned char *) OCMalloc(strlen(leftToken) + 1);
if(!*query)
{
OCFree(tempURI);
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;
+}
+