+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"));
+}
+