Added changes for implementing SequenceNum on Client Side.
Fixed token nuances. Now server and client utilize the same token.
Added Delete functionality to observer implementation.
Sequence Iterator work...It works!! :D
Patch #7 : Modified OCClientResponseHandler callback signature. Updated occlient sample app to reflect that.
Updated code in OCDoResource API for proper error handling.
Updated OCClientCb.h to store DoHandle instead of address of DoHandle.
Took care of some other small tid-bits regarding code formatiing.
Patch #8 : Made one little change Sachin forgot. Check for ptr == NULL not needed when calling free().
Patch #9 : Put in logic for OBSERVE_ALL notification Vs. OBSERVE on client-side. Now client will not accept notifications out of order if OC_REST_OBSERVE is used.
Patch #10 & 11: Added more complete logic for OBSERVE Vs. OBSERVE_ALL logic. Also verified that out of order notifications are handled correctly in each case.
Patch #12: Added functionality to convert coap errors to OC stack errors for server respsonses.
Updated OCClient application to weild specific usage scenarios.
Patch #13: Added fix for some of code review comments by Jesse.
Updated occlient.cpp to OC_REST_OBSERVE in InitObserveRequest method.
Patch #14: (Joey) Added RST to Remove Observations logic.
Patch #15: Rebase on master
Patch #16: (Vijay) Observe delete on server
Patch #17: (Vijay) Fixed issues with cancel (cancel observe still not working)
Patch #18: (Joey) Reverted and Fixed issues with cancel observe.
Patch #19: (Vijay) Observer list delete
Patch #20: (Joey) Fully implemented Cancel Observe. Needs Vijay's approval. (I.e. if Vijay +1's we're done make changes except for code review changes)
Patch #21: (Joey) Cleaned up ALL warnings (minus TODO pragma messages someone has put in.).
Patch #22: (Vijay) Clean up of observe delete and removed printfs
Patch #23: (Vijay) Addressed some of the review comments
Change-Id: Iad7a4263ece57f1545606a5cf05ddfcacb48d363
== 0)
goto cleanup;
break;
+ case COAP_MESSAGE_RST:
+ /* We have sent something the receiver disliked, so we remove
+ * not only the transaction but also the subscriptions we might
+ * have. */
+
+ coap_log(LOG_ALERT, "got RST for message %u\n",
+ ntohs(rcvd->pdu->hdr->id));
+
+ // Handing this up, hoping there's enough info to remove an observe if at all possible.
+ handle_response(context, rcvd);
+
+ /* find transaction in sendqueue to stop retransmission */
+ coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
+
+ if (sent)
+ coap_handle_rst(context, sent);
+ goto cleanup;
default:
debug(
"TODO: Need to handle other message types in coap_dispatch");
int OCProcessCoAP();
OCCoAPToken * OCGenerateCoAPToken();
-/* Vijay: TODO: Add description */
+/**
+ * Initiate sending of CoAP messages. Example: server uses it to send observe messages
+ *
+ * @return OC_COAP_OK - success, OC_COAP_ERR
+ */
int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode,
OCQualityOfService qos, OCCoAPToken * token,
const char *payload, uint32_t seqNum);
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
+#include <unistd.h>
+#include <limits.h>
+#include <ctype.h>
#include "coap.h"
#include "ocstack.h"
#include "occoaptoken.h"
#include "ocstackinternal.h"
-#include <unistd.h>
-#include <limits.h>
-#include <ctype.h>
// Convert OCStack code to CoAP code
uint8_t OCToCoAPResponseCode(OCStackResult result);
+// Convert CoAP code to OCStack code
+OCStackResult CoAPToOCResponseCode(uint8_t coapCode);
+
// Internal function to generate a coap pdu based on passed parameters
coap_pdu_t *
GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id,
//=============================================================================
#include "occoap.h"
#include "occlientcb.h"
+#include "ocobserve.h"
#include <coap.h>
#ifndef WITH_ARDUINO
//=============================================================================
//generate a coap token
-OCCoAPToken * OCGenerateCoAPToken() {
- OCCoAPToken *token;
+OCCoAPToken * OCGenerateCoAPToken()
+{
+ OCCoAPToken *token = NULL;
// Generate token here, it will be deleted when the transaction is deleted
token = (OCCoAPToken *) malloc(sizeof(OCCoAPToken));
- token->tokenLength = MAX_TOKEN_LENGTH;
- OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
+ if (token)
+ {
+ token->tokenLength = MAX_TOKEN_LENGTH;
+ OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
+ }
- //OC_LOG_V(INFO,TAG,"Toke n generated %d bytes..........%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
- // token->tokenLength,token->token[0],token->token[1],token->token[2],token->token[3],
- // token->token[4],token->token[5],token->token[6],token->token[7]);
return token;
}
+
//This function is called back by libcoap when a request is received
static void HandleCoAPRequests(struct coap_context_t *ctx,
const coap_queue_t * rcvdRequest)
OC_LOG_V(INFO, TAG, " Receveid query: %s", entityHandlerRequest->query);
OC_LOG_V(INFO, TAG, " Receveid payload: %s",
request->entityHandlerRequest->reqJSONPayload);
-
- if(GetClientCB(rcvdToken, 0)) { //True if the token was found in the list of clientCBs
- OC_LOG_V(INFO, TAG, " Token received %d bytes",
- rcvdToken->tokenLength);
- OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength);
- }
+ OC_LOG_V(INFO, TAG, " Token received %d bytes",
+ rcvdToken->tokenLength);
+ OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength);
// process the request
result = HandleStackRequests(request);
exit:
coap_delete_list(optList);
- if(rcvdToken) {
- OCFree(rcvdToken);
- rcvdToken = NULL;
- }
+ OCFree(rcvdToken);
OCFree(entityHandlerRequest);
OCFree(request);
}
static void HandleCoAPResponses(struct coap_context_t *ctx,
const coap_queue_t * rcvdResponse) {
OCResponse * response = NULL;
- OCCoAPToken * _token = NULL;
+ OCCoAPToken * token = NULL;
OCClientResponse * clientResponse = NULL;
+ ClientCB * cbNode = NULL;
OCStackResult result;
VERIFY_NON_NULL(ctx);
// TODO: we should check if we are interested in the token
// Now, just accept NON packets
- if (rcvdResponse->pdu->hdr->type == COAP_MESSAGE_NON) {
+ if (rcvdResponse->pdu->hdr->type == COAP_MESSAGE_NON)
+ {
// fill OCResponse structure
result = FormOCResponse(rcvdResponse, &response);
VERIFY_SUCCESS(result, OC_STACK_OK);
// fill OCCoAPToken structure
- result = RetrieveOCCoAPToken(rcvdResponse, &_token);
+ result = RetrieveOCCoAPToken(rcvdResponse, &token);
VERIFY_SUCCESS(result, OC_STACK_OK);
// fill OCClientResponse structure
VERIFY_SUCCESS(result, OC_STACK_OK);
// put everything together
- ClientCB * clientCB = GetClientCB(_token, NULL);
- OCDoHandle *handle = NULL;
- if(clientCB) {
- handle = clientCB->handle;
- response->handle = handle;
- }
response->clientResponse = clientResponse;
+ cbNode = GetClientCB(token, NULL);
+
OC_LOG_V(INFO, TAG, " Received a response HandleCoAPResponses in occoap: %s",
response->clientResponse->resJSONPayload);
- OC_LOG_V(INFO, TAG,"Token received %d bytes", _token->tokenLength);
- OC_LOG_BUFFER(INFO, TAG, _token->token,
- _token->tokenLength);
+ OC_LOG_V(INFO, TAG,"Token received %d bytes", token->tokenLength);
+ OC_LOG_BUFFER(INFO, TAG, token->token,
+ token->tokenLength);
- response->clientResponse->result = OC_STACK_OK;
- HandleStackResponses(response);
- /*if (rcvdResponse->pdu->hdr->code == COAP_RESPONSE_CODE(205))
+ if(cbNode && (cbNode->method == OC_REST_OBSERVE || cbNode->method == OC_REST_OBSERVE_ALL))
{
- response->clientResponse->result = OC_STACK_OK;
- HandleStackResponses(response);
+ if(clientResponse->sequenceNumber != 0)
+ {
+ if(clientResponse->sequenceNumber <= cbNode->sequenceNumber)
+ {
+ OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
+ Ignoring Incoming:%d Against Current:%d.",
+ clientResponse->sequenceNumber, cbNode->sequenceNumber);
+ return;
+ }
+ else
+ {
+ cbNode->sequenceNumber = clientResponse->sequenceNumber;
+ }
+ }
}
- else
+ else if(!cbNode && clientResponse && clientResponse->sequenceNumber != 0) // Ensure that this is an observe notification.
{
- OC_LOG(DEBUG, TAG,
- "No other response codes are supported in HandleCoAPResponses");
- }*/
+
+ coap_pdu_t *pdu;
+ coap_list_t *optList = NULL;
+ coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
+ strlen(OC_RESOURCE_OBSERVE_DEREGISTER), (unsigned char *)OC_RESOURCE_OBSERVE_DEREGISTER), OrderOptions);
+
+ pdu = GenerateCoAPPdu(COAP_MESSAGE_NON, COAP_REQUEST_GET,
+ coap_new_message_id(gCoAPCtx), token->tokenLength, token->token,
+ (unsigned char*)"", optList);
+ VERIFY_NON_NULL(pdu);
+ coap_tid_t tid;
+ tid = coap_send(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, pdu);
+
+ OC_LOG_V(INFO, TAG, "TID %d", tid);
+ if (tid != COAP_INVALID_TID)
+ {
+ OC_LOG(INFO, TAG, "Deleting PDU");
+ coap_delete_pdu(pdu);
+ }
+ else
+ {
+ OC_LOG(INFO, TAG, "Keeping PDU, we should handle the retry of this pdu");
+ }
+ goto exit;
+ }
+ response->cbNode = cbNode;
+ response->clientResponse->result = CoAPToOCResponseCode(rcvdResponse->pdu->hdr->code);
+ HandleStackResponses(response);
}
else
{
exit:
OCFree(response);
- if(_token) {
- OCFree(_token);
- _token = NULL;
- }
+ OCFree(token);
OCFree(clientResponse);
}
ret = OC_COAP_OK;
exit:
+ if (ret != OC_COAP_OK)
+ {
+ OCStopCoAP(gCoAPCtx);
+ }
return ret;
}
int ret = OC_COAP_ERR;
coap_pdu_t *pdu = NULL;
coap_uri_t uri;
- coap_tid_t tid = COAP_INVALID_TID;
OCDevAddr dst;
uint8_t ipAddr[4] = { 0 };
coap_list_t *optList = NULL;
int res;
uint8_t coapMsgType;
uint8_t coapMethod;
- // Vijay: TODO Observation registration is hardcoded here - change
- unsigned char obs[] = "0";
OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
if (Uri) {
OC_LOG_V(INFO, TAG, "URI = %s", Uri);
- }
-
- VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), 0);
-
- // Generate the destination address
- if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr)) {
- OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
- &dst);
- } else {
- goto exit;
- }
-
- //create appropriate coap options
- if (uri.port != COAP_DEFAULT_PORT) {
- coap_insert(&optList,
- CreateNewOptionNode(COAP_OPTION_URI_PORT,
- coap_encode_var_bytes(portBuf, uri.port), portBuf),
- OrderOptions);
- }
-
- if (uri.path.length) {
- buflen = BUF_SIZE;
- res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+ VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), 0);
+
+ // Generate the destination address
+ if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr)) {
+ OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
+ &dst);
+ } else {
+ goto exit;
+ }
- while (res--) {
+ //create appropriate coap options
+ if (uri.port != COAP_DEFAULT_PORT) {
coap_insert(&optList,
- CreateNewOptionNode(COAP_OPTION_URI_PATH,
- COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
+ CreateNewOptionNode(COAP_OPTION_URI_PORT,
+ coap_encode_var_bytes(portBuf, uri.port), portBuf),
OrderOptions);
-
- buf += COAP_OPT_SIZE(buf);
}
- }
- if (uri.query.length) {
- buflen = BUF_SIZE;
- buf = _buf;
- res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+ if (uri.path.length) {
+ buflen = BUF_SIZE;
+ res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
- while (res--) {
- coap_insert(&optList,
- CreateNewOptionNode(COAP_OPTION_URI_QUERY,
- COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
- OrderOptions);
+ while (res--) {
+ coap_insert(&optList,
+ CreateNewOptionNode(COAP_OPTION_URI_PATH,
+ COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
+ OrderOptions);
- buf += COAP_OPT_SIZE(buf);
+ buf += COAP_OPT_SIZE(buf);
+ }
}
- }
- OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
- OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
- OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
- OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
+ if (uri.query.length) {
+ buflen = BUF_SIZE;
+ buf = _buf;
+ res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+
+ while (res--) {
+ coap_insert(&optList,
+ CreateNewOptionNode(COAP_OPTION_URI_QUERY,
+ COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
+ OrderOptions);
+
+ buf += COAP_OPT_SIZE(buf);
+ }
+ }
+ OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
+ OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
+ OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
+ OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
+ }
coapMsgType = COAP_MESSAGE_NON;
// Decide message type
coapMsgType = COAP_MESSAGE_CON;
OC_LOG(FATAL, TAG, "qos == OC_CONFIRMABLE is not supported in OCDoCoAPResource");
}
-
// Decide method type
switch (method) {
case OC_REST_GET:
case OC_REST_OBSERVE_ALL:
case OC_REST_OBSERVE:
coapMethod = COAP_REQUEST_GET;
-#if 0
- // Joey's add for observation registration: not working.
- // Vijay's change below
- buflen = BUF_SIZE;
- buf = _buf;
- res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
- //Set observe option flag.
- while (res--) {
- coap_insert(&optList,
- CreateNewOptionNode(COAP_OPTION_SUBSCRIPTION,
- COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
- OrderOptions);
-
- buf += COAP_OPT_SIZE(buf);
- }
-#endif
coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
- strlen((const char *)obs), (obs)), OrderOptions);
+ strlen(OC_RESOURCE_OBSERVE_REGISTER), (unsigned char *)OC_RESOURCE_OBSERVE_REGISTER), OrderOptions);
break;
default:
(unsigned char*) payload, optList);
VERIFY_NON_NULL(pdu);
- TODO ("Post Sprint 1 -- Send Confirmed requests for non-discovery requests");
- tid = coap_send(gCoAPCtx, (coap_address_t*) &dst, pdu);
+ coap_send(gCoAPCtx, (coap_address_t*) &dst, pdu);
- OC_LOG_V(INFO, TAG, "TID %d", tid);
- if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
+ //OC_LOG_V(INFO, TAG, "TID %d", tid);
+ TODO ("Once CON implementation is available, pdu should be saved until ACK is received");
+ //if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
{
OC_LOG(INFO, TAG, "Deleting PDU");
coap_delete_pdu(pdu);
pdu = NULL;
}
- else
- {
- OC_LOG(INFO, TAG, "Keeping PDU, we should handle the retry of this pdu");
- }
ret = OC_COAP_OK;
return ret;
}
-int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode,
+int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode,
OCQualityOfService qos, OCCoAPToken * token,
const char *payload, uint32_t seqNum)
{
OC_LOG(INFO, TAG, PCF("Entering OCCoAPSendMessage"));
- printf ("Payload: %s\n", payload);
OC_LOG_V(INFO, TAG, "OCStack payload: %s", payload);
coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE,
coap_encode_var_bytes(tempBuf, COAP_MEDIATYPE_APPLICATION_JSON),
// Helper Functions
//=============================================================================
-//convert OCStack code to CoAP code
+// Convert OCStack code to CoAP code
uint8_t OCToCoAPResponseCode(OCStackResult result)
{
uint8_t ret;
ret = COAP_RESPONSE_400;
break;
- case OC_STACK_INVALID_METHOD :
- ret = COAP_RESPONSE_405;
+ case OC_STACK_NO_RESOURCE :
+ ret = COAP_RESPONSE_404;
break;
- case OC_STACK_NO_RESOURCE :
+ case OC_STACK_INVALID_METHOD :
ret = COAP_RESPONSE_405;
break;
default:
ret = COAP_RESPONSE_500;
+ }
+ return ret;
+}
+
+
+// Convert CoAP code to OCStack code
+OCStackResult CoAPToOCResponseCode(uint8_t coapCode)
+{
+ OCStackResult ret;
+ int decimal;
+ switch(coapCode)
+ {
+ case COAP_RESPONSE_200 :
+ ret = OC_STACK_OK;
+ break;
+
+ case COAP_RESPONSE_400 :
+ ret = OC_STACK_INVALID_QUERY;
+ break;
+
+ case COAP_RESPONSE_404 :
+ ret = OC_STACK_NO_RESOURCE;
+ break;
+ case COAP_RESPONSE_405 :
+ ret = OC_STACK_INVALID_METHOD;
+ break;
+
+ default:
+ decimal = ((coapCode >> 5) * 100) + (coapCode && 31);
+ if (decimal >= 200 && decimal <= 231)
+ {
+ ret = OC_STACK_OK;
+ }
+ else
+ {
+ ret = OC_STACK_ERROR;
+ }
}
return ret;
}
+
// Form the OCRequest struct
OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
OCRequest * * requestLoc, unsigned char * uriBuf,
coap_option_setb(filter, COAP_OPTION_OBSERVE);
coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter);
while ((option = coap_option_next(&opt_iter))) {
- printf ("\n\n ******************* OBS ********** %d, %s\n\n\n", COAP_OPT_LENGTH(option), COAP_OPT_VALUE(option));
request->observe = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq));
if (request->observe)
{
else
{
OCFree (request->observe);
+ OCFree (request);
+ return OC_STACK_NO_MEMORY;
+ }
+ obsReq->token = (OCCoAPToken *)OCMalloc(sizeof(MAX_TOKEN_LENGTH));
+ if(obsReq->token)
+ {
+ memcpy (&obsReq->token->token, rcvdRequest->pdu->hdr->token,
+ rcvdRequest->pdu->hdr->token_length);
+ obsReq->token->tokenLength = rcvdRequest->pdu->hdr->token_length;
+ }
+ else
+ {
+ OCFree (request->observe);
+ OCFree (request);
return OC_STACK_NO_MEMORY;
}
- /*
- // Vijay: TODO: Remove this code block before final commit
- // TODO: Should we copy sizeof OCDevAddr or introspect the addr for size
- memcpy (&(obsReq->subAddr), (OCDevAddr *) &(rcvdRequest->remote),sizeof(OCDevAddr));
- coapTok = obsReq->coapTok;
- coapTok->tokenLength = rcvdRequest->pdu->hdr->token_length;
- memcpy(coapTok->token, rcvdRequest->pdu->hdr->token, coapTok->tokenLength);
- */
obsReq->subAddr = (OCDevAddr *)&(rcvdRequest->remote);
- obsReq->coapToken = rcvdRequest->pdu->hdr->token;
- obsReq->coapTokenLen = rcvdRequest->pdu->hdr->token_length;
} else {
+ OCFree (request);
return OC_STACK_NO_MEMORY;
}
}
OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse,
OCClientResponse * * clientResponseLoc) {
- //OCClientResponse * * clientResponseLoc, unsigned char * resBuf) {
+
+ coap_opt_filter_t filter;
+ coap_opt_iterator_t opt_iter;
+ coap_opt_t *option;
unsigned char * pRes = NULL;
size_t bufLen = 0;
if (!clientResponse) {
return OC_STACK_NO_MEMORY;
}
-
+ clientResponse->sequenceNumber = 0;
clientResponse->result = OC_STACK_ERROR;
clientResponse->addr = (OCDevAddr *) &(rcvdResponse->remote);
+ // fill in observe, if present
+ coap_option_filter_clear(filter);
+ coap_option_setb(filter, COAP_OPTION_OBSERVE);
+ coap_option_iterator_init(rcvdResponse->pdu, &opt_iter, filter);
+ while ((option = coap_option_next(&opt_iter))) {
+ if (option)
+ {
+ memcpy(&clientResponse->sequenceNumber, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
+ }
+ else
+ {
+ return OC_STACK_NO_MEMORY;
+ }
+ }
coap_get_data(rcvdResponse->pdu, &bufLen, &pRes);
clientResponse->resJSONPayload = pRes;
- //clientResponse->resJSONPayloadLen = bufLen;
-
- /*if (bufLen >= MAX_RESPONSE_LENGTH) {
- return OC_STACK_NO_MEMORY;
- }
-
- memcpy(resBuf, pRes, bufLen);
- resBuf[bufLen] = '\0';
- clientResponse->resJSONPayload = resBuf;*/
*clientResponseLoc = clientResponse;
return OC_STACK_OK;
//a function to create a coap option
coap_list_t *
-CreateNewOptionNode(unsigned short key, unsigned int length,
- unsigned char *data) {
- coap_option *option;
+CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data)
+{
+ coap_option *option = NULL;
coap_list_t *node;
+ VERIFY_NON_NULL(data);
option = coap_malloc(sizeof(coap_option) + length);
- if (!option) {
- goto exit;
- }
+ VERIFY_NON_NULL(option);
COAP_OPTION_KEY(*option) = key;
COAP_OPTION_LENGTH(*option) = length;
- VERIFY_NON_NULL(data);
memcpy(COAP_OPTION_DATA(*option), data, length);
/* we can pass NULL here as delete function since option is released automatically */
node = coap_new_listnode(option, NULL);
- if (node) {
+ if (node)
+ {
return node;
}
- exit: OC_LOG(ERROR,TAG,"new_option_node: malloc: was not created");
+exit:
+ OC_LOG(ERROR,TAG,"new_option_node: malloc: was not created");
coap_free(option);
return NULL;
}
#include <ocstack.h>
#include <occoaptoken.h>
-#include <occoap.h>
typedef struct ClientCB {
// callback method defined in application address space
// when a response is recvd with this token, above callback will be invoked
OCCoAPToken * token;
// Invocation handle tied to original call to OCDoResource()
- OCDoHandle * handle;
+ OCDoHandle handle;
// This is used to determine if all responses should be consumed or not. (For now, only pertains to OC_REST_OBSERVE_ALL Vs. OC_REST_OBSERVE functionality)
OCMethod method;
+ // This is the sequence identifier the server applies to the invocation tied to 'handle'.
+ uint32_t sequenceNumber;
// next node in this list
struct ClientCB *next;
} ClientCB;
* @retval OC_STACK_OK for Success, otherwise some error value
*/
//------------------------------------------------------------------------
-OCStackResult AddClientCB(ClientCB* clientCB, OCCallbackData *cbData, OCCoAPToken * token, OCDoHandle * handle, OCMethod method);
+OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData *cbData, OCCoAPToken * token, OCDoHandle handle, OCMethod method);
//-- DeleteClientCB -----------------------------------------------------------
/** @ingroup ocstack
#define OC_RESOURCE_OBSERVE_REGISTER "0"
#define OC_RESOURCE_OBSERVE_DEREGISTER "1"
-/* Vijay: TODO add comments */
+/* This information is stored for each registerd observer */
typedef struct ObserveResourceServer {
- // xxxxxxxxxxxxxxxx
+ // URI of observed resource
unsigned char *resUri;
- // xxxxxxxxxxxxxxxxx
+ // Query
unsigned char *query;
- // xxxxxxxxxxxxxxxxx
- OCCoAPToken *coapTok;
- // xxxxxxxxxxxxxxxxx
+ // CoAP token for the observe request
+ OCCoAPToken *token;
+ // Resource handle
OCResource *resource;
- // xxxxxxxxxxxxxxxxx
+ // IP address & port of client registered for observe
OCDevAddr *addr;
// next node in this list
struct ObserveResourceServer *next;
OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr);
+void DeleteObserverList();
+
#endif //OC_OBSERVE_H
//-----------------------------------------------------------------------------
#include "ocstack.h"
#include "occoaptoken.h"
+#include "occlientcb.h"
#ifdef __cplusplus
extern "C" {
uint32_t sequenceNum;
} OCResource;
-/* Vijay: TODO add comments */
typedef struct {
- // xxxxxxxxxxxxxxxx
+ // Observe option field
unsigned char *option;
- // xxxxxxxxxxxxxxxx
+ // IP address & port of client registered for observe
OCDevAddr *subAddr;
- // xxxxxxxxxxxxxxxx
- uint8_t *coapToken;
- // xxxxxxxxxxxxxxxx
- size_t coapTokenLen;
+ // CoAP token for the observe request
+ OCCoAPToken *token;
} OCObserveReq;
// following structure will be created in occoap and passed up the stack on the server side
OCQualityOfService qos;
// this structure points to the information for processing observe option
OCObserveReq *observe;
+ // If a subscription update, this is count of observe notifications from server perspective.
+ uint32_t sequenceNum;
// this structure will be passed to entity handler
OCEntityHandlerRequest * entityHandlerRequest;
} OCRequest;
// following structure will be created in occoap and passed up the stack on the client side
typedef struct {
// handle is retrieved by comparing the token-handle pair in the PDU.
- OCDoHandle * handle;
+ ClientCB * cbNode;
// this structure will be passed to client
OCClientResponse * clientResponse;
} OCResponse;
// Address of remote server
OCDevAddr * addr;
// If associated with observe, this will represent the sequence of notifications from server.
- uint8_t sequenceNumber;
+ uint32_t sequenceNumber;
// resJSONPayload is retrieved from the payload of the received request PDU
unsigned const char * resJSONPayload;
}OCClientResponse;
/**
* Client applications implement this callback to consume responses received from Servers.
*/
-typedef OCStackApplicationResult (* OCClientResponseHandler)(void *context, OCClientResponse * clientResponse);
+typedef OCStackApplicationResult (* OCClientResponseHandler)(void *context, OCDoHandle handle, OCClientResponse * clientResponse);
/*
INC_DIRS += -I$(OCTBSTACK_INC)
CC_FLAGS.debug := -O0 -g3 -Wall -ffunction-sections -fdata-sections -fno-exceptions \
- -pedantic $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
+ -std=c++0x -pedantic $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
CC_FLAGS.release := -Os -Wall -fdata-sections -Wl,--gc-sections -Wl,-s -fno-exceptions \
- $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
+ -std=c++0x $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
LDLIBS += -loctbstack -lpthread
CPPFLAGS += $(CC_FLAGS.$(BUILD)) $(LDLIBS)
#define MAX_LENGTH_IPv4_ADDR 16
#endif
+#define MAX_TEST_CASES 5
+
+static int UNICAST_DISCOVERY = 0;
+static int TEST_CASE = 0;
static std::string putPayload = "{\"state\":\"off\",\"power\":\"0\"}";
+// The handle for the observe registration
+OCDoHandle gObserveDoHandle;
+// After this crosses a threshold client deregisters for further observations
+int gNumNotifies = 1;
+
int gQuitFlag = 0;
/* SIGINT handler: set gQuitFlag to 1 for graceful termination */
void handleSigInt(int signum) {
}
}
-OCStackApplicationResult clientApplicationGETCb(void* ctx, OCClientResponse * clientResponse);
+// Forward Declaration
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse);
+int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse);
+int InitObserveRequest(OCClientResponse * clientResponse);
+int InitPutRequest(OCClientResponse * clientResponse);
+int InitGetRequest(OCClientResponse * clientResponse);
+int InitDiscovery();
+
+void PrintUsage()
+{
+ OC_LOG(INFO, TAG, "Usage : occlient <Unicast Discovery> <Test Case>");
+ OC_LOG(INFO, TAG, "Test Case 1 : Discover Resources");
+ OC_LOG(INFO, TAG, "Test Case 2 : Discover Resources and Initiate Get Request");
+ OC_LOG(INFO, TAG, "Test Case 3 : Discover Resources and Initiate Get/Put Requests");
+ OC_LOG(INFO, TAG, "Test Case 4 : Discover Resources and Initiate Observe Requests");
+ OC_LOG(INFO, TAG, "Test Case 5 : Discover Resources and Initiate Get Request for a resource which is unavailable");
+}
-OCStackApplicationResult clientApplicationPUTCb(void* ctx, OCClientResponse * clientResponse) {
+OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
if(clientResponse) {}
if(ctx == (void*)CTX_VAL) {
OC_LOG_V(INFO, TAG, "Callback Context for PUT query recvd successfully");
- OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
+ OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
}
return OC_STACK_KEEP_TRANSACTION;
}
-OCStackApplicationResult clientApplicationGETCb(void* ctx, OCClientResponse * clientResponse) {
- if(clientResponse) {}
- if(ctx == (void*)CTX_VAL) {
- OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
- OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
-#if 0
- //* Make a GET query*/
- std::ostringstream getQuery;
- getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
- OCCallbackData cbData;
- cbData.cb = clientApplicationPUTCb;
- cbData.context = (void*)CTX_VAL;
- OCDoHandle handle;
-
- OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
- if (OCDoResource(&handle, OC_REST_PUT, getQuery.str().c_str(), 0, putPayload.c_str(), OC_NON_CONFIRMABLE, &cbData)
- != OC_STACK_OK) {
- OC_LOG_V(ERROR, TAG, "OCStack resource error");
- //reOC_LOG_Vturn 0;
- }
-#endif
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
+ OC_LOG_V(INFO, TAG, "StackResult: %s",
+ getResult(clientResponse->result));
+ if(ctx == (void*)CTX_VAL) {
+ OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
+ if(clientResponse->sequenceNumber == 0) {
+ OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
+ OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
+ }
+ else {
+ OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumNotifies);
+ OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
+ gNumNotifies++;
+ if (gNumNotifies == 3)
+ {
+ if (OCCancel (gObserveDoHandle) != OC_STACK_OK){
+ OC_LOG(ERROR, TAG, "Observe cancel error");
+ }
+ }
+ }
}
return OC_STACK_KEEP_TRANSACTION;
}
// This is a function called back when a device is discovered
-OCStackApplicationResult clientApplicationCB(void* ctx,
+OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
OCClientResponse * clientResponse) {
uint8_t remoteIpAddr[4];
uint16_t remotePortNu;
- OCDoHandle handle;
OC_LOG(INFO, TAG,
- "Entering clientApplicationCB (Application Layer CB)");
+ "Entering discoveryReqCB (Application Layer CB)");
OC_LOG_V(INFO, TAG, "StackResult: %s",
getResult(clientResponse->result));
"Device =============> Discovered %s @ %d.%d.%d.%d:%d",
clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
-
- std::ostringstream obsReg;
- obsReg << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+
+ if (TEST_CASE == 2)
+ {
+ InitGetRequest(clientResponse);
+ }
+ else if (TEST_CASE == 3)
+ {
+ InitPutRequest(clientResponse);
+ }
+ else if (TEST_CASE == 4)
+ {
+ InitObserveRequest(clientResponse);
+ }
+ else if (TEST_CASE == 5)
+ {
+ InitGetRequestToUnavailableResource(clientResponse);
+ }
+ return OC_STACK_KEEP_TRANSACTION;
+}
+
+
+int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse)
+{
+ OCStackResult ret;
OCCallbackData cbData;
- cbData.cb = clientApplicationGETCb;
- cbData.context = (void*)CTX_VAL;
- if (OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData)
- != OC_STACK_OK) {
+ OCDoHandle handle;
+ std::ostringstream getQuery;
+ getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << "/SomeUnknownResource";
+ cbData.cb = getReqCB;
+ cbData.context = (void*)CTX_VAL;
+ ret = OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
+ if (ret != OC_STACK_OK)
+ {
OC_LOG(ERROR, TAG, "OCStack resource error");
- //return 0;
- }
- return OC_STACK_KEEP_TRANSACTION;
-#if 0
- //* Make a GET query*/
- std::ostringstream getQuery;
- getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+ }
+ return ret;
+}
+
+
+int InitObserveRequest(OCClientResponse * clientResponse)
+{
+ OCStackResult ret;
+ OCCallbackData cbData;
+ OCDoHandle handle;
+ std::ostringstream obsReg;
+ obsReg << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+ cbData.cb = getReqCB;
+ cbData.context = (void*)CTX_VAL;
+ OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
+ ret = OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
+ if (ret != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack resource error");
+ }
+ else
+ {
+ gObserveDoHandle = handle;
+ }
+ return ret;
+}
+
+
+int InitPutRequest(OCClientResponse * clientResponse)
+{
+ OCStackResult ret;
+ OCCallbackData cbData;
+ OCDoHandle handle;
+ //* Make a PUT query*/
+ std::ostringstream getQuery;
+ getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+ cbData.cb = putReqCB;
+ cbData.context = (void*)CTX_VAL;
+ OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
+ ret = OCDoResource(&handle, OC_REST_PUT, getQuery.str().c_str(), 0, putPayload.c_str(), OC_NON_CONFIRMABLE, &cbData);
+ if (ret != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack resource error");
+ }
+ return ret;
+}
+
+
+int InitGetRequest(OCClientResponse * clientResponse)
+{
+ OCStackResult ret;
OCCallbackData cbData;
- cbData.cb = clientApplicationGETCb;
- cbData.context = (void*)CTX_VAL;
- if (OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData)
- != OC_STACK_OK) {
+ OCDoHandle handle;
+ //* Make a GET query*/
+ std::ostringstream getQuery;
+ getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+ cbData.cb = getReqCB;
+ cbData.context = (void*)CTX_VAL;
+ ret = OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
+ if (ret != OC_STACK_OK)
+ {
OC_LOG(ERROR, TAG, "OCStack resource error");
- //return 0;
- }
+ }
+ return ret;
+}
- return OC_STACK_KEEP_TRANSACTION;
-#endif
+#define TEST_APP_UNICAST_DISCOVERY_QUERY PCF("coap://0.0.0.0:5683/oc/core")
+int InitDiscovery()
+{
+ OCStackResult ret;
+ OCCallbackData cbData;
+ OCDoHandle handle;
+ /* Start a discovery query*/
+ char szQueryUri[64] = { 0 };
+ if (UNICAST_DISCOVERY)
+ {
+ strcpy(szQueryUri, TEST_APP_UNICAST_DISCOVERY_QUERY);
+ }
+ else
+ {
+ strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
+ }
+ cbData.cb = discoveryReqCB;
+ cbData.context = (void*)CTX_VAL;
+ ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_NON_CONFIRMABLE, &cbData);
+ if (ret != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack resource error");
+ }
+ return ret;
}
-//This function is called back when a resource is discovered.
-int main() {
+int main(int argc, char* argv[]) {
uint8_t addr[20] = {0};
uint8_t* paddr = NULL;
uint16_t port = USE_RANDOM_PORT;
uint8_t ifname[] = "eth0";
- OCCallbackData cbData;
- OCDoHandle handle;
+
+ if (argc == 3)
+ {
+ UNICAST_DISCOVERY = atoi(argv[1]);
+ TEST_CASE = atoi(argv[2]);
+ if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
+ (TEST_CASE < 1 || TEST_CASE > MAX_TEST_CASES) )
+ {
+ PrintUsage();
+ return -1;
+ }
+ }
+ else
+ {
+ PrintUsage();
+ return -1;
+ }
+
/*Get Ip address on defined interface and initialize coap on it with random port number
* this port number will be used as a source port in all coap communications*/
return 0;
}
- /* Start a discovery query*/
- char szQueryUri[64] = { 0 };
- strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
- cbData.cb = clientApplicationCB;
- cbData.context = (void*)CTX_VAL;
- if (OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_NON_CONFIRMABLE, &cbData)
- != OC_STACK_OK) {
- OC_LOG(ERROR, TAG, "OCStack resource error");
- return 0;
- }
+ InitDiscovery();
// Break from loop with Ctrl+C
OC_LOG(INFO, TAG, "Entering occlient main loop...");
}
}
-void * ChangeLEDRepresentation (void *param)
+void *ChangeLEDRepresentation (void *param)
{
(void)param;
OCStackResult result = OC_STACK_ERROR;
while (1)
{
- sleep (15);
+ sleep(10);
LED.power += 5;
if (gLEDUnderObservation)
{
OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", LED.power);
result = OCNotifyObservers (LED.handle);
- printf ("==========> Result from stack: %s\n", getResult(result));
if (OC_STACK_NO_OBSERVERS == result)
{
gLEDUnderObservation = 0;
}
}
}
+ return NULL;
}
int main() {
#include "occlientcb.h"
+#include "occoap.h"
#include "utlist.h"
#include "logger.h"
#include <string.h>
static struct ClientCB *cbList = NULL;
-OCStackResult AddClientCB(ClientCB* clientCB, OCCallbackData* cbData, OCCoAPToken * token, OCDoHandle * handle, OCMethod method) {
+OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData, OCCoAPToken * token, OCDoHandle handle, OCMethod method) {
ClientCB *cbNode;
cbNode = (ClientCB*) OCMalloc(sizeof(ClientCB));
if (cbNode) {
cbNode->token = token;
cbNode->handle = handle;
cbNode->method = method;
+ cbNode->sequenceNumber = 0;
LL_APPEND(cbList, cbNode);
- clientCB = cbNode;
+ *clientCB = cbNode;
return OC_STACK_OK;
}
- clientCB = NULL;
+ *clientCB = NULL;
return OC_STACK_NO_MEMORY;
}
void DeleteClientCB(ClientCB * cbNode) {
if(cbNode) {
LL_DELETE(cbList, cbNode);
- if(cbNode->token) {
- OCFree(cbNode->token);
- cbNode->token = NULL;
- }
+ OCFree(cbNode->token);
+ OCFree(cbNode->handle);
OCFree(cbNode);
cbNode = NULL;
}
size_t tokenLength,
OCDevAddr *addr,
OCResource *resHandle);
+OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength);
OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
{
OCObserveReq *obs = request->observe;
OC_LOG(INFO, TAG, "Entering ProcessObserveRequest");
- printf ("Observer option: %s\n", obs->option);
if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_REGISTER) == 0) {
+ if (NULL == resource)
+ {
+ return OC_STACK_ERROR;
+ }
// Register new observation
- printf ("Register new observation\n\n");
+ request->entityHandlerRequest->resource = (OCResourceHandle)resource;
result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest);
if (OC_STACK_OK == result)
{
// Add subscriber to the server observation list
result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query),
- obs->coapToken, obs->coapTokenLen, obs->subAddr, resource);
+ obs->token->token, obs->token->tokenLength, obs->subAddr, resource);
}
return result;
- } else if (strcmp ((char *)request->observe, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) {
+ } else if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) {
// Deregister observation
- return OC_STACK_NOTIMPL;
+ result = DeleteObserver (obs->token->token, obs->token->tokenLength);
+ return result;
} else {
// Invalid option
+ OC_LOG(ERROR, TAG, "Invalid CoAP observe option");
return OC_STACK_INVALID_OBSERVE_PARAM;
}
}
result = resPtr->entityHandler (OC_REQUEST_FLAG, &entityHandlerReq);
if (OC_STACK_OK == result)
{
- printf ("Calling OCCoAPSendMessage: Payload: %s\n", entityHandlerReq.resJSONPayload);
- OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->coapTok,
+ OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->token,
(const char *)entityHandlerReq.resJSONPayload,
resPtr->sequenceNum);
}
obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1));
VERIFY_NON_NULL (obsNode->query);
memcpy (obsNode->query, query, sizeof(strlen(query)+1));
- obsNode->coapTok = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
- VERIFY_NON_NULL (obsNode->coapTok);
- tokPtr = obsNode->coapTok;
+ obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
+ VERIFY_NON_NULL (obsNode->token);
+ tokPtr = obsNode->token;
memcpy (tokPtr->token, token, sizeof(OCCoAPToken));
tokPtr->tokenLength = tokenLength;
obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
exit:
OCFree(obsNode->resUri);
OCFree(obsNode->query);
- OCFree(obsNode->coapTok);
+ OCFree(obsNode->token);
OCFree(obsNode->addr);
OCFree(obsNode);
return OC_STACK_NO_MEMORY;
}
+
+ObserveResourceServer* GetObserver (const uint8_t *token, const size_t tokenLength)
+{
+ ObserveResourceServer *out = NULL;
+
+ if(token)
+ {
+ LL_FOREACH (serverObsList, out)
+ {
+ if((out->token->tokenLength == tokenLength) &&
+ (memcmp(out->token->token, token, tokenLength) == 0)) {
+ return out;
+ }
+ }
+ }
+ OC_LOG(INFO, MOD_NAME, PCF("Observer node not found!!"));
+ return NULL;
+}
+
+OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength)
+{
+ ObserveResourceServer *obsNode = NULL;
+
+ obsNode = GetObserver (token, tokenLength);
+ if (obsNode) {
+ LL_DELETE (serverObsList, obsNode);
+ OCFree(obsNode->resUri);
+ OCFree(obsNode->query);
+ OCFree(obsNode->token);
+ OCFree(obsNode->addr);
+ OCFree(obsNode);
+ return OC_STACK_OK;
+ }
+ return OC_STACK_ERROR;
+}
+
+void DeleteObserverList()
+{
+ ObserveResourceServer *out;
+ ObserveResourceServer *tmp;
+ LL_FOREACH_SAFE (serverObsList, out, tmp)
+ {
+ DeleteObserver (out->token->token, out->token->tokenLength);
+ }
+ serverObsList = NULL;
+}
#include "ocrandom.h"
#include "debug.h"
#include "occoap.h"
-#include "cJSON.h"
-#include <string.h>
-#include <stdlib.h>
//-----------------------------------------------------------------------------
// Typedefs
OCResource* resource = FindResourceByUri((const char*)request->resourceUrl);
if (resource)
{
+ request->entityHandlerRequest->resource = (OCResourceHandle)resource;
result = resource->entityHandler(OC_REQUEST_FLAG, request->entityHandlerRequest);
- if (request->observe != NULL)
- {
- printf ("\n *** An observe is included in message \n");
- ProcessObserveRequest (resource, request);
- }
}
else
{
+ OC_LOG(INFO, TAG, "Resource Not found");
result = OC_STACK_NO_RESOURCE;
}
+ if (request->observe != NULL)
+ {
+ result = ProcessObserveRequest (resource, request);
+ }
}
return result;
//This function will be called back by occoap layer when a response is received
void HandleStackResponses(OCResponse * response) {
- ClientCB * cbNode = NULL;
OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION;
- OC_LOG(INFO, TAG, "Entering OCHandleClientReceiveResponse (OCStack Layer)");
+ OC_LOG(INFO, TAG, "Entering HandleStackResponses (OCStack Layer)");
- TODO ("What does the stack does in case of error");
- if (response->clientResponse->result != OC_STACK_OK) {
- OC_LOG(DEBUG, TAG, "The response has an error, should we do anything?");
- }
-
- cbNode = GetClientCB(NULL, response->handle);
- if (cbNode) {
+ if (response->cbNode) {
OC_LOG(INFO, TAG, PCF("Calling into application address space"));
- result = cbNode->callBack(cbNode->context, response->clientResponse);
+ result = response->cbNode->callBack(response->cbNode->context, response->cbNode->handle, response->clientResponse);
if (result == OC_STACK_DELETE_TRANSACTION) {
- DeleteClientCB(cbNode);
+ DeleteClientCB(response->cbNode);
}
}
- TODO ("What does the stack does in case of error");
}
int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr) {
// Private internal function prototypes
//-----------------------------------------------------------------------------
-OCDoHandle *generateInvocationHandle();
+static OCDoHandle GenerateInvocationHandle();
static void initResources();
static void insertResource(OCResource *resource);
static OCResource *findResource(OCResource *resource);
// Make call to OCCoAP layer
if (OCStopCoAP() == 0) {
+ // Remove all observers
+ DeleteObserverList();
// Remove all the client callbacks
DeleteClientCBList();
stackState = OC_STACK_UNINITIALIZED;
const char *referenceUri, const char *request,
OCQualityOfService qos, OCCallbackData *cbData)
{
- OCDoHandle * _handle;
- OCCoAPToken * _token;
+ OCStackResult result = OC_STACK_ERROR;
+ OCCoAPToken * token = NULL;
ClientCB *clientCB = NULL;
(void) referenceUri;
VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
- _handle = generateInvocationHandle();
- *handle = *_handle;
- _token = OCGenerateCoAPToken();
- if(AddClientCB(clientCB, cbData, _token, handle, method) != OC_STACK_OK) {
- return OC_STACK_NO_MEMORY;
- }
+ TODO ("Need to form the final query by concatenating require and reference URI's");
+ VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
switch (method)
{
case OC_REST_GET:
case OC_REST_PUT:
+ break;
case OC_REST_OBSERVE:
case OC_REST_OBSERVE_ALL:
break;
return OC_STACK_INVALID_METHOD;
}
- TODO ("Need to form the final query by concatenating require and reference URI's");
- // Validate required URI
- VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
-
- if (method == OC_REST_OBSERVE)
+ *handle = GenerateInvocationHandle();
+ VERIFY_NON_NULL(*handle, FATAL, OC_STACK_ERROR);
+ token = OCGenerateCoAPToken();
+ if (!token)
{
- printf ("\n\n ********* OBSERVE REGISTRATION ******* \n\n");
+ goto exit;
}
- // Make call to OCCoAP layer
- if (OCDoCoAPResource(method, qos, _token, requiredUri, request) == OC_COAP_OK) {
- OC_LOG(INFO, TAG, "Done with this function");
- return OC_STACK_OK;
+ if((result = AddClientCB(&clientCB, cbData, token, *handle, method)) != OC_STACK_OK)
+ {
+ goto exit;
}
- OC_LOG(ERROR, TAG, PCF("Stack stop error"));
- DeleteClientCB(clientCB);
- return OC_STACK_ERROR;
+ // Make call to OCCoAP layer
+ result = OCDoCoAPResource(method, qos, token, requiredUri, request);
+
+exit:
+
+ if (result != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
+ if (clientCB)
+ {
+ DeleteClientCB(clientCB);
+ }
+ else
+ {
+ OCFree(token);
+ OCFree(*handle);
+ }
+ }
+ return result;
}
/**
* OC_STACK_INVALID_PARAM - The handle provided is invalid.
*/
OCStackResult OCCancel(OCDoHandle handle) {
+ /*
+ * This ftn can be implemented one of two ways:
+ *
+ * 1. When observe is unobserved..Remove the callback associated on client side.
+ * When the next notification comes in from server, reply with RST message to server.
+ *
+ * 2. When OCCancel is called, and it is associated with an observe request
+ * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
+ * Send Observe request to server with observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
+ * Remove the callback associated on client side.
+ *
+ * Number 1 is implemented here.
+ */
if(!handle) {
return OC_STACK_INVALID_PARAM;
}
+
+ OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
+
ClientCB *clientCB = GetClientCB(NULL, handle);
+
if(clientCB) {
- DeleteClientCB(clientCB);
- return OC_STACK_OK;
+ switch (clientCB->method)
+ {
+ case OC_REST_OBSERVE:
+ case OC_REST_OBSERVE_ALL:
+ // Make call to OCCoAP layer
+ DeleteClientCB(clientCB);
+ break;
+ default:
+ return OC_STACK_INVALID_METHOD;
+ }
}
- return OC_STACK_INVALID_PARAM;
+ return OC_STACK_OK;
}
/**
OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
goto exit;
}
-
+
// added [CL]
result = OCBindResourceHandler((OCResourceHandle) pointer, entityHandler);
if (result != OC_STACK_OK) {
*handle = pointer;
result = OC_STACK_OK;
- exit: if (result != OC_STACK_OK) {
+exit:
+ if (result != OC_STACK_OK)
+ {
OCFree(pointer);
OCFree(str);
}
OCResource *resPtr = NULL;
OCStackResult result;
- OC_LOG(INFO, TAG, PCF("====>Entering OCNotifyObservers"));
+ OC_LOG(INFO, TAG, PCF("Entering OCNotifyObservers"));
VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
// Verify that the resource exists
- printf ("====> Finding resource\n");
resPtr = findResource ((OCResource *) handle);
if (NULL == resPtr)
{
/**
* Generate handle of OCDoResource invocation for callback management.
*/
-OCDoHandle *generateInvocationHandle() {
- OCDoHandle *handle = NULL;
- uint8_t val = sizeof(uint8_t[MAX_TOKEN_LENGTH]);
+static OCDoHandle GenerateInvocationHandle()
+{
+ OCDoHandle handle = NULL;
// Generate token here, it will be deleted when the transaction is deleted
- handle = (OCDoHandle *) malloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
- memset(handle, 0, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
- OCFillRandomMem((uint8_t*)handle, val);
+ handle = (OCDoHandle) malloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
+ if (handle)
+ {
+ OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
+ }
return handle;
}
void OCFree(void *ptr) {
TODO ("This should be moved into an ocmalloc dir and implemented as a separate OC module");
- if(ptr) {
- free(ptr);
- }
+ free(ptr);
}