OCStackResult AddClientCB (ClientCB** clientCB, OCCallbackData* cbData, CAToken_t token, uint8_t tokenLength, OCDoHandle *handle, OCMethod method, OCDevAddr *devAddr, char * requestUri, char * resourceTypeName, uint32_t ttl) { if(!clientCB || !cbData || !handle || !requestUri || tokenLength > CA_MAX_TOKEN_LEN) { return OC_STACK_INVALID_PARAM; } ClientCB *cbNode = NULL; #ifdef WITH_PRESENCE if(method == OC_REST_PRESENCE) { // Retrieve the presence callback structure for this specific requestUri. cbNode = GetClientCB(NULL, 0, NULL, requestUri); } #endif // WITH_PRESENCE if(!cbNode)// If it does not already exist, create new node. { cbNode = (ClientCB*) OICMalloc(sizeof(ClientCB)); if(!cbNode) { *clientCB = NULL; goto exit; } else { OC_LOG(INFO, TAG, "Adding client callback with token"); OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength); cbNode->callBack = cbData->cb; cbNode->context = cbData->context; cbNode->deleteCallback = cbData->cd; //Note: token memory is allocated in the caller OCDoResource //but freed in DeleteClientCB cbNode->token = token; cbNode->tokenLength = tokenLength; cbNode->handle = *handle; cbNode->method = method; cbNode->sequenceNumber = 0; #ifdef WITH_PRESENCE cbNode->presence = NULL; cbNode->filterResourceType = NULL; #endif // WITH_PRESENCE if (method == OC_REST_PRESENCE || method == OC_REST_OBSERVE || method == OC_REST_OBSERVE_ALL) { cbNode->TTL = 0; } else { cbNode->TTL = ttl; } cbNode->requestUri = requestUri; // I own it now cbNode->devAddr = devAddr; // I own it now OC_LOG_V(INFO, TAG, "Added Callback for uri : %s", requestUri); LL_APPEND(cbList, cbNode); *clientCB = cbNode; } } else { // Ensure that the handle the SDK hands back up to the application layer for the // OCDoResource call matches the found ClientCB Node. *clientCB = cbNode; if (cbData->cd) { cbData->cd(cbData->context); } OICFree(token); OICFree(*handle); OICFree(requestUri); OICFree(devAddr); *handle = cbNode->handle; } #ifdef WITH_PRESENCE if(method == OC_REST_PRESENCE && resourceTypeName) { // Amend the found or created node by adding a new resourceType to it. return InsertResourceTypeFilter(cbNode,(char *)resourceTypeName); // I own resourceTypName now. } else { OICFree(resourceTypeName); } #else OICFree(resourceTypeName); #endif return OC_STACK_OK; exit: return OC_STACK_NO_MEMORY; }
//This function is called back by libcoap when a response is received static void HandleCoAPResponses(struct coap_context_t *ctx, const coap_queue_t * rcvdResponse) { OCResponse * response = NULL; OCCoAPToken rcvdToken; OCClientResponse clientResponse = {0}; ClientCB * cbNode = NULL; unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0}; uint32_t sequenceNumber = OC_OBSERVE_NO_OPTION; uint32_t maxAge = 0; OCStackResult result = OC_STACK_ERROR; coap_pdu_t * sendPdu = NULL; coap_pdu_t * recvPdu = NULL; unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 }; uint8_t isObserveNotification = 0; #ifdef WITH_PRESENCE char * resourceTypeName = NULL; uint8_t remoteIpAddr[4]; uint16_t remotePortNu; unsigned char fullUri[MAX_URI_LENGTH] = { 0 }; uint8_t isPresenceNotification = 0; uint8_t isMulticastPresence = 0; uint32_t lowerBound; uint32_t higherBound; char * tok = NULL; #endif coap_block_t rcvdBlock1 = {COAP_BLOCK_FILL_VALUE}; coap_block_t rcvdBlock2 = {COAP_BLOCK_FILL_VALUE}; uint16_t rcvdSize2 = 0; VERIFY_NON_NULL(ctx); VERIFY_NON_NULL(rcvdResponse); recvPdu = rcvdResponse->pdu; result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &sequenceNumber, &maxAge, &clientResponse.numRcvdVendorSpecificHeaderOptions, clientResponse.rcvdVendorSpecificHeaderOptions, &rcvdBlock1, &rcvdBlock2, NULL, &rcvdSize2, bufRes); VERIFY_SUCCESS(result, OC_STACK_OK); OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u", sequenceNumber); OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", maxAge); OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes); if(sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER) { isObserveNotification = 1; OC_LOG(INFO, TAG, PCF("Received an observe notification")); } #ifdef WITH_PRESENCE if(!strcmp((char *)rcvdUri, (char *)OC_PRESENCE_URI)){ char* tokSavePtr; isPresenceNotification = 1; OC_LOG(INFO, TAG, PCF("Received a presence notification")); tok = strtok_r((char *)bufRes, "[:]}", &tokSavePtr); bufRes[strlen((char *)bufRes)] = ':'; tok = strtok_r(NULL, "[:]}", &tokSavePtr); bufRes[strlen((char *)bufRes)] = ':'; VERIFY_NON_NULL(tok); sequenceNumber = (uint32_t )atol(tok); OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", sequenceNumber); tok = strtok_r(NULL, "[:]}", &tokSavePtr); VERIFY_NON_NULL(tok); maxAge = (uint32_t )atol(tok); OC_LOG_V(DEBUG, TAG, "The received TTL is %u", maxAge); tok = strtok_r(NULL, "[:]}", &tokSavePtr); if(tok) { bufRes[strlen((char *)bufRes)] = ':'; resourceTypeName = (char *)OCMalloc(strlen(tok)); if(!resourceTypeName) { goto exit; } strcpy(resourceTypeName, tok); OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s", resourceTypeName); } bufRes[strlen((char *)bufRes)] = ']'; } #endif // fill OCCoAPToken structure RetrieveOCCoAPToken(recvPdu, &rcvdToken); OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken.tokenLength); OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength); // fill OCClientResponse structure result = FormOCClientResponse(&clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code), (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes); VERIFY_SUCCESS(result, OC_STACK_OK); cbNode = GetClientCB(&rcvdToken, NULL, NULL); #ifdef WITH_PRESENCE // Check if the application subscribed for presence if(!cbNode) { // get the address of the remote OCDevAddrToIPv4Addr((OCDevAddr *) &(rcvdResponse->remote), remoteIpAddr, remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3); OCDevAddrToPort((OCDevAddr *) &(rcvdResponse->remote), &remotePortNu); snprintf((char *)fullUri, sizeof(fullUri), "coap://%d.%d.%d.%d:%d%s", remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3], remotePortNu,rcvdUri); cbNode = GetClientCB(NULL, NULL, fullUri); } // Check if application subscribed for multicast presence if(!cbNode) { snprintf((char *)fullUri, sizeof(fullUri), "%s%s", OC_MULTICAST_IP, rcvdUri); cbNode = GetClientCB(NULL, NULL, fullUri); isMulticastPresence = 1; isPresenceNotification = 0; } #endif // fill OCResponse structure result = FormOCResponse(&response, cbNode, maxAge, &clientResponse); VERIFY_SUCCESS(result, OC_STACK_OK); if(cbNode) { if(!isObserveNotification) { #ifdef WITH_PRESENCE if(!isPresenceNotification) { #endif OC_LOG(INFO, TAG, PCF("Received a regular response")); if(recvPdu->hdr->type == COAP_MESSAGE_CON) { sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, recvPdu->hdr->id, NULL, NULL, NULL); VERIFY_NON_NULL(sendPdu); result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu, (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0)); } #ifdef WITH_PRESENCE } #endif } if(isObserveNotification) { OC_LOG(INFO, TAG, PCF("Received an observe notification")); if(recvPdu->hdr->type == COAP_MESSAGE_CON) { sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, recvPdu->hdr->id, NULL, NULL, NULL); VERIFY_NON_NULL(sendPdu); result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu, (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0)); } //TODO: check the standard for methods to detect wrap around condition if(cbNode->method == OC_REST_OBSERVE && (clientResponse.sequenceNumber <= cbNode->sequenceNumber || (clientResponse.sequenceNumber > cbNode->sequenceNumber && clientResponse.sequenceNumber == (MAX_SEQUENCE_NUMBER)))) { OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \ Ignoring Incoming:%d Against Current:%d.", clientResponse.sequenceNumber, cbNode->sequenceNumber); goto exit; } if(clientResponse.sequenceNumber > cbNode->sequenceNumber){ cbNode->sequenceNumber = clientResponse.sequenceNumber; } } else { #ifdef WITH_PRESENCE if(isPresenceNotification)