CA Integration: Use only non-confirmed messages for initial integration
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocstack.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21
22 //-----------------------------------------------------------------------------
23 // Includes
24 //-----------------------------------------------------------------------------
25 #include "ocstack.h"
26 #include "ocstackinternal.h"
27 #include "ocresourcehandler.h"
28 #include "occlientcb.h"
29 #include "ocobserve.h"
30 #include "ocrandom.h"
31 #include "debug.h"
32 #include "occoap.h"
33 #include "ocmalloc.h"
34 #include "ocserverrequest.h"
35
36 #ifdef CA_INT
37     #include "cacommon.h"
38     #include "cainterface.h"
39 #endif
40
41 //-----------------------------------------------------------------------------
42 // Typedefs
43 //-----------------------------------------------------------------------------
44 typedef enum {
45     OC_STACK_UNINITIALIZED = 0, OC_STACK_INITIALIZED
46 } OCStackState;
47
48 #ifdef WITH_PRESENCE
49 typedef enum {
50     OC_PRESENCE_UNINITIALIZED = 0, OC_PRESENCE_INITIALIZED
51 } OCPresenceState;
52 #endif
53
54 //-----------------------------------------------------------------------------
55 // Private variables
56 //-----------------------------------------------------------------------------
57 static OCStackState stackState = OC_STACK_UNINITIALIZED;
58
59 OCResource *headResource = NULL;
60 #ifdef WITH_PRESENCE
61 static OCPresenceState presenceState = OC_PRESENCE_UNINITIALIZED;
62 static PresenceResource presenceResource;
63 uint8_t PresenceTimeOutSize = 0;
64 uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100};
65 #endif
66
67 OCMode myStackMode;
68 OCDeviceEntityHandler defaultDeviceHandler;
69
70 //-----------------------------------------------------------------------------
71 // Macros
72 //-----------------------------------------------------------------------------
73 #define TAG  PCF("OCStack")
74 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
75             {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
76 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
77              TAG, PCF(#arg " is NULL")); return (retVal); } }
78 #define VERIFY_NON_NULL_V(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
79     goto exit;} }
80
81 //TODO: we should allow the server to define this
82 #define MAX_OBSERVE_AGE (0x2FFFFUL)
83
84 //-----------------------------------------------------------------------------
85 // Externs
86 //-----------------------------------------------------------------------------
87 extern void DeinitOCSecurityInfo();
88
89 //-----------------------------------------------------------------------------
90 // Internal API function
91 //-----------------------------------------------------------------------------
92
93 // This internal function is called to update the stack with the status of
94 // observers and communication failures
95 OCStackResult OCStackFeedBack(OCCoAPToken * token, uint8_t status)
96 {
97     OCStackResult result = OC_STACK_ERROR;
98     ResourceObserver * observer = NULL;
99     OCEntityHandlerRequest ehRequest = {0};
100
101     switch(status)
102     {
103     case OC_OBSERVER_NOT_INTERESTED:
104         OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
105         observer = GetObserverUsingToken (token);
106         if(observer)
107         {
108             result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
109                     OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
110                     NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
111             if(result != OC_STACK_OK)
112             {
113                 return result;
114             }
115             observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
116         }
117         //observer is not observing anymore
118         result = DeleteObserverUsingToken (token);
119         if(result == OC_STACK_OK)
120         {
121             OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
122         }
123         else
124         {
125             result = OC_STACK_OK;
126             OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
127         }
128         break;
129     case OC_OBSERVER_STILL_INTERESTED:
130         //observer is still interested
131         OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
132                 notifications, reset the failedCount"));
133         observer = GetObserverUsingToken(token);
134         if(observer)
135         {
136             observer->forceHighQos = 0;
137             observer->failedCommCount = 0;
138             result = OC_STACK_OK;
139         }
140         else
141         {
142             result = OC_STACK_OBSERVER_NOT_FOUND;
143         }
144         break;
145     case OC_OBSERVER_FAILED_COMM:
146         //observer is not reachable
147         OC_LOG(DEBUG, TAG, PCF("observer is unreachable"));
148         observer = GetObserverUsingToken(token);
149         if(observer)
150         {
151             if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
152             {
153                 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
154                         OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
155                         NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
156                 if(result != OC_STACK_OK)
157                 {
158                     return OC_STACK_ERROR;
159                 }
160                 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
161                 //observer is unreachable
162                 result = DeleteObserverUsingToken (token);
163                 if(result == OC_STACK_OK)
164                 {
165                     OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
166                 }
167                 else
168                 {
169                     result = OC_STACK_OK;
170                     OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
171                 }
172             }
173             else
174             {
175                 observer->failedCommCount++;
176                 result = OC_STACK_CONTINUE;
177             }
178             observer->forceHighQos = 1;
179             OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
180         }
181         break;
182     default:
183         OC_LOG(ERROR, TAG, PCF("Unknown status"));
184         result = OC_STACK_ERROR;
185         break;
186         }
187     return result;
188 }
189
190 #ifdef CA_INT
191 OCStackResult CAToOCStackResult(CAResponseResult_t caCode)
192 {
193     OCStackResult ret = OC_STACK_ERROR;
194
195     switch(caCode)
196     {
197         case CA_SUCCESS:
198             ret = OC_STACK_OK;
199             break;
200         case CA_CREATED:
201             ret = OC_STACK_RESOURCE_CREATED;
202             break;
203         case CA_DELETED:
204             ret = OC_STACK_RESOURCE_DELETED;
205             break;
206         case CA_BAD_REQ:
207             ret = OC_STACK_INVALID_QUERY;
208             break;
209         case CA_BAD_OPT:
210             ret = OC_STACK_INVALID_OPTION;
211             break;
212         case CA_NOT_FOUND:
213             ret = OC_STACK_NO_RESOURCE;
214             break;
215         default:
216             break;
217     }
218     return ret;
219 }
220
221 //This function will be called back by CA layer when a response is received
222 void HandleCAResponses(const CARemoteEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo)
223 {
224     OC_LOG(INFO, TAG, PCF("Enter HandleCAResponses"));
225     printf ("Received payload: %s\n", (char *)responseInfo->info.payload);
226     OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION;
227     ClientCB *cbNode = GetClientCB((CAToken_t *)&responseInfo->info.token, NULL, NULL);
228     if (cbNode)
229     {
230         OC_LOG(INFO, TAG, PCF("Calling into application address space"));
231         OCClientResponse response;
232         struct sockaddr_in sa;
233
234         inet_pton(AF_INET, endPoint->addressInfo.IP.ipAddress, &(sa.sin_addr));
235         sa.sin_port = htons(endPoint->addressInfo.IP.port);
236         static OCDevAddr address;
237         memcpy((void*)&address.addr, &(sa), sizeof(sa));
238         response.addr = &address;
239         response.result = CAToOCStackResult(responseInfo->result);
240         response.resJSONPayload = (unsigned char*)responseInfo->info.payload;
241         response.numRcvdVendorSpecificHeaderOptions = 0;
242         if(responseInfo->info.numOptions > 0)
243         {
244             //First option alwas with option ID COAP_OPTION_OBSERVE if it is availbale
245             if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE)
246             {
247                 memcpy (&(response.sequenceNumber),
248                 &(responseInfo->info.options[0].optionData), 4);
249             }
250             else
251             {
252                memcpy (&(response.rcvdVendorSpecificHeaderOptions[0]),
253                  &(responseInfo->info.options[0]), sizeof(OCHeaderOption));
254             }
255             for (uint8_t i = 1; i < responseInfo->info.numOptions; i++)
256             {
257                 memcpy (&(response.rcvdVendorSpecificHeaderOptions[i]),
258                  &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
259             }
260             response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions;
261         }
262         result = cbNode->callBack(cbNode->context,
263                 cbNode->handle, &response);
264         if (result == OC_STACK_DELETE_TRANSACTION)
265         {
266             FindAndDeleteClientCB(cbNode);
267         }
268     }
269     OC_LOG_V(INFO, TAG, PCF("Received payload: %s\n"), (char*)responseInfo->info.payload);
270     OC_LOG(INFO, TAG, PCF("Exit HandleCAResponses"));
271 }
272
273 //This function will be called back by CA layer when a request is received
274 void HandleCARequests(const CARemoteEndpoint_t* endPoint, const CARequestInfo_t* requestInfo)
275 {
276     CAInfo_t responseData;
277     CAResponseInfo_t responseInfo;
278     OCStackResult requestResult = OC_STACK_ERROR;
279
280     OC_LOG(INFO, TAG, PCF("Enter HandleCARequests"));
281
282 #if 1
283     if(myStackMode == OC_CLIENT)
284     {
285         //TODO: should the client be responding to requests?
286         return;
287     }
288
289     OCServerProtocolRequest serverRequest;
290
291     memset (&serverRequest, 0, sizeof(OCServerProtocolRequest));
292     // copy URI of resource
293     memcpy (&(serverRequest.resourceUrl), endPoint->resourceUri, strlen(endPoint->resourceUri));
294     //copy query
295     // TODO-CA: Is the query part of header option?
296     //copy request payload
297     if (requestInfo->info.payload)
298     {
299         memcpy (&(serverRequest.reqJSONPayload), requestInfo->info.payload,
300                 strlen(requestInfo->info.payload));
301     }
302     switch (requestInfo->method)
303     {
304         case CA_GET:
305             {
306                 serverRequest.method = OC_REST_GET;
307                 break;
308             }
309         case CA_PUT:
310             {
311                 serverRequest.method = OC_REST_PUT;
312                 break;
313             }
314         case CA_POST:
315             {
316                 serverRequest.method = OC_REST_POST;
317                 break;
318             }
319         case CA_DELETE:
320             {
321                 serverRequest.method = OC_REST_DELETE;
322                 break;
323             }
324         default:
325             {
326                 OC_LOG(ERROR, TAG, PCF("Received CA method %d not supported"));
327                 return;
328             }
329     }
330
331     // copy token
332     OC_LOG_V(INFO, TAG, "HandleCARequests: CA token length = %d", strlen(requestInfo->info.token));
333     OC_LOG_BUFFER(INFO, TAG, requestInfo->info.token, strlen(requestInfo->info.token));
334     // TODO-CA: For CA integration currently copying CAToken to OCCoapToken:
335     // Need to remove OCCoapToken
336     memcpy (&(serverRequest.requestToken.token), requestInfo->info.token,
337             strlen(requestInfo->info.token));
338     serverRequest.requestToken.tokenLength = strlen(requestInfo->info.token);
339     serverRequest.observationOption = OC_OBSERVE_NO_OPTION;
340     if (requestInfo->info.type == CA_MSG_CONFIRM)
341     {
342         serverRequest.qos = OC_HIGH_QOS;
343     }
344     else if (requestInfo->info.type == CA_MSG_NONCONFIRM)
345     {
346         serverRequest.qos = OC_LOW_QOS;
347     }
348     else if (requestInfo->info.type == CA_MSG_ACKNOWLEDGE)
349     {
350         // TODO-CA: Need to handle this
351     }
352     else if (requestInfo->info.type == CA_MSG_RESET)
353     {
354         // TODO-CA: Need to handle this
355     }
356     // CA does not need the following 3 fields
357     serverRequest.coapID = 0;
358     serverRequest.delayedResNeeded = 0;
359     serverRequest.secured = 0;
360
361     // copy the address
362     serverRequest.addressInfo      = endPoint->addressInfo;
363     serverRequest.connectivityType = endPoint->connectivityType;
364     if (requestInfo->info.token)
365     {
366         strncpy(serverRequest.token, requestInfo->info.token, sizeof(serverRequest.token) - 1);
367     }
368 #if 0
369     struct sockaddr_in sa;
370     inet_pton(AF_INET, endPoint->addressInfo.IP.ipAddress, &(sa.sin_addr));
371     sa.sin_port = htons(endPoint->addressInfo.IP.port);
372     memcpy((void*)&serverRequest.requesterAddr, &(sa), sizeof(sa));
373 #endif
374     // copy vendor specific header options
375     // TODO-CA: CA is including non-vendor header options as well, like observe.
376     // Need to filter those out
377     if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS)
378     {
379         // TODO-CA: Need to send an error indicating the num of options is incorrect
380         return;
381     }
382     serverRequest.numRcvdVendorSpecificHeaderOptions = requestInfo->info.numOptions;
383     if (serverRequest.numRcvdVendorSpecificHeaderOptions)
384     {
385         memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
386             sizeof(CAHeaderOption_t)*requestInfo->info.numOptions);
387     }
388
389     requestResult = HandleStackRequests (&serverRequest);
390 #endif
391
392 #if 0
393     // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
394     memset(&responseData, 0, sizeof(CAInfo_t));
395     responseData.token = (requestInfo != NULL) ? requestInfo->info.token : "";
396
397     // TODO : I guess we need to allocate memeory?
398     responseData.payload = "{\"oc\":[{\"href\":\"/a/led\",\"sid\":\"\",\"prop\":{\"rt\":[\"core.led\"],\"if\":[\"oc.mi.def\"],\"obs\":1}}]}";
399
400     //responseInfo = (CAResponseInfo*) malloc(sizeof(CAResponseInfo));
401     memset(&responseInfo, 0, sizeof(CAResponseInfo_t));
402     responseInfo.result = 200;
403     responseInfo.info = responseData;
404
405     // send request (connectivityType from remoteEndpoint of request Info)
406     OC_LOG(INFO, TAG, PCF("CASendResponse in HandleCARequests"));
407     //TODO-CA: CASendResponse returns the result (we need to check if the
408     // result is ok)
409     CAResult_t caResult = CASendResponse(endPoint, &responseInfo);
410     if(caResult != CA_STATUS_OK)
411     {
412         OC_LOG(ERROR, TAG, PCF("CASendResponse error"));
413     }
414 #endif
415
416     OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
417 }
418
419 #endif // CA_INT
420
421 //This function will be called back by occoap layer when a request is received
422 OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
423 {
424     OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
425
426     OCStackResult result = OC_STACK_ERROR;
427     ResourceHandling resHandling;
428     OCResource *resource;
429
430     OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken);
431     if(!request)
432     {
433         OC_LOG(INFO, TAG, PCF("This is a new Server Request"));
434 #ifdef CA_INT
435         result = AddServerCARequest(&request, protocolRequest->coapID,
436                 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
437                 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
438                 protocolRequest->observationOption, protocolRequest->qos,
439                 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
440                 protocolRequest->reqJSONPayload, &protocolRequest->requestToken,
441                 &protocolRequest->requesterAddr, protocolRequest->resourceUrl,
442                 protocolRequest->reqTotalSize,
443                 &protocolRequest->addressInfo, protocolRequest->connectivityType, protocolRequest->token);
444 #else
445         result = AddServerRequest(&request, protocolRequest->coapID,
446                 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
447                 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
448                 protocolRequest->observationOption, protocolRequest->qos,
449                 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
450                 protocolRequest->reqJSONPayload, &protocolRequest->requestToken,
451                 &protocolRequest->requesterAddr, protocolRequest->resourceUrl,
452                 protocolRequest->reqTotalSize);
453 #endif
454         if (OC_STACK_OK != result)
455         {
456             OC_LOG(ERROR, TAG, PCF("Error adding server request"));
457             return result;
458         }
459         VERIFY_NON_NULL(request, ERROR, OC_STACK_NO_MEMORY);
460
461         if(!protocolRequest->reqMorePacket)
462         {
463             request->requestComplete = 1;
464         }
465     }
466     else
467     {
468         OC_LOG(INFO, TAG, PCF("This is either a repeated Server Request or blocked Server Request"));
469     }
470
471     if(request->requestComplete)
472     {
473         OC_LOG(INFO, TAG, PCF("This Server Request is complete"));
474         result = DetermineResourceHandling (request, &resHandling, &resource);
475         if (result == OC_STACK_OK)
476         {
477             result = ProcessRequest(resHandling, resource, request);
478         }
479         else
480         {
481             result = OC_STACK_ERROR;
482         }
483     }
484     else
485     {
486         OC_LOG(INFO, TAG, PCF("This Server Request is incomplete"));
487         result = OC_STACK_CONTINUE;
488     }
489     return result;
490 }
491
492 //This function will be called back by occoap layer when a response is received
493 OCStackResult HandleStackResponses(OCResponse * response)
494 {
495     OC_LOG(INFO, TAG, PCF("Entering HandleStackResponses (OCStack Layer)"));
496     OCStackResult result = OC_STACK_OK;
497     OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
498     uint8_t isObserveNotification = 0;
499     ClientCB * cbNode = NULL;
500     #ifdef WITH_PRESENCE
501     uint8_t isPresenceNotification = 0;
502     uint8_t isMulticastPresence = 0;
503     char * resourceTypeName = NULL;
504     uint32_t lowerBound = 0;
505     uint32_t higherBound = 0;
506     char * tok = NULL;
507     unsigned char * bufRes = response->bufRes;
508     #endif // WITH_PRESENCE
509
510     cbNode = response->cbNode;
511     if(!cbNode)
512     {
513         cbNode = GetClientCB(response->rcvdToken, NULL, NULL);
514     }
515
516     if(response->clientResponse->sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER)
517     {
518         isObserveNotification = 1;
519         OC_LOG(INFO, TAG, PCF("Received an observe notification"));
520     }
521
522     OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u",
523             response->clientResponse->sequenceNumber);
524     OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", response->maxAge);
525     OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
526
527 #ifdef WITH_PRESENCE
528     if(!strcmp((char *)response->rcvdUri, (char *)OC_PRESENCE_URI)){
529         isPresenceNotification = 1;
530         if(!bufRes)
531         {
532             result = OC_STACK_INVALID_PARAM;
533             goto exit;
534         }
535         tok = strtok((char *)bufRes, "[:]}");
536         bufRes[strlen((char *)bufRes)] = ':';
537         tok = strtok(NULL, "[:]}");
538         bufRes[strlen((char *)bufRes)] = ':';
539         response->clientResponse->sequenceNumber = (uint32_t )atoi(tok);
540         OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", response->clientResponse->sequenceNumber);
541         tok = strtok(NULL, "[:]}");
542         response->maxAge = (uint32_t )atoi(tok);
543         OC_LOG_V(DEBUG, TAG, "The received TTL is %u", response->maxAge);
544         tok = strtok(NULL, "[:]}");
545         if(tok)
546         {
547             resourceTypeName = (char *)OCMalloc(strlen(tok));
548             if(!resourceTypeName)
549             {
550                 goto exit;
551             }
552             bufRes[strlen((char *)bufRes)] = ':';
553             strcpy(resourceTypeName, tok);
554             OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s",
555                     resourceTypeName);
556         }
557         bufRes[strlen((char *)bufRes)] = ']';
558     }
559
560     // Check if the application subcribed for presence
561     if(!cbNode)
562     {
563         cbNode = GetClientCB(NULL, NULL, response->fullUri);
564     }
565
566     // Check if application subscribed for multicast presence
567     if(!cbNode)
568     {
569         snprintf((char *)response->fullUri, MAX_URI_LENGTH, "%s%s",
570                 OC_MULTICAST_IP, response->rcvdUri);
571         cbNode = GetClientCB(NULL, NULL, response->fullUri);
572         if(cbNode)
573         {
574             isMulticastPresence = 1;
575             isPresenceNotification = 0;
576         }
577     }
578
579     if(cbNode && isPresenceNotification)
580     {
581         OC_LOG(INFO, TAG, PCF("Received a presence notification"));
582         if(!cbNode->presence)
583         {
584             cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
585             VERIFY_NON_NULL_V(cbNode->presence);
586             cbNode->presence->timeOut = NULL;
587             cbNode->presence->timeOut = (uint32_t *)
588                     OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
589             if(!(cbNode->presence->timeOut)){
590                 OCFree(cbNode->presence);
591                 result = OC_STACK_NO_MEMORY;
592             }
593         }
594         if(response->maxAge == 0)
595         {
596             OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
597             response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
598             if(cbNode->presence)
599             {
600                 OCFree(cbNode->presence->timeOut);
601                 OCFree(cbNode->presence);
602                 cbNode->presence = NULL;
603             }
604         }
605         else
606         {
607             OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %d", GetTime(0));
608             cbNode->presence->TTL = response->maxAge;
609             for(int index = 0; index < PresenceTimeOutSize; index++)
610             {
611                 lowerBound = GetTime(((float)(PresenceTimeOut[index])
612                         /(float)100)*(float)cbNode->presence->TTL);
613                 higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
614                         /(float)100)*(float)cbNode->presence->TTL);
615                 cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
616                 OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout  %d", lowerBound);
617                 OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
618                 OC_LOG_V(DEBUG, TAG, "----------------timeOut entry  %d",
619                         cbNode->presence->timeOut[index]);
620             }
621             cbNode->presence->TTLlevel = 0;
622             OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
623             if(cbNode->sequenceNumber == response->clientResponse->sequenceNumber)
624             {
625                 OC_LOG(INFO, TAG, PCF("===============No presence change"));
626                 goto exit;
627             }
628             OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack"));
629             cbNode->sequenceNumber = response->clientResponse->sequenceNumber;;
630         }
631
632         // Ensure that a filter is actually applied.
633         if(resourceTypeName && cbNode->filterResourceType)
634         {
635             if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
636             {
637                 goto exit;
638             }
639         }
640     }
641     else if(cbNode && isMulticastPresence)
642     {
643         // Check if the same nonce for a given host
644         OCMulticastNode* mcNode = NULL;
645         mcNode = GetMCPresenceNode(response->fullUri);
646
647         if(response->maxAge == 0)
648         {
649             OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
650             response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
651             if(cbNode->presence)
652             {
653                 OCFree(cbNode->presence->timeOut);
654                 OCFree(cbNode->presence);
655                 cbNode->presence = NULL;
656             }
657         }
658         else if(mcNode != NULL)
659         {
660             if(mcNode->nonce == response->clientResponse->sequenceNumber)
661             {
662                 OC_LOG(INFO, TAG, PCF("===============No presence change (Multicast)"));
663                 result = OC_STACK_NO_MEMORY;
664                 goto exit;
665             }
666             mcNode->nonce = response->clientResponse->sequenceNumber;
667         }
668         else
669         {
670             uint32_t uriLen = strlen((char*)response->fullUri);
671             unsigned char* uri = (unsigned char *) OCMalloc(uriLen + 1);
672             if(uri)
673             {
674                 memcpy(uri, response->fullUri, (uriLen + 1));
675             }
676             else
677             {
678                 OC_LOG(INFO, TAG,
679                     PCF("===============No Memory for URI to store in the presence node"));
680                 result = OC_STACK_NO_MEMORY;
681                 goto exit;
682             }
683             result = AddMCPresenceNode(&mcNode, (unsigned char*) uri,
684                     response->clientResponse->sequenceNumber);
685             if(result == OC_STACK_NO_MEMORY)
686             {
687                 OC_LOG(INFO, TAG,
688                     PCF("===============No Memory for Multicast Presence Node"));
689                 result = OC_STACK_NO_MEMORY;
690                 goto exit;
691             }
692         }
693
694         // Ensure that a filter is actually applied.
695         if(resourceTypeName && cbNode->filterResourceType)
696         {
697             if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
698             {
699                 goto exit;
700             }
701         }
702     }
703
704     else if(!cbNode && isPresenceNotification)
705     {
706     OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
707                  ------------ ignoring"));
708     }
709     #endif // WITH_PRESENCE
710
711     if(cbNode)
712     {
713         if(isObserveNotification)
714         {
715             OC_LOG(INFO, TAG, PCF("Received an observe notification"));
716             //TODO: check the standard for methods to detect wrap around condition
717             if(cbNode->method == OC_REST_OBSERVE &&
718                     (response->clientResponse->sequenceNumber <= cbNode->sequenceNumber ||
719                             (response->clientResponse->sequenceNumber > cbNode->sequenceNumber &&
720                                     response->clientResponse->sequenceNumber ==
721                                             MAX_SEQUENCE_NUMBER)))
722             {
723                 OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
724                         Ignoring Incoming:%d  Against Current:%d.",
725                         response->clientResponse->sequenceNumber, cbNode->sequenceNumber);
726                 goto exit;
727             }
728             if(response->clientResponse->sequenceNumber > cbNode->sequenceNumber){
729                 cbNode->sequenceNumber = response->clientResponse->sequenceNumber;
730             }
731         }
732
733         response->clientResponse->resJSONPayload = bufRes;
734
735         cbResult = cbNode->callBack(cbNode->context, cbNode->handle, response->clientResponse);
736
737         if (cbResult == OC_STACK_DELETE_TRANSACTION ||
738                 response->clientResponse->result == OC_STACK_COMM_ERROR ||
739                 (response->clientResponse->result == OC_STACK_RESOURCE_DELETED &&
740                         !isPresenceNotification && !isMulticastPresence))
741         {
742             FindAndDeleteClientCB(cbNode);
743         }
744     }
745     else
746     {
747         result = OC_STACK_ERROR;
748     }
749
750     exit:
751     #ifdef WITH_PRESENCE
752     OCFree(resourceTypeName);
753     #endif
754     return result;
755 }
756
757 int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
758 {
759     size_t index = 0;
760     unsigned char *itr, *coap;
761     uint8_t dotCount = 0;
762
763     ipAddr[index] = 0;
764     *port = 0;
765     /* search for scheme */
766     itr = ipAddrStr;
767     if (!isdigit((unsigned char) *ipAddrStr))
768     {
769         coap = (unsigned char *) OC_COAP_SCHEME;
770         while (*coap && tolower(*itr) == *coap)
771         {
772             coap++;
773             itr++;
774         }
775     }
776     ipAddrStr = itr;
777
778     while (*ipAddrStr) {
779         if (isdigit((unsigned char) *ipAddrStr))
780         {
781             ipAddr[index] *= 10;
782             ipAddr[index] += *ipAddrStr - '0';
783         }
784         else if ((unsigned char) *ipAddrStr == '.')
785         {
786             index++;
787             dotCount++;
788             ipAddr[index] = 0;
789         }
790         else
791         {
792             break;
793         }
794         ipAddrStr++;
795     }
796     if(*ipAddrStr == ':')
797     {
798         ipAddrStr++;
799         while (*ipAddrStr){
800             if (isdigit((unsigned char) *ipAddrStr))
801             {
802                 *port *= 10;
803                 *port += *ipAddrStr - '0';
804             }
805             else
806             {
807                 break;
808             }
809             ipAddrStr++;
810         }
811     }
812
813
814     if (ipAddr[0] < 255 && ipAddr[1] < 255 && ipAddr[2] < 255 && ipAddr[3] < 255
815             && dotCount == 3)
816     {
817         return 1;
818     }
819     else
820     {
821         return 0;
822     }
823 }
824
825 //-----------------------------------------------------------------------------
826 // Private internal function prototypes
827 //-----------------------------------------------------------------------------
828
829 static OCDoHandle GenerateInvocationHandle();
830 static OCStackResult initResources();
831 static void insertResource(OCResource *resource);
832 static OCResource *findResource(OCResource *resource);
833 static void insertResourceType(OCResource *resource,
834         OCResourceType *resourceType);
835 static OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle,
836         uint8_t index);
837 static void insertResourceInterface(OCResource *resource,
838         OCResourceInterface *resourceInterface);
839 static OCResourceInterface *findResourceInterfaceAtIndex(
840         OCResourceHandle handle, uint8_t index);
841 static void deleteResourceType(OCResourceType *resourceType);
842 static void deleteResourceInterface(OCResourceInterface *resourceInterface);
843 static void deleteResourceElements(OCResource *resource);
844 static int deleteResource(OCResource *resource);
845 static void deleteAllResources();
846 static void incrementSequenceNumber(OCResource * resPtr);
847 static OCStackResult verifyUriQueryLength(const char * inputUri,
848         uint16_t uriLen);
849 static uint8_t OCIsPacketTransferRequired(const char *request, const char *response, uint16_t size);
850 OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI);
851
852 //-----------------------------------------------------------------------------
853 // Public APIs
854 //-----------------------------------------------------------------------------
855
856 /**
857  * Initialize the OC Stack.  Must be called prior to starting the stack.
858  *
859  * @param ipAddr
860  *     IP Address of host device
861  * @param port
862  *     Port of host device
863  * @param mode
864  *     Host device is client, server, or client-server
865  *
866  * @return
867  *     OC_STACK_OK    - no errors
868  *     OC_STACK_ERROR - stack init error
869  */
870 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
871 {
872     OCStackResult result = OC_STACK_ERROR;
873     OC_LOG(INFO, TAG, PCF("Entering OCInit"));
874
875     if (ipAddr)
876     {
877         OC_LOG_V(INFO, TAG, "IP Address = %s", ipAddr);
878     }
879 #ifdef CA_INT
880     CAInitialize();
881     //It is ok to select network to CA_WIFI for now
882     CAResult_t caResult = CASelectNetwork(CA_WIFI);
883     if(caResult == CA_STATUS_OK)
884     {
885         OC_LOG(INFO, TAG, PCF("CASelectNetwork to WIFI"));
886         caResult = CARegisterHandler(HandleCARequests, HandleCAResponses);
887         if(caResult == CA_STATUS_OK)
888         {
889             OC_LOG(INFO, TAG, PCF("CARegisterHandler..."));
890             stackState = OC_STACK_INITIALIZED;
891             result = OC_STACK_OK;
892             switch (mode)
893             {
894                 case OC_CLIENT:
895                     caResult = CAStartDiscoveryServer();
896                     OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
897                     break;
898                 case OC_SERVER:
899                     caResult = CAStartListeningServer();
900                     OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
901                     break;
902                 case OC_CLIENT_SERVER:
903                     caResult = CAStartListeningServer();
904                     if(caResult == CA_STATUS_OK)
905                     {
906                         caResult = CAStartDiscoveryServer();
907                     }
908                     OC_LOG(INFO, TAG, PCF("Client-server mode"));
909                     break;
910                 default:
911                     OC_LOG(ERROR, TAG, PCF("Invalid mode"));
912                     return OC_STACK_ERROR;
913                     break;
914             }
915
916         }
917         if (caResult == CA_STATUS_OK)
918         {
919             result = OC_STACK_OK;
920         }
921         else
922         {
923             result = OC_STACK_ERROR;
924         }
925     }
926 #else
927     switch (mode)
928     {
929     case OC_CLIENT:
930         OC_LOG(INFO, TAG, PCF("Client mode"));
931         break;
932     case OC_SERVER:
933         OC_LOG(INFO, TAG, PCF("Server mode"));
934         break;
935     case OC_CLIENT_SERVER:
936         OC_LOG(INFO, TAG, PCF("Client-server mode"));
937         break;
938     default:
939         OC_LOG(ERROR, TAG, PCF("Invalid mode"));
940         return OC_STACK_ERROR;
941         break;
942     }
943
944     // Make call to OCCoAP layer
945     result = OCInitCoAP(ipAddr, (uint16_t) port, myStackMode);
946 #endif //CA_INT
947
948     myStackMode = mode;
949     defaultDeviceHandler = NULL;
950
951 #ifdef WITH_PRESENCE
952     PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
953 #endif // WITH_PRESENCE
954
955     if (result == OC_STACK_OK)
956     {
957         stackState = OC_STACK_INITIALIZED;
958     }
959     // Initialize resource
960     if(result == OC_STACK_OK && myStackMode != OC_CLIENT)
961     {
962         result = initResources();
963     }
964     if(result != OC_STACK_OK)
965     {
966         OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
967     }
968     return result;
969 }
970
971 /**
972  * Stop the OC stack.  Use for a controlled shutdown.
973  * @return
974  *     OC_STACK_OK    - no errors
975  *     OC_STACK_ERROR - stack not initialized
976  */
977 OCStackResult OCStop()
978 {
979     OCStackResult result = OC_STACK_ERROR;
980
981     OC_LOG(INFO, TAG, PCF("Entering OCStop"));
982
983     if (stackState != OC_STACK_INITIALIZED)
984     {
985         OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
986         return OC_STACK_ERROR;
987     }
988
989     #ifdef WITH_PRESENCE
990     // Ensure that the TTL associated with ANY and ALL presence notifications originating from
991     // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
992     presenceResource.presenceTTL = 0;
993     #endif // WITH_PRESENCE
994
995     // Free memory dynamically allocated for resources
996     deleteAllResources();
997
998     // Make call to OCCoAP layer
999     if (OCStopCoAP() == OC_STACK_OK)
1000     {
1001         // Remove all observers
1002         DeleteObserverList();
1003         // Remove all the client callbacks
1004         DeleteClientCBList();
1005         stackState = OC_STACK_UNINITIALIZED;
1006         result = OC_STACK_OK;
1007     } else {
1008         result = OC_STACK_ERROR;
1009     }
1010
1011     // Deinit security blob
1012     DeinitOCSecurityInfo();
1013
1014     if (result != OC_STACK_OK) {
1015         OC_LOG(ERROR, TAG, PCF("Stack stop error"));
1016     }
1017
1018     return result;
1019 }
1020
1021 /**
1022  * Verify the lengths of the URI and the query separately
1023  *
1024  * @param inputUri       - Input URI and query.
1025  * @param uriLen         - The length of the initial URI with query.
1026  *
1027  * Note: The '?' that appears after the URI is not considered as
1028  * a part of the query.
1029  */
1030 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
1031 {
1032     char *query;
1033
1034     query = strchr (inputUri, '?');
1035
1036     if (query != NULL)
1037     {
1038         if((query - inputUri) > MAX_URI_LENGTH)
1039         {
1040             return OC_STACK_INVALID_URI;
1041         }
1042
1043         if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
1044         {
1045             return OC_STACK_INVALID_QUERY;
1046         }
1047     }
1048     else if(uriLen > MAX_URI_LENGTH)
1049     {
1050         return OC_STACK_INVALID_URI;
1051     }
1052     return OC_STACK_OK;
1053 }
1054
1055 /**
1056  * Discover or Perform requests on a specified resource (specified by that Resource's respective URI).
1057  *
1058  * @param handle             - @ref OCDoHandle to refer to the request sent out on behalf of calling this API.
1059  * @param method             - @ref OCMethod to perform on the resource
1060  * @param requiredUri        - URI of the resource to interact with
1061  * @param referenceUri       - URI of the reference resource
1062  * @param request            - JSON encoded request
1063  * @param qos                - quality of service
1064  * @param cbData             - struct that contains asynchronous callback function that is invoked
1065  *                             by the stack when discovery or resource interaction is complete
1066  * @param options            - The address of an array containing the vendor specific header
1067  *                             header options to be sent with the request
1068  * @param numOptions         - Number of vendor specific header options to be included
1069  *
1070  * @return
1071  *     OC_STACK_OK               - no errors
1072  *     OC_STACK_INVALID_CALLBACK - invalid callback function pointer
1073  *     OC_STACK_INVALID_METHOD   - invalid resource method
1074  *     OC_STACK_INVALID_URI      - invalid required or reference URI
1075  */
1076
1077 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
1078                            const char *referenceUri, const char *request,
1079                            OCQualityOfService qos, OCCallbackData *cbData,
1080                            OCHeaderOption * options, uint8_t numOptions)
1081 {
1082     OCStackResult result = OC_STACK_ERROR;
1083     OCCoAPToken token;
1084     ClientCB *clientCB = NULL;
1085     unsigned char * requestUri = NULL;
1086     unsigned char * resourceType = NULL;
1087     char * newUri = (char *)requiredUri;
1088     (void) referenceUri;
1089 #ifdef CA_INT
1090     CARemoteEndpoint_t* endpoint = NULL;
1091     CAResult_t caResult;
1092     CAToken_t caToken = NULL;
1093     CAInfo_t requestData;
1094     CARequestInfo_t requestInfo;
1095     // To track if memory is allocated for additional header options
1096     uint8_t hdrOptionMemAlloc = 0;
1097 #endif // CA_INT
1098
1099     OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
1100
1101     // Validate input parameters
1102     VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
1103     VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
1104
1105     TODO ("Need to form the final query by concatenating require and reference URI's");
1106     VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
1107
1108     uint16_t uriLen = strlen(requiredUri);
1109
1110     // ToDo: We should also check if the requiredUri has a mutlicast address, then qos has to be OC_Low_QOS
1111     switch (method)
1112     {
1113         case OC_REST_GET:
1114         case OC_REST_PUT:
1115         case OC_REST_POST:
1116         case OC_REST_DELETE:
1117         case OC_REST_OBSERVE:
1118         case OC_REST_OBSERVE_ALL:
1119         case OC_REST_CANCEL_OBSERVE:
1120             break;
1121         #ifdef WITH_PRESENCE
1122         case OC_REST_PRESENCE:
1123             break;
1124         #endif
1125         default:
1126             result = OC_STACK_INVALID_METHOD;
1127             goto exit;
1128     }
1129
1130     if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
1131     {
1132         goto exit;
1133     }
1134
1135     if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
1136     {
1137         result = OC_STACK_INVALID_PARAM;
1138         goto exit;
1139     }
1140
1141 #ifdef WITH_PRESENCE
1142     if(method == OC_REST_PRESENCE)
1143     {
1144         result = getResourceType(requiredUri, &resourceType, &newUri);
1145         if(resourceType) {
1146             OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
1147         }
1148         else
1149         {
1150             OC_LOG(DEBUG, TAG, PCF("Got Resource Type is NULL."));
1151         }
1152         if(result != OC_STACK_OK)
1153         {
1154             goto exit;
1155         }
1156     }
1157 #endif // WITH_PRESENCE
1158
1159     requestUri = (unsigned char *) OCMalloc(uriLen + 1);
1160     if(requestUri)
1161     {
1162         memcpy(requestUri, newUri, (uriLen + 1));
1163     }
1164     else
1165     {
1166         result = OC_STACK_NO_MEMORY;
1167         goto exit;
1168     }
1169
1170     *handle = GenerateInvocationHandle();
1171     if(!*handle)
1172     {
1173         result = OC_STACK_NO_MEMORY;
1174         goto exit;
1175     }
1176
1177 #ifdef CA_INT
1178     memset(&requestData, 0, sizeof(CAInfo_t));
1179     memset(&requestInfo, 0, sizeof(CARequestInfo_t));
1180     switch (method)
1181     {
1182         case OC_REST_GET:
1183         case OC_REST_OBSERVE:
1184         case OC_REST_OBSERVE_ALL:
1185         case OC_REST_CANCEL_OBSERVE:
1186             {
1187                 requestInfo.method = CA_GET;
1188                 break;
1189             }
1190         case OC_REST_PUT:
1191             {
1192                 requestInfo.method = CA_PUT;
1193                 break;
1194             }
1195         case OC_REST_POST:
1196             {
1197                 requestInfo.method = CA_POST;
1198                 break;
1199             }
1200         case OC_REST_DELETE:
1201             {
1202                 requestInfo.method = CA_DELETE;
1203                 break;
1204             }
1205         #ifdef WITH_PRESENCE
1206         case OC_REST_PRESENCE:
1207             //TODO-CA: What should be the CA method?
1208             break;
1209         #endif
1210         default:
1211             result = OC_STACK_INVALID_METHOD;
1212             goto exit;
1213     }
1214
1215     // TODO-CA: Handle multi-cast scenario
1216     // Create remote end point
1217     caResult = CACreateRemoteEndpoint(newUri, CA_WIFI, &endpoint);
1218     // TODO-CA: Connectivity type should be passed to API
1219     endpoint->connectivityType = CA_WIFI;
1220     if (caResult != CA_STATUS_OK)
1221     {
1222         OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
1223         goto exit;
1224     }
1225
1226     // create token
1227     caResult = CAGenerateToken(&caToken);
1228
1229     if (caResult != CA_STATUS_OK)
1230     {
1231         OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
1232         caToken = NULL;
1233         goto exit;
1234     }
1235
1236     // TODO-CA: Map QoS to the right CA msg type
1237     requestData.type = CA_MSG_NONCONFIRM;
1238     requestData.token = caToken;
1239     requestData.options = (CAHeaderOption_t*)options;
1240     requestData.numOptions = numOptions;
1241     requestData.payload = (char *)request;
1242
1243     requestInfo.info = requestData;
1244
1245     // send request
1246     caResult = CASendRequest(endpoint, &requestInfo);
1247     if (caResult != CA_STATUS_OK)
1248     {
1249         OC_LOG(ERROR, TAG, PCF("CASendRequest"));
1250         goto exit;
1251     }
1252
1253     if((result = AddClientCB(&clientCB, cbData, &caToken, handle, method,
1254                              requestUri, resourceType)) != OC_STACK_OK)
1255     {
1256         result = OC_STACK_NO_MEMORY;
1257         goto exit;
1258     }
1259
1260 #else // CA_INT
1261
1262     // Generate token which will be used by OCStack to match responses received
1263     // with the request
1264     OCGenerateCoAPToken(&token);
1265
1266     if((result = AddClientCB(&clientCB, cbData, &token, handle, method, requestUri, resourceType))
1267             != OC_STACK_OK)
1268     {
1269         result = OC_STACK_NO_MEMORY;
1270         goto exit;
1271     }
1272
1273 #ifdef WITH_PRESENCE
1274     if(method == OC_REST_PRESENCE)
1275     {
1276         // Replacing method type with GET because "presence" is a stack layer only implementation.
1277         method = OC_REST_GET;
1278     }
1279 #endif
1280
1281     // Make call to OCCoAP layer
1282     result = OCDoCoAPResource(method, qos, &token, newUri, request, options, numOptions);
1283 #endif // CA_INT
1284
1285 exit:
1286     if(newUri != requiredUri)
1287     {
1288         OCFree(newUri);
1289     }
1290     if (result != OC_STACK_OK)
1291     {
1292         OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
1293         FindAndDeleteClientCB(clientCB);
1294     }
1295 #ifdef CA_INT
1296     CADestroyRemoteEndpoint(endpoint);
1297     if (hdrOptionMemAlloc)
1298     {
1299         OCFree(requestData.options);
1300     }
1301     //TODO-CA: CADestroyToken here
1302 #endif // CA_INT
1303     return result;
1304 }
1305
1306 /**
1307  * Cancel a request associated with a specific @ref OCDoResource invocation.
1308  *
1309  * @param handle - Used to identify a specific OCDoResource invocation.
1310  * @param qos    - used to specify Quality of Service (read below for more info)
1311  * @param options- used to specify vendor specific header options when sending
1312  *                 explicit observe cancellation
1313  * @param numOptions- Number of header options to be included
1314  *
1315  * @return
1316  *     OC_STACK_OK               - No errors; Success
1317  *     OC_STACK_INVALID_PARAM    - The handle provided is invalid.
1318  */
1319 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
1320         uint8_t numOptions) {
1321     /*
1322      * This ftn is implemented one of two ways in the case of observation:
1323      *
1324      * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
1325      *      Remove the callback associated on client side.
1326      *      When the next notification comes in from server,
1327      *      reply with RESET message to server.
1328      *      Keep in mind that the server will react to RESET only
1329      *      if the last notification was sent ans CON
1330      *
1331      * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
1332      *      and it is associated with an observe request
1333      *      (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
1334      *      Send CON Observe request to server with
1335      *      observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
1336      *      Remove the callback associated on client side.
1337      */
1338     OCStackResult ret = OC_STACK_OK;
1339
1340     if(!handle) {
1341         return OC_STACK_INVALID_PARAM;
1342     }
1343
1344     OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
1345
1346     ClientCB *clientCB = GetClientCB(NULL, handle, NULL);
1347
1348     if(clientCB) {
1349         switch (clientCB->method)
1350         {
1351             case OC_REST_OBSERVE:
1352             case OC_REST_OBSERVE_ALL:
1353                 if(qos == OC_HIGH_QOS)
1354                 {
1355                     ret = OCDoCoAPResource(OC_REST_CANCEL_OBSERVE, qos,
1356                             &(clientCB->token), (const char *) clientCB->requestUri, NULL, options,
1357                             numOptions);
1358                 }
1359                 else
1360                 {
1361                     FindAndDeleteClientCB(clientCB);
1362                 }
1363                 break;
1364             #ifdef WITH_PRESENCE
1365             case OC_REST_PRESENCE:
1366                 FindAndDeleteClientCB(clientCB);
1367                 break;
1368             #endif
1369             default:
1370                 return OC_STACK_INVALID_METHOD;
1371         }
1372     }
1373     return ret;
1374 }
1375 #ifdef WITH_PRESENCE
1376 OCStackResult OCProcessPresence()
1377 {
1378     OCStackResult result = OC_STACK_OK;
1379     uint8_t ipAddr[4] = { 0 };
1380     uint16_t port = 0;
1381
1382     OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
1383     ClientCB* cbNode = NULL;
1384     OCDevAddr dst;
1385     OCClientResponse clientResponse;
1386     OCResponse * response = NULL;
1387
1388     LL_FOREACH(cbList, cbNode) {
1389         if(OC_REST_PRESENCE == cbNode->method)
1390         {
1391             if(cbNode->presence)
1392             {
1393                 uint32_t now = GetTime(0);
1394                 OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
1395                 OC_LOG_V(DEBUG, TAG, "----------------current ticks %d", now);
1396
1397
1398                 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
1399                 {
1400                     goto exit;
1401                 }
1402
1403                 if(cbNode->presence->TTLlevel < PresenceTimeOutSize){
1404                     OC_LOG_V(DEBUG, TAG, "----------------timeout ticks %d",
1405                             cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
1406                 }
1407
1408                 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
1409                 {
1410                     OC_LOG(DEBUG, TAG, PCF("----------------No more timeout ticks"));
1411                     if (ParseIPv4Address( cbNode->requestUri, ipAddr, &port))
1412                     {
1413                         OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
1414                                 &dst);
1415                         result = FormOCClientResponse(&clientResponse, OC_STACK_PRESENCE_TIMEOUT,
1416                                 (OCDevAddr *) &dst, 0, NULL);
1417                         if(result != OC_STACK_OK)
1418                         {
1419                             goto exit;
1420                         }
1421                         result = FormOCResponse(&response, cbNode, 0, NULL, NULL,
1422                                 &cbNode->token, &clientResponse, NULL);
1423                         if(result != OC_STACK_OK)
1424                         {
1425                             goto exit;
1426                         }
1427
1428                         // Increment the TTLLevel (going to a next state), so we don't keep
1429                         // sending presence notification to client.
1430                         cbNode->presence->TTLlevel++;
1431                         OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d",
1432                                                 cbNode->presence->TTLlevel);
1433                     }
1434                     else
1435                     {
1436                         result = OC_STACK_INVALID_IP;
1437                         goto exit;
1438                     }
1439                     HandleStackResponses(response);
1440                 }
1441                 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
1442                 {
1443                     OC_LOG(DEBUG, TAG, PCF("time to test server presence =========="));
1444                     OCCoAPToken token;
1445                     OCGenerateCoAPToken(&token);
1446                     result = OCDoCoAPResource(OC_REST_GET, OC_LOW_QOS,
1447                             &token, (const char *)cbNode->requestUri, NULL, NULL, 0);
1448                     if(result != OC_STACK_OK)
1449                     {
1450                         goto exit;
1451                     }
1452                     cbNode->presence->TTLlevel++;
1453                     OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d", cbNode->presence->TTLlevel);
1454                 }
1455             }
1456         }
1457     }
1458 exit:
1459     if (result != OC_STACK_OK)
1460     {
1461         OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
1462     }
1463     return result;
1464 }
1465 #endif
1466
1467 /**
1468  * Called in main loop of OC client or server.  Allows low-level processing of
1469  * stack services.
1470  *
1471  * @return
1472  *     OC_STACK_OK    - no errors
1473  *     OC_STACK_ERROR - stack process error
1474  */
1475 OCStackResult OCProcess() {
1476
1477     OC_LOG(INFO, TAG, PCF("Entering OCProcess"));
1478     #ifdef WITH_PRESENCE
1479     OCProcessPresence();
1480     #endif
1481 #ifdef CA_INT
1482     CAHandleRequestResponse();
1483 #else
1484     OCProcessCoAP();
1485 #endif // CA_INT
1486
1487     return OC_STACK_OK;
1488 }
1489
1490 #ifdef WITH_PRESENCE
1491 /**
1492  * When operating in @ref OCServer or @ref OCClientServer mode, this API will start sending out
1493  * presence notifications to clients via multicast. Once this API has been called with a success,
1494  * clients may query for this server's presence and this server's stack will respond via multicast.
1495  *
1496  * Server can call this function when it comes online for the first time, or when it comes back
1497  * online from offline mode, or when it re enters network.
1498  *
1499  * @param ttl - Time To Live in seconds
1500  * Note: If ttl is '0', then the default stack value will be used (60 Seconds).
1501  *
1502  * @return
1503  *     OC_STACK_OK      - No errors; Success
1504  */
1505 OCStackResult OCStartPresence(const uint32_t ttl)
1506 {
1507     OCChangeResourceProperty(
1508             &(((OCResource *)presenceResource.handle)->resourceProperties),
1509             OC_ACTIVE, 1);
1510
1511     if(ttl > 0)
1512     {
1513         presenceResource.presenceTTL = ttl;
1514     }
1515
1516     if(OC_PRESENCE_UNINITIALIZED == presenceState)
1517     {
1518         OCDevAddr multiCastAddr;
1519         OCCoAPToken token;
1520
1521         presenceState = OC_PRESENCE_INITIALIZED;
1522         OCGenerateCoAPToken(&token);
1523         OCBuildIPv4Address(224, 0, 1, 187, 5683, &multiCastAddr);
1524         //add the presence observer
1525         AddObserver(OC_PRESENCE_URI, NULL, 0, &token, &multiCastAddr,
1526             (OCResource *)presenceResource.handle, OC_LOW_QOS);
1527     }
1528
1529     // Each time OCStartPresence is called
1530     // a different random 32-bit integer number is used
1531     ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1532
1533     return SendPresenceNotification(NULL);
1534 }
1535
1536 /**
1537  * When operating in @ref OCServer or @ref OCClientServer mode, this API will stop sending out
1538  * presence notifications to clients via multicast. Once this API has been called with a success,
1539  * this server's stack will not respond to clients querying for this server's presence.
1540  *
1541  * Server can call this function when it is terminating, going offline, or when going
1542  * away from network.
1543  *
1544  * @return
1545  *     OC_STACK_OK      - No errors; Success
1546  */
1547 OCStackResult OCStopPresence()
1548 {
1549     OCStackResult result = OC_STACK_ERROR;
1550     //make resource inactive
1551     result = OCChangeResourceProperty(
1552             &(((OCResource *) presenceResource.handle)->resourceProperties),
1553             OC_ACTIVE, 0);
1554     result = SendPresenceNotification(NULL);
1555
1556     return result;
1557 }
1558 #endif
1559
1560
1561 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
1562 {
1563     defaultDeviceHandler = entityHandler;
1564
1565     return OC_STACK_OK;
1566 }
1567
1568 /**
1569  * Create a resource
1570  *
1571  * @param handle - pointer to handle to newly created resource.  Set by ocstack.  Used to refer to resource
1572  * @param resourceTypeName - name of resource type.  Example: "core.led"
1573  * @param resourceInterfaceName - name of resource interface.  Example: "core.rw"
1574  * @param uri - URI of the resource.  Example:  "/a/led"
1575  * @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
1576  *                        NULL for default entity handler
1577  * @param resourceProperties - properties supported by resource.  Example: OC_DISCOVERABLE|OC_OBSERVABLE
1578  *
1579  * @return
1580  *     OC_STACK_OK    - no errors
1581  *     OC_STACK_ERROR - stack process error
1582  */
1583 OCStackResult OCCreateResource(OCResourceHandle *handle,
1584         const char *resourceTypeName,
1585         const char *resourceInterfaceName,
1586         const char *uri, OCEntityHandler entityHandler,
1587         uint8_t resourceProperties) {
1588
1589     OCResource *pointer = NULL;
1590     char *str = NULL;
1591     size_t size;
1592     OCStackResult result = OC_STACK_ERROR;
1593
1594     OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
1595
1596     if(myStackMode == OC_CLIENT)
1597     {
1598         return result;
1599     }
1600     // Validate parameters
1601     // Is it presented during resource discovery?
1602     if (!handle || !resourceTypeName || !uri) {
1603         OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
1604         return OC_STACK_INVALID_PARAM;
1605     }
1606
1607     if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0) {
1608         resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
1609     }
1610
1611     // Make sure resourceProperties bitmask has allowed properties specified
1612     if (resourceProperties
1613             > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE)) {
1614         OC_LOG(ERROR, TAG, PCF("Invalid property"));
1615         return OC_STACK_INVALID_PARAM;
1616     }
1617
1618     // If the headResource is NULL, then no resources have been created...
1619     pointer = headResource;
1620     if (pointer) {
1621         // At least one resources is in the resource list, so we need to search for
1622         // repeated URLs, which are not allowed.  If a repeat is found, exit with an error
1623         while (pointer) {
1624             if (strcmp(uri, pointer->uri) == 0) {
1625                 OC_LOG(ERROR, TAG, PCF("URI already in use"));
1626                 return OC_STACK_INVALID_PARAM;
1627             }
1628             pointer = pointer->next;
1629         }
1630     }
1631     // Create the pointer and insert it into the resource list
1632     pointer = (OCResource *) OCCalloc(1, sizeof(OCResource));
1633     if (!pointer) {
1634         goto exit;
1635     }
1636     pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
1637
1638     insertResource(pointer);
1639
1640     // Set the uri
1641     size = strlen(uri) + 1;
1642     str = (char *) OCMalloc(size);
1643     if (!str) {
1644         goto exit;
1645     }
1646     strncpy(str, uri, size);
1647     pointer->uri = str;
1648
1649     // Set properties.  Set OC_ACTIVE
1650     pointer->resourceProperties = (OCResourceProperty) (resourceProperties
1651             | OC_ACTIVE);
1652
1653     // Add the resourcetype to the resource
1654     result = BindResourceTypeToResource(pointer, resourceTypeName);
1655     if (result != OC_STACK_OK) {
1656         OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
1657         goto exit;
1658     }
1659
1660     // Add the resourceinterface to the resource
1661     result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
1662     if (result != OC_STACK_OK) {
1663         OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
1664         goto exit;
1665     }
1666
1667     // If an entity handler has been passed, attach it to the newly created
1668     // resource.  Otherwise, set the default entity handler.
1669     if (entityHandler)
1670     {
1671         pointer->entityHandler = entityHandler;
1672     }
1673     else
1674     {
1675         pointer->entityHandler = defaultResourceEHandler;
1676     }
1677
1678     *handle = pointer;
1679     result = OC_STACK_OK;
1680
1681     #ifdef WITH_PRESENCE
1682     if(presenceResource.handle)
1683     {
1684         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1685         SendPresenceNotification(pointer->rsrcType);
1686     }
1687     #endif
1688 exit:
1689     if (result != OC_STACK_OK)
1690     {
1691         // Deep delete of resource and other dynamic elements that it contains
1692         deleteResource(pointer);
1693         OCFree(str);
1694     }
1695     return result;
1696 }
1697
1698
1699
1700 /**
1701  * Create a resource. with host ip address for remote resource
1702  *
1703  * @param handle - pointer to handle to newly created resource.  Set by ocstack.
1704  *                 Used to refer to resource
1705  * @param resourceTypeName - name of resource type.  Example: "core.led"
1706  * @param resourceInterfaceName - name of resource interface.  Example: "core.rw"
1707  * @param host - HOST address of the remote resource.  Example:  "coap://xxx.xxx.xxx.xxx:xxxxx"
1708  * @param uri - URI of the resource.  Example:  "/a/led"
1709  * @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
1710  *                        NULL for default entity handler
1711  * @param resourceProperties - properties supported by resource.
1712  *                             Example: OC_DISCOVERABLE|OC_OBSERVABLE
1713  *
1714  * @return
1715  *     OC_STACK_OK    - no errors
1716  *     OC_STACK_ERROR - stack process error
1717  */
1718
1719 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
1720         const char *resourceTypeName,
1721         const char *resourceInterfaceName,
1722         const char *host,
1723         const char *uri,
1724         OCEntityHandler entityHandler,
1725         uint8_t resourceProperties)
1726 {
1727     char *str = NULL;
1728     size_t size;
1729     OCStackResult result = OC_STACK_ERROR;
1730
1731     result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
1732                                 uri, entityHandler, resourceProperties);
1733
1734     if (result != OC_STACK_ERROR)
1735     {
1736         // Set the uri
1737         size = strlen(host) + 1;
1738         str = (char *) OCMalloc(size);
1739         if (!str)
1740         {
1741             return OC_STACK_ERROR;
1742         }
1743         strncpy(str, host, size);
1744         ((OCResource *) *handle)->host = str;
1745     }
1746
1747     return result;
1748 }
1749
1750 /**
1751  * Add a resource to a collection resource.
1752  *
1753  * @param collectionHandle - handle to the collection resource
1754  * @param resourceHandle - handle to resource to be added to the collection resource
1755  *
1756  * @return
1757  *     OC_STACK_OK    - no errors
1758  *     OC_STACK_ERROR - stack process error
1759  *     OC_STACK_INVALID_PARAM - invalid collectionhandle
1760  */
1761 OCStackResult OCBindResource(
1762         OCResourceHandle collectionHandle, OCResourceHandle resourceHandle) {
1763     OCResource *resource;
1764     uint8_t i;
1765
1766     OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
1767
1768     // Validate parameters
1769     VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
1770     VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
1771     // Container cannot contain itself
1772     if (collectionHandle == resourceHandle) {
1773         OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
1774         return OC_STACK_INVALID_PARAM;
1775     }
1776
1777     // Use the handle to find the resource in the resource linked list
1778     resource = findResource((OCResource *) collectionHandle);
1779     if (!resource) {
1780         OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
1781         return OC_STACK_INVALID_PARAM;
1782     }
1783
1784     // Look for an open slot to add add the child resource.
1785     // If found, add it and return success
1786     for (i = 0; i < MAX_CONTAINED_RESOURCES; i++) {
1787         if (!resource->rsrcResources[i]) {
1788             resource->rsrcResources[i] = (OCResource *) resourceHandle;
1789             OC_LOG(INFO, TAG, PCF("resource bound"));
1790             return OC_STACK_OK;
1791         }
1792     }
1793
1794     #ifdef WITH_PRESENCE
1795     if(presenceResource.handle)
1796     {
1797         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1798         SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
1799     }
1800     #endif
1801
1802     // Unable to add resourceHandle, so return error
1803     return OC_STACK_ERROR;
1804 }
1805
1806 /**
1807  * Remove a resource from a collection resource.
1808  *
1809  * @param collectionHandle - handle to the collection resource
1810  * @param resourceHandle - handle to resource to be added to the collection resource
1811  *
1812  * @return
1813  *     OC_STACK_OK    - no errors
1814  *     OC_STACK_ERROR - stack process error
1815  *     OC_STACK_INVALID_PARAM - invalid collectionHandle
1816  */
1817 OCStackResult OCUnBindResource(
1818         OCResourceHandle collectionHandle, OCResourceHandle resourceHandle) {
1819     OCResource *resource;
1820     uint8_t i;
1821
1822     OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
1823
1824     // Validate parameters
1825     VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
1826     VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
1827     // Container cannot contain itself
1828     if (collectionHandle == resourceHandle) {
1829         OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
1830         return OC_STACK_INVALID_PARAM;
1831     }
1832
1833     // Use the handle to find the resource in the resource linked list
1834     resource = findResource((OCResource *) collectionHandle);
1835     if (!resource) {
1836         OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
1837         return OC_STACK_INVALID_PARAM;
1838     }
1839
1840     // Look for an open slot to add add the child resource.
1841     // If found, add it and return success
1842     for (i = 0; i < MAX_CONTAINED_RESOURCES; i++) {
1843         if (resourceHandle == resource->rsrcResources[i]) {
1844             resource->rsrcResources[i] = (OCResource *) NULL;
1845             OC_LOG(INFO, TAG, PCF("resource unbound"));
1846             return OC_STACK_OK;
1847         }
1848     }
1849
1850     OC_LOG(INFO, TAG, PCF("resource not found in collection"));
1851
1852     #ifdef WITH_PRESENCE
1853     if(presenceResource.handle)
1854     {
1855         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1856         SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
1857     }
1858     #endif
1859
1860     // Unable to add resourceHandle, so return error
1861     return OC_STACK_ERROR;
1862 }
1863
1864 OCStackResult BindResourceTypeToResource(OCResource* resource,
1865                                             const char *resourceTypeName)
1866 {
1867     OCResourceType *pointer = NULL;
1868     char *str = NULL;
1869     size_t size;
1870     OCStackResult result = OC_STACK_ERROR;
1871
1872     OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
1873
1874     // Validate parameters
1875     VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
1876     // TODO:  Does resource attribute resentation really have to be maintained in stack?
1877     // Is it presented during resource discovery?
1878
1879     TODO ("Make sure that the resourcetypename doesn't already exist in the resource");
1880
1881     // Create the resourcetype and insert it into the resource list
1882     pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
1883     if (!pointer) {
1884         goto exit;
1885     }
1886
1887     // Set the resourceTypeName
1888     size = strlen(resourceTypeName) + 1;
1889     str = (char *) OCMalloc(size);
1890     if (!str) {
1891         goto exit;
1892     }
1893     strncpy(str, resourceTypeName, size);
1894     pointer->resourcetypename = str;
1895
1896     insertResourceType(resource, pointer);
1897     result = OC_STACK_OK;
1898
1899     exit: if (result != OC_STACK_OK) {
1900         OCFree(pointer);
1901         OCFree(str);
1902     }
1903
1904     return result;
1905 }
1906
1907 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
1908         const char *resourceInterfaceName)
1909 {
1910     OCResourceInterface *pointer = NULL;
1911     char *str = NULL;
1912     size_t size;
1913     OCStackResult result = OC_STACK_ERROR;
1914
1915     OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
1916
1917     // Validate parameters
1918     VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
1919
1920     TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
1921
1922     // Create the resourceinterface and insert it into the resource list
1923     pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
1924     if (!pointer) {
1925         goto exit;
1926     }
1927
1928     // Set the resourceinterface name
1929     size = strlen(resourceInterfaceName) + 1;
1930     str = (char *) OCMalloc(size);
1931     if (!str) {
1932         goto exit;
1933     }
1934     strncpy(str, resourceInterfaceName, size);
1935     pointer->name = str;
1936
1937     // Bind the resourceinterface to the resource
1938     insertResourceInterface(resource, pointer);
1939
1940     result = OC_STACK_OK;
1941
1942     exit: if (result != OC_STACK_OK) {
1943         OCFree(pointer);
1944         OCFree(str);
1945     }
1946
1947     return result;
1948 }
1949
1950 /**
1951  * Bind a resourcetype to a resource.
1952  *
1953  * @param handle - handle to the resource
1954  * @param resourceTypeName - name of resource type.  Example: "core.led"
1955  *
1956  * @return
1957  *     OC_STACK_OK    - no errors
1958  *     OC_STACK_ERROR - stack process error
1959  */
1960 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
1961         const char *resourceTypeName) {
1962
1963     OCStackResult result = OC_STACK_ERROR;
1964     OCResource *resource;
1965
1966     // Make sure resource exists
1967     resource = findResource((OCResource *) handle);
1968     if (!resource) {
1969         OC_LOG(ERROR, TAG, PCF("Resource not found"));
1970         return OC_STACK_ERROR;
1971     }
1972
1973     // call internal function
1974     result = BindResourceTypeToResource(resource, resourceTypeName);
1975
1976     #ifdef WITH_PRESENCE
1977     if(presenceResource.handle)
1978     {
1979         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1980         SendPresenceNotification(resource->rsrcType);
1981     }
1982     #endif
1983
1984     return result;
1985 }
1986
1987 /**
1988  * Bind a resourceinterface to a resource.
1989  *
1990  * @param handle - handle to the resource
1991  * @param resourceInterfaceName - name of resource interface.  Example: "oc.mi.b"
1992  *
1993  * @return
1994  *     OC_STACK_OK    - no errors
1995  *     OC_STACK_ERROR - stack process error
1996  */
1997
1998 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
1999         const char *resourceInterfaceName) {
2000
2001     OCStackResult result = OC_STACK_ERROR;
2002     OCResource *resource;
2003
2004     // Make sure resource exists
2005     resource = findResource((OCResource *) handle);
2006     if (!resource) {
2007         OC_LOG(ERROR, TAG, PCF("Resource not found"));
2008         return OC_STACK_ERROR;
2009     }
2010
2011     // call internal function
2012     result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
2013
2014     #ifdef WITH_PRESENCE
2015     if(presenceResource.handle)
2016     {
2017         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2018         SendPresenceNotification(resource->rsrcType);
2019     }
2020     #endif
2021
2022     return result;
2023 }
2024
2025 /**
2026  * Get the number of resources that have been created in the stack.
2027  *
2028  * @param numResources - pointer to count variable
2029  *
2030  * @return
2031  *     OC_STACK_OK    - no errors
2032  *     OC_STACK_ERROR - stack process error
2033
2034  */
2035 OCStackResult OCGetNumberOfResources(uint8_t *numResources) {
2036     OCResource *pointer = headResource;
2037
2038     OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
2039     VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
2040     *numResources = 0;
2041     while (pointer) {
2042         *numResources = *numResources + 1;
2043         pointer = pointer->next;
2044     }
2045     return OC_STACK_OK;
2046 }
2047
2048 /**
2049  * Get a resource handle by index.
2050  *
2051  * @param index - index of resource, 0 to Count - 1
2052  *
2053  * @return
2054  *    Resource handle - if found
2055  *    NULL - if not found
2056  */
2057 OCResourceHandle OCGetResourceHandle(uint8_t index) {
2058     OCResource *pointer = headResource;
2059     uint8_t i = 0;
2060
2061     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
2062
2063     // Iterate through the list
2064     while ((i < index) && pointer) {
2065         i++;
2066         pointer = pointer->next;
2067     }
2068     return (OCResourceHandle) pointer;
2069 }
2070
2071 /**
2072  * Delete resource specified by handle.  Deletes resource and all resourcetype and resourceinterface
2073  * linked lists.
2074  *
2075  * @param handle - handle of resource to be deleted
2076  *
2077  * @return
2078  *     OC_STACK_OK              - no errors
2079  *     OC_STACK_ERROR           - stack process error
2080  *     OC_STACK_NO_RESOURCE     - resource not found
2081  *     OC_STACK_INVALID_PARAM   - invalid param
2082  */
2083 OCStackResult OCDeleteResource(OCResourceHandle handle) {
2084     OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
2085
2086     if (!handle) {
2087         OC_LOG(ERROR, TAG, PCF("Invalid param"));
2088         return OC_STACK_INVALID_PARAM;
2089     }
2090
2091     OCResource *resource = findResource((OCResource *) handle);
2092     if (resource == NULL) {
2093         OC_LOG(ERROR, TAG, PCF("Resource not found"));
2094         return OC_STACK_NO_RESOURCE;
2095     }
2096
2097     if (deleteResource((OCResource *) handle) == 0) {
2098         OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
2099         return OC_STACK_ERROR;
2100     }
2101
2102     return OC_STACK_OK;
2103 }
2104
2105 /**
2106  * Get the URI of the resource specified by handle.
2107  *
2108  * @param handle - handle of resource
2109  * @return
2110  *    URI string - if resource found
2111  *    NULL - resource not found
2112  */
2113 const char *OCGetResourceUri(OCResourceHandle handle) {
2114     OCResource *resource;
2115     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
2116
2117     resource = findResource((OCResource *) handle);
2118     if (resource) {
2119         return resource->uri;
2120     }
2121     return (const char *) NULL;
2122 }
2123
2124 /**
2125  * Get the properties of the resource specified by handle.
2126  * NOTE: that after a resource is created, the OC_ACTIVE property is set
2127  * for the resource by the stack.
2128  *
2129  * @param handle - handle of resource
2130  * @return
2131  *    property bitmap - if resource found
2132  *    NULL - resource not found
2133  */
2134 uint8_t OCGetResourceProperties(OCResourceHandle handle) {
2135     OCResource *resource;
2136     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
2137
2138     resource = findResource((OCResource *) handle);
2139     if (resource) {
2140         return resource->resourceProperties;
2141     }
2142     return 0;
2143 }
2144
2145 /**
2146  * Get the number of resource types of the resource.
2147  *
2148  * @param handle - handle of resource
2149  * @param numResourceTypes - pointer to count variable
2150  *
2151  * @return
2152  *     OC_STACK_OK    - no errors
2153  *     OC_STACK_ERROR - stack process error
2154  */
2155 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
2156         uint8_t *numResourceTypes) {
2157     OCResource *resource;
2158     OCResourceType *pointer;
2159
2160     OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
2161     VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
2162     VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2163
2164     *numResourceTypes = 0;
2165
2166     resource = findResource((OCResource *) handle);
2167     if (resource) {
2168         pointer = resource->rsrcType;
2169         while (pointer) {
2170             *numResourceTypes = *numResourceTypes + 1;
2171             pointer = pointer->next;
2172         }
2173     }
2174     return OC_STACK_OK;
2175 }
2176
2177 /**
2178  * Get name of resource type of the resource.
2179  *
2180  * @param handle - handle of resource
2181  * @param index - index of resource, 0 to Count - 1
2182  *
2183  * @return
2184  *    resource type name - if resource found
2185  *    NULL - resource not found
2186  */
2187 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index) {
2188     OCResourceType *resourceType;
2189
2190     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
2191
2192     resourceType = findResourceTypeAtIndex(handle, index);
2193     if (resourceType) {
2194         return resourceType->resourcetypename;
2195     }
2196     return (const char *) NULL;
2197 }
2198
2199
2200
2201 /**
2202  * Get the number of resource interfaces of the resource.
2203  *
2204  * @param handle - handle of resource
2205  * @param numResources - pointer to count variable
2206  *
2207  * @return
2208  *     OC_STACK_OK    - no errors
2209  *     OC_STACK_ERROR - stack process error
2210  */
2211 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
2212         uint8_t *numResourceInterfaces) {
2213     OCResourceInterface *pointer;
2214     OCResource *resource;
2215
2216     OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
2217
2218     VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2219     VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
2220
2221     *numResourceInterfaces = 0;
2222     resource = findResource((OCResource *) handle);
2223     if (resource) {
2224         pointer = resource->rsrcInterface;
2225         while (pointer) {
2226             *numResourceInterfaces = *numResourceInterfaces + 1;
2227             pointer = pointer->next;
2228         }
2229     }
2230     return OC_STACK_OK;
2231 }
2232
2233 /**
2234  * Get name of resource interface of the resource.
2235  *
2236  * @param handle - handle of resource
2237  * @param index - index of resource, 0 to Count - 1
2238  *
2239  * @return
2240  *    resource interface name - if resource found
2241  *    NULL - resource not found
2242  */
2243 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index) {
2244     OCResourceInterface *resourceInterface;
2245
2246     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
2247
2248     resourceInterface = findResourceInterfaceAtIndex(handle, index);
2249     if (resourceInterface) {
2250         return resourceInterface->name;
2251     }
2252     return (const char *) NULL;
2253 }
2254
2255 /**
2256  * Get resource handle from the collection resource by index.
2257  *
2258  * @param collectionHandle - handle of collection resource
2259  * @param index - index of contained resource, 0 to Count - 1
2260  *
2261  * @return
2262  *    handle to resource - if resource found
2263  *    NULL - resource not found
2264  */
2265 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
2266         uint8_t index) {
2267     OCResource *resource;
2268
2269     OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
2270
2271     if (index >= MAX_CONTAINED_RESOURCES) {
2272         return NULL;
2273     }
2274
2275     resource = findResource((OCResource *) collectionHandle);
2276     if (!resource) {
2277         return NULL;
2278     }
2279
2280     return resource->rsrcResources[index];
2281 }
2282
2283 /**
2284  * Bind an entity handler to the resource.
2285  *
2286  * @param handle - handle to the resource that the contained resource is to be bound
2287  * @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
2288  * @return
2289  *     OC_STACK_OK    - no errors
2290  *     OC_STACK_ERROR - stack process error
2291  */
2292 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
2293         OCEntityHandler entityHandler) {
2294     OCResource *resource;
2295
2296     OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
2297
2298     // Validate parameters
2299     VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2300     //VERIFY_NON_NULL(entityHandler, ERROR, OC_STACK_INVALID_PARAM);
2301
2302     // Use the handle to find the resource in the resource linked list
2303     resource = findResource((OCResource *)handle);
2304     if (!resource) {
2305         OC_LOG(ERROR, TAG, PCF("Resource not found"));
2306         return OC_STACK_ERROR;
2307     }
2308
2309     // Bind the handler
2310     resource->entityHandler = entityHandler;
2311
2312     #ifdef WITH_PRESENCE
2313     if(presenceResource.handle)
2314     {
2315         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2316         SendPresenceNotification(resource->rsrcType);
2317     }
2318     #endif
2319
2320     return OC_STACK_OK;
2321 }
2322
2323 /**
2324  * Get the entity handler for a resource.
2325  *
2326  * @param handle - handle of resource
2327  *
2328  * @return
2329  *    entity handler - if resource found
2330  *    NULL - resource not found
2331  */
2332 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) {
2333     OCResource *resource;
2334
2335     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
2336
2337     // Use the handle to find the resource in the resource linked list
2338     resource = findResource((OCResource *)handle);
2339     if (!resource) {
2340         OC_LOG(ERROR, TAG, PCF("Resource not found"));
2341         return NULL;
2342     }
2343
2344     // Bind the handler
2345     return resource->entityHandler;
2346 }
2347
2348 void incrementSequenceNumber(OCResource * resPtr)
2349 {
2350     // Increment the sequence number
2351     resPtr->sequenceNum += 1;
2352     if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
2353     {
2354         resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
2355     }
2356     return;
2357 }
2358
2359 /**
2360  * Notify Presence subscribers that a resource has been modified
2361  *
2362  * @param resourceType - Handle to the resourceType linked list of resource
2363  *                       that was modified.
2364  * @param qos          - Quality Of Service
2365  *
2366  */
2367 #ifdef WITH_PRESENCE
2368 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
2369 {
2370     OCResource *resPtr = NULL;
2371     OCStackResult result;
2372     OCMethod method = OC_REST_PRESENCE;
2373     uint32_t maxAge = 0;
2374     resPtr = findResource((OCResource *) presenceResource.handle);
2375     if(NULL == resPtr)
2376     {
2377         return OC_STACK_NO_RESOURCE;
2378     }
2379     if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
2380     {
2381         maxAge = presenceResource.presenceTTL;
2382     }
2383     else
2384     {
2385         maxAge = 0;
2386     }
2387
2388     result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
2389     return result;
2390 }
2391 #endif // WITH_PRESENCE
2392 /**
2393  * Notify observers that an observed value has changed.
2394  *
2395  * @param handle - handle of resource
2396  *
2397  * @return
2398  *     OC_STACK_OK    - no errors
2399  *     OC_STACK_NO_RESOURCE - invalid resource handle
2400  *     OC_STACK_NO_OBSERVERS - no more observers intrested in resource
2401  */
2402 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos) {
2403
2404     OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
2405
2406     OCResource *resPtr = NULL;
2407     OCStackResult result;
2408     OCMethod method = OC_REST_NOMETHOD;
2409     uint32_t maxAge = 0;
2410
2411     OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
2412     #ifdef WITH_PRESENCE
2413     if(handle == presenceResource.handle)
2414     {
2415         return OC_STACK_OK;
2416     }
2417     #endif // WITH_PRESENCE
2418     VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
2419
2420     // Verify that the resource exists
2421     resPtr = findResource ((OCResource *) handle);
2422     if (NULL == resPtr)
2423     {
2424         return OC_STACK_NO_RESOURCE;
2425     }
2426     else
2427     {
2428         //only increment in the case of regular observing (not presence)
2429         incrementSequenceNumber(resPtr);
2430         method = OC_REST_OBSERVE;
2431         maxAge = MAX_OBSERVE_AGE;
2432         #ifdef WITH_PRESENCE
2433         result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
2434         #else
2435         result = SendAllObserverNotification (method, resPtr, maxAge, qos);
2436         #endif
2437         return result;
2438     }
2439 }
2440
2441 OCStackResult
2442 OCNotifyListOfObservers (OCResourceHandle handle,
2443                          OCObservationId  *obsIdList,
2444                          uint8_t          numberOfIds,
2445                          unsigned char    *notificationJSONPayload,
2446                          OCQualityOfService qos)
2447 {
2448     OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
2449
2450     OCResource *resPtr = NULL;
2451     //TODO: we should allow the server to define this
2452     uint32_t maxAge = MAX_OBSERVE_AGE;
2453
2454     VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
2455     VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
2456     VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
2457
2458     // Verify that the resource exists
2459     resPtr = findResource ((OCResource *) handle);
2460     if (NULL == resPtr || myStackMode == OC_CLIENT)
2461     {
2462         return OC_STACK_NO_RESOURCE;
2463     }
2464     else
2465     {
2466         incrementSequenceNumber(resPtr);
2467     }
2468     return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
2469             notificationJSONPayload, maxAge, qos));
2470 }
2471
2472 /**
2473  * Send a response to a request.
2474  * The response can be a regular, slow, or block (i.e. a response that
2475  * is too large to be sent in a single PDU and must span multiple transmissions)
2476  *
2477  * @param response - pointer to structure that contains response parameters
2478  *
2479  * @return
2480  *     OC_STACK_OK                         - No errors; Success
2481  *     OC_STACK_INVALID_PARAM              - Invalid pointer to OCServerResponse
2482  *     OC_STACK_INVALID_REQUEST_HANDLE     - Request handle not found
2483  *     OC_STACK_PERSISTENT_BUFFER_REQUIRED - Block transfer needed for response, so a
2484  *                                           persistent response buffer is necessary
2485  */
2486 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
2487 {
2488     OCStackResult result = OC_STACK_ERROR;
2489     OCServerRequest *serverRequest = NULL;
2490
2491     OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
2492
2493     // Validate input parameters
2494     VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
2495     VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
2496
2497     // TODO: Placeholder for creating a response entry when implementing
2498     // block transfer feature
2499
2500     // If a response payload is present, check if block transfer is required
2501     if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
2502             (const char *)ehResponse->payload, ehResponse->payloadSize))
2503     {
2504         OC_LOG(INFO, TAG, PCF("Block transfer required"));
2505
2506         // Persistent response buffer is needed for block transfer
2507         if (!ehResponse->persistentBufferFlag)
2508         {
2509             OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
2510             return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
2511         }
2512         // TODO: Placeholder for block transfer handling
2513         // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
2514             // when implementing the block transfer feature
2515     }
2516     else
2517     {
2518         // Normal response
2519
2520         // Get pointer to request info
2521         serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
2522         if(serverRequest)
2523         {
2524             result = serverRequest->ehResponseHandler(ehResponse);
2525         }
2526     }
2527     return result;
2528 }
2529
2530 /**
2531  * Cancel a response.  Applies to a block response
2532  *
2533  * @param responseHandle - response handle set by stack in OCServerResponse after
2534  *                         OCDoResponse is called
2535  *
2536  * @return
2537  *     OC_STACK_OK               - No errors; Success
2538  *     OC_STACK_INVALID_PARAM    - The handle provided is invalid.
2539  */
2540 OCStackResult OCCancelResponse(OCResponseHandle responseHandle)
2541 {
2542     OCStackResult result = OC_STACK_NOTIMPL;
2543
2544     OC_LOG(INFO, TAG, PCF("Entering OCCancelResponse"));
2545
2546     // TODO: validate response handle
2547
2548     return result;
2549 }
2550
2551 //-----------------------------------------------------------------------------
2552 // Private internal function definitions
2553 //-----------------------------------------------------------------------------
2554 /**
2555  * Generate handle of OCDoResource invocation for callback management.
2556  */
2557 static OCDoHandle GenerateInvocationHandle()
2558 {
2559     OCDoHandle handle = NULL;
2560     // Generate token here, it will be deleted when the transaction is deleted
2561     handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
2562     if (handle)
2563     {
2564         OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
2565     }
2566
2567     return handle;
2568 }
2569 #ifdef WITH_PRESENCE
2570 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
2571         OCResourceProperty resourceProperties, uint8_t enable)
2572 {
2573     if (resourceProperties
2574             > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW)) {
2575         OC_LOG(ERROR, TAG, PCF("Invalid property"));
2576         return OC_STACK_INVALID_PARAM;
2577     }
2578     if(!enable)
2579     {
2580         *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
2581     }
2582     else
2583     {
2584         *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
2585     }
2586     return OC_STACK_OK;
2587 }
2588 #endif
2589
2590 /**
2591  * Initialize resource data structures, variables, etc.
2592  */
2593 OCStackResult initResources() {
2594     OCStackResult result = OC_STACK_OK;
2595     // Init application resource vars
2596     headResource = NULL;
2597     // Init Virtual Resources
2598     #ifdef WITH_PRESENCE
2599     presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL;
2600     //presenceResource.token = OCGenerateCoAPToken();
2601     result = OCCreateResource(&presenceResource.handle,
2602             OC_RSRVD_RESOURCE_TYPE_PRESENCE,
2603             "core.r",
2604             OC_PRESENCE_URI,
2605             NULL,
2606             OC_OBSERVABLE);
2607     //make resource inactive
2608     result = OCChangeResourceProperty(
2609             &(((OCResource *) presenceResource.handle)->resourceProperties),
2610             OC_ACTIVE, 0);
2611     #endif
2612     return result;
2613 }
2614
2615 /**
2616  * Add a resource to the end of the linked list of resources.
2617  *
2618  * @param resource - resource to be added
2619  */
2620 void insertResource(OCResource *resource) {
2621     OCResource *pointer;
2622
2623     if (!headResource) {
2624         headResource = resource;
2625     } else {
2626         pointer = headResource;
2627
2628         while (pointer->next) {
2629             pointer = pointer->next;
2630         }
2631         pointer->next = resource;
2632     }
2633     resource->next = NULL;
2634 }
2635
2636 /**
2637  * Find a resource in the linked list of resources.
2638  *
2639  * @param resource - resource to be found
2640  * @return
2641  *     NULL                - resource not found
2642  *     pointer to resource - pointer to resource that was found in the linked list
2643  */
2644 OCResource *findResource(OCResource *resource) {
2645     OCResource *pointer = headResource;
2646
2647     while (pointer) {
2648         if (pointer == resource) {
2649             return resource;
2650         }
2651         pointer = pointer->next;
2652     }
2653     return NULL;
2654 }
2655
2656 void deleteAllResources()
2657 {
2658     OCResource *pointer = headResource;
2659     OCResource *temp;
2660
2661     while (pointer)
2662     {
2663         temp = pointer->next;
2664         #ifdef WITH_PRESENCE
2665         if(pointer != (OCResource *) presenceResource.handle)
2666         {
2667             #endif // WITH_PRESENCE
2668             deleteResource(pointer);
2669             #ifdef WITH_PRESENCE
2670         }
2671         #endif // WITH_PRESENCE
2672         pointer = temp;
2673     }
2674
2675     #ifdef WITH_PRESENCE
2676     // Ensure that the last resource to be deleted is the presence resource. This allows for all
2677     // presence notification attributed to their deletion to be processed.
2678     deleteResource((OCResource *) presenceResource.handle);
2679     #endif // WITH_PRESENCE
2680 }
2681
2682 /**
2683  * Delete the resource from the linked list.
2684  *
2685  * @param resource - resource to be deleted
2686  * @return
2687  *    0 - error
2688  *    1 - success
2689  */
2690 int deleteResource(OCResource *resource) {
2691     OCResource *prev = NULL;
2692     OCResource *temp;
2693
2694     temp = headResource;
2695     while (temp) {
2696         if (temp == resource) {
2697             // Invalidate all Resource Properties.
2698             resource->resourceProperties = (OCResourceProperty) 0;
2699             #ifdef WITH_PRESENCE
2700             if(resource != (OCResource *) presenceResource.handle)
2701             {
2702             #endif // WITH_PRESENCE
2703                 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
2704             #ifdef WITH_PRESENCE
2705             }
2706
2707             if(presenceResource.handle)
2708             {
2709                 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2710                 if(resource != (OCResource *) presenceResource.handle)
2711                 {
2712                     SendPresenceNotification(resource->rsrcType);
2713                 }
2714                 else
2715                 {
2716                     SendPresenceNotification(NULL);
2717                 }
2718             }
2719         #endif
2720
2721             if (temp == headResource) {
2722                 headResource = temp->next;
2723             } else {
2724                 prev->next = temp->next;
2725             }
2726
2727             deleteResourceElements(temp);
2728             OCFree(temp);
2729             return 1;
2730         } else {
2731             prev = temp;
2732             temp = temp->next;
2733         }
2734     }
2735
2736     return 0;
2737 }
2738
2739 /**
2740  * Delete all of the dynamically allocated elements that were created for the resource.
2741  *
2742  * @param resource - specified resource
2743  */
2744 void deleteResourceElements(OCResource *resource) {
2745     if (!resource) {
2746         return;
2747     }
2748
2749     // remove URI
2750     OCFree(resource->uri);
2751
2752     // Delete resourcetype linked list
2753     deleteResourceType(resource->rsrcType);
2754
2755     // Delete resourceinterface linked list
2756     deleteResourceInterface(resource->rsrcInterface);
2757 }
2758
2759 /**
2760  * Delete all of the dynamically allocated elements that were created for the resource type.
2761  *
2762  * @param resourceType - specified resource type
2763  */
2764 void deleteResourceType(OCResourceType *resourceType) {
2765     OCResourceType *pointer = resourceType;
2766     OCResourceType *next;
2767
2768     while (pointer) {
2769         next = pointer->next;
2770         OCFree(pointer->resourcetypename);
2771         OCFree(pointer);
2772         pointer = next;
2773     }
2774 }
2775
2776 /**
2777  * Delete all of the dynamically allocated elements that were created for the resource interface.
2778  *
2779  * @param resourceInterface - specified resource interface
2780  */
2781 void deleteResourceInterface(OCResourceInterface *resourceInterface) {
2782     OCResourceInterface *pointer = resourceInterface;
2783     OCResourceInterface *next;
2784
2785     while (pointer) {
2786         next = pointer->next;
2787         OCFree(pointer->name);
2788         OCFree(pointer);
2789         pointer = next;
2790     }
2791 }
2792
2793 /**
2794  * Insert a resource type into a resource's resource type linked list.
2795  *
2796  * @param resource - resource where resource type is to be inserted
2797  * @param resourceType - resource type to be inserted
2798  */
2799 void insertResourceType(OCResource *resource, OCResourceType *resourceType) {
2800     OCResourceType *pointer;
2801
2802     if (resource && !resource->rsrcType) {
2803         resource->rsrcType = resourceType;
2804     } else {
2805         if(resource)
2806         {
2807             pointer = resource->rsrcType;
2808         }
2809         else
2810         {
2811             pointer = resourceType;
2812         }
2813         while (pointer->next) {
2814             pointer = pointer->next;
2815         }
2816         pointer->next = resourceType;
2817     }
2818     resourceType->next = NULL;
2819 }
2820
2821 /**
2822  * Get a resource type at the specified index within a resource.
2823  *
2824  * @param handle - handle of resource
2825  * @param index - index of resource type
2826  *
2827  * @return
2828  *    resourcetype - if found
2829  *    NULL - not found
2830  */
2831 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index) {
2832     OCResource *resource;
2833     OCResourceType *pointer;
2834     uint8_t i;
2835
2836     // Find the specified resource
2837     resource = findResource((OCResource *) handle);
2838     if (!resource) {
2839         return NULL;
2840     }
2841
2842     // Make sure a resource has a resourcetype
2843     if (!resource->rsrcType) {
2844         return NULL;
2845     }
2846
2847     // Iterate through the list
2848     pointer = resource->rsrcType;
2849     i = 0;
2850     while ((i < index) && pointer) {
2851         i++;
2852         pointer = pointer->next;
2853     }
2854     return pointer;
2855 }
2856
2857 /**
2858  * Finds a resource type in an OCResourceType link-list.
2859  *
2860  * @param resourceTypeList - the link-list to be searched through
2861  * @param resourceTypeName - the key to search for
2862  *
2863  * @return
2864  *      resourceType that matches the key (ie. resourceTypeName)
2865  *      NULL - either an invalid parameter or this function was unable to find the key.
2866  */
2867 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
2868 {
2869     if(resourceTypeList && resourceTypeName)
2870     {
2871         OCResourceType * rtPointer = resourceTypeList;
2872         while(resourceTypeName && rtPointer)
2873         {
2874             if(rtPointer->resourcetypename &&
2875                     strcmp(resourceTypeName, (const char *)
2876                     (rtPointer->resourcetypename)) == 0)
2877             {
2878                 break;
2879             }
2880             rtPointer = rtPointer->next;
2881         }
2882         return rtPointer;
2883     }
2884     return NULL;
2885 }
2886 /**
2887  * Insert a resource interface into a resource's resource interface linked list.
2888  *
2889  * @param resource - resource where resource interface is to be inserted
2890  * @param resourceInterface - resource interface to be inserted
2891  */
2892 void insertResourceInterface(OCResource *resource,
2893         OCResourceInterface *resourceInterface) {
2894     OCResourceInterface *pointer;
2895
2896     if (!resource->rsrcInterface) {
2897         resource->rsrcInterface = resourceInterface;
2898     } else {
2899         pointer = resource->rsrcInterface;
2900         while (pointer->next) {
2901             pointer = pointer->next;
2902         }
2903         pointer->next = resourceInterface;
2904     }
2905     resourceInterface->next = NULL;
2906 }
2907
2908 /**
2909  * Get a resource interface at the specified index within a resource.
2910  *
2911  * @param handle - handle of resource
2912  * @param index - index of resource interface
2913  *
2914  * @return
2915  *    resourceinterface - if found
2916  *    NULL - not found
2917  */
2918 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
2919         uint8_t index) {
2920     OCResource *resource;
2921     OCResourceInterface *pointer;
2922     uint8_t i = 0;
2923
2924     // Find the specified resource
2925     resource = findResource((OCResource *) handle);
2926     if (!resource) {
2927         return NULL;
2928     }
2929
2930     // Make sure a resource has a resourceinterface
2931     if (!resource->rsrcInterface) {
2932         return NULL;
2933     }
2934
2935     // Iterate through the list
2936     pointer = resource->rsrcInterface;
2937
2938     while ((i < index) && pointer) {
2939         i++;
2940         pointer = pointer->next;
2941     }
2942     return pointer;
2943 }
2944
2945 /**
2946  * Determine if a request/response must be sent in a block transfer because it is too large to be
2947  * sent in a single PDU.  This function can be used for either a request or a response
2948  *
2949  * @param request  - NULL or pointer to request
2950  * @param response - NULL or pointer to response
2951  * @param size     - 0 or size of the request/response.  If 0, strlen is used for determining
2952  *                   the length of the request/response
2953  *
2954  * @return
2955  *    0 - packet transfer NOT required (i.e. normal request/response)
2956  *    1 - packet transfer required (i.e. block transfer needed)
2957  */
2958 uint8_t OCIsPacketTransferRequired(const char *request, const char *response, uint16_t size)
2959 {
2960     uint8_t result = 0;
2961
2962     // Determine if we are checking a request or a response
2963     if (request)
2964     {
2965         // If size is greater than 0, use it for the request size value, otherwise
2966         // assume request is null terminated and use strlen for size value
2967         if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
2968         {
2969             result = 1;
2970         }
2971     }
2972     else if (response)
2973     {
2974         // If size is greater than 0, use it for the response size value, otherwise
2975         // assume response is null terminated and use strlen for size value
2976         if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
2977         {
2978             result = 1;
2979         }
2980     }
2981     return result;
2982 }
2983
2984 /**
2985  * Retrieves a resource type based upon a uri string if the uri string contains only just one
2986  * resource attribute (and that has to be of type "rt").
2987  *
2988  * @remark This API malloc's memory for the resource type and newURI. Do not malloc resourceType
2989  * or newURI before passing in.
2990  *
2991  * @param uri - Valid URI for "requiredUri" parameter to OCDoResource API.
2992  * @param resourceType - The resource type to be populated; pass by reference.
2993  * @param newURI - Return URI without resourceType appended to the end of it. This is used to
2994  *                 ensure that the uri parameter is not modified; pass by reference.
2995  *
2996  * @return
2997  *  OC_STACK_INVALID_URI   - Returns this if the URI is invalid/NULL.
2998  *  OC_STACK_INVALID_PARAM - Returns this if the resourceType parameter is invalid/NULL.
2999  *  OC_STACK_OK            - Success
3000  */
3001 OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI)
3002 {
3003     if(!uri)
3004     {
3005         return OC_STACK_INVALID_URI;
3006     }
3007     if(!resourceType || !newURI)
3008     {
3009         return OC_STACK_INVALID_PARAM;
3010     }
3011     char * leftToken = NULL;
3012     char * tempURI = (char *) OCMalloc(strlen(uri) + 1);
3013     if(!tempURI)
3014     {
3015         goto exit;
3016     }
3017     strcpy(tempURI, uri);
3018     leftToken = strtok((char *)tempURI, "?");
3019
3020     while(leftToken != NULL)
3021     {
3022         if(strncmp(leftToken, "rt=", 3) == 0)
3023         {
3024             *resourceType = (unsigned char *) OCMalloc(strlen(leftToken)-3);
3025             if(!*resourceType)
3026             {
3027                 goto exit;
3028             }
3029             strcpy((char *)*resourceType, ((const char *)&leftToken[3]));
3030             break;
3031         }
3032         leftToken = strtok(NULL, "?");
3033     }
3034
3035     *newURI = tempURI;
3036
3037     return OC_STACK_OK;
3038
3039     exit:
3040         return OC_STACK_NO_MEMORY;
3041 }
3042
3043 const ServerID OCGetServerInstanceID(void)
3044 {
3045     static bool generated = false;
3046     static ServerID sid;
3047
3048     if(generated)
3049     {
3050         return sid;
3051     }
3052
3053     sid = OCGetRandom();
3054     generated = true;
3055     return sid;
3056 }
3057
3058 const char* OCGetServerInstanceIDString(void)
3059 {
3060     // max printed length of a base 10
3061     // uint32 is 10 characters, so 11 includes null.
3062     // This will change as the representation gets switched
3063     // to another value
3064     static char buffer[11];
3065     int n = sprintf(buffer, "%u", OCGetServerInstanceID());
3066     if (n < 0)
3067     {
3068         buffer[0]='\0';
3069     }
3070
3071     return buffer;
3072 }