Merge "Fix Unicast Presence Error"
[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 //-----------------------------------------------------------------------------
37 // Typedefs
38 //-----------------------------------------------------------------------------
39 typedef enum {
40     OC_STACK_UNINITIALIZED = 0, OC_STACK_INITIALIZED
41 } OCStackState;
42
43 #ifdef WITH_PRESENCE
44 typedef enum {
45     OC_PRESENCE_UNINITIALIZED = 0, OC_PRESENCE_INITIALIZED
46 } OCPresenceState;
47 #endif
48
49 //-----------------------------------------------------------------------------
50 // Private variables
51 //-----------------------------------------------------------------------------
52 static OCStackState stackState = OC_STACK_UNINITIALIZED;
53
54 OCResource *headResource = NULL;
55 #ifdef WITH_PRESENCE
56 static OCPresenceState presenceState = OC_PRESENCE_UNINITIALIZED;
57 static PresenceResource presenceResource;
58 uint8_t PresenceTimeOutSize = 0;
59 uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100};
60 #endif
61
62 OCMode myStackMode;
63 OCDeviceEntityHandler defaultDeviceHandler;
64
65 //-----------------------------------------------------------------------------
66 // Macros
67 //-----------------------------------------------------------------------------
68 #define TAG  PCF("OCStack")
69 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
70              TAG, PCF(#arg " is NULL")); return (retVal); } }
71
72 //TODO: we should allow the server to define this
73 #define MAX_OBSERVE_AGE (0x2FFFFUL)
74 //-----------------------------------------------------------------------------
75 // Externs
76 //-----------------------------------------------------------------------------
77 extern void DeinitOCSecurityInfo();
78
79 //-----------------------------------------------------------------------------
80 // Internal API function
81 //-----------------------------------------------------------------------------
82
83 // This internal function is called to update the stack with the status of
84 // observers and communication failures
85 OCStackResult OCStackFeedBack(OCCoAPToken * token, uint8_t status)
86 {
87     OCStackResult result = OC_STACK_ERROR;
88     ResourceObserver * observer = NULL;
89     OCEntityHandlerRequest ehRequest = {0};
90
91     switch(status)
92     {
93     case OC_OBSERVER_NOT_INTERESTED:
94         OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
95         observer = GetObserverUsingToken (token);
96         if(observer)
97         {
98             result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
99                     OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
100                     NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
101             if(result != OC_STACK_OK)
102             {
103                 return result;
104             }
105             observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
106         }
107         //observer is not observing anymore
108         result = DeleteObserverUsingToken (token);
109         if(result == OC_STACK_OK)
110         {
111             OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
112         }
113         else
114         {
115             result = OC_STACK_OK;
116             OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
117         }
118         break;
119     case OC_OBSERVER_STILL_INTERESTED:
120         //observer is still interested
121         OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
122                 notifications, reset the failedCount"));
123         observer = GetObserverUsingToken(token);
124         if(observer)
125         {
126             observer->forceHighQos = 0;
127             observer->failedCommCount = 0;
128             result = OC_STACK_OK;
129         }
130         else
131         {
132             result = OC_STACK_OBSERVER_NOT_FOUND;
133         }
134         break;
135     case OC_OBSERVER_FAILED_COMM:
136         //observer is not reachable
137         OC_LOG(DEBUG, TAG, PCF("observer is unreachable"));
138         observer = GetObserverUsingToken(token);
139         if(observer)
140         {
141             if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
142             {
143                 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
144                         OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
145                         NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
146                 if(result != OC_STACK_OK)
147                 {
148                     return OC_STACK_ERROR;
149                 }
150                 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
151                 //observer is unreachable
152                 result = DeleteObserverUsingToken (token);
153                 if(result == OC_STACK_OK)
154                 {
155                     OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
156                 }
157                 else
158                 {
159                     result = OC_STACK_OK;
160                     OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
161                 }
162             }
163             else
164             {
165                 observer->failedCommCount++;
166                 result = OC_STACK_CONTINUE;
167             }
168             observer->forceHighQos = 1;
169             OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
170         }
171         break;
172     default:
173         OC_LOG(ERROR, TAG, PCF("Unknown status"));
174         result = OC_STACK_ERROR;
175         break;
176         }
177     return result;
178 }
179
180 //This function will be called back by occoap layer when a request is received
181 OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
182 {
183     OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
184
185     OCStackResult result = OC_STACK_ERROR;
186     ResourceHandling resHandling;
187     OCResource *resource;
188
189     OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken);
190     if(!request)
191     {
192         OC_LOG(INFO, TAG, PCF("This is a new Server Request"));
193         result = AddServerRequest(&request, protocolRequest->coapID,
194                 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
195                 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
196                 protocolRequest->observationOption, protocolRequest->qos,
197                 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
198                 protocolRequest->reqJSONPayload, &protocolRequest->requestToken,
199                 &protocolRequest->requesterAddr, protocolRequest->resourceUrl,
200                 protocolRequest->reqTotalSize);
201         if (OC_STACK_OK != result)
202         {
203             OC_LOG(ERROR, TAG, PCF("Error adding server request"));
204             return result;
205         }
206         VERIFY_NON_NULL(request, ERROR, OC_STACK_NO_MEMORY);
207
208         if(!protocolRequest->reqMorePacket)
209         {
210             request->requestComplete = 1;
211         }
212     }
213     else
214     {
215         OC_LOG(INFO, TAG, PCF("This is either a repeated Server Request or blocked Server Request"));
216     }
217
218     if(request->requestComplete)
219     {
220         OC_LOG(INFO, TAG, PCF("This Server Request is complete"));
221         result = DetermineResourceHandling (request, &resHandling, &resource);
222         if (result == OC_STACK_OK)
223         {
224             result = ProcessRequest(resHandling, resource, request);
225         }
226         else
227         {
228             result = OC_STACK_ERROR;
229         }
230     }
231     else
232     {
233         OC_LOG(INFO, TAG, PCF("This Server Request is incomplete"));
234         result = OC_STACK_CONTINUE;
235     }
236     return result;
237 }
238
239 //This function will be called back by occoap layer when a response is received
240 void HandleStackResponses(OCResponse * response)
241 {
242     OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION;
243     OC_LOG(INFO, TAG, PCF("Entering HandleStackResponses (OCStack Layer)"));
244
245     if (response->cbNode)
246     {
247         OC_LOG(INFO, TAG, PCF("Calling into application address space"));
248         result = response->cbNode->callBack(response->cbNode->context,
249                 response->cbNode->handle, response->clientResponse);
250         if (result == OC_STACK_DELETE_TRANSACTION ||
251                 response->clientResponse->result == OC_STACK_COMM_ERROR ||
252                 response->clientResponse->result == OC_STACK_RESOURCE_DELETED)
253         {
254             FindAndDeleteClientCB(response->cbNode);
255         }
256     }
257 }
258
259 int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
260 {
261     size_t index = 0;
262     unsigned char *itr, *coap;
263     uint8_t dotCount = 0;
264
265     ipAddr[index] = 0;
266     *port = 0;
267     /* search for scheme */
268     itr = ipAddrStr;
269     if (!isdigit((unsigned char) *ipAddrStr))
270     {
271         coap = (unsigned char *) OC_COAP_SCHEME;
272         while (*coap && tolower(*itr) == *coap)
273         {
274             coap++;
275             itr++;
276         }
277     }
278     ipAddrStr = itr;
279
280     while (*ipAddrStr) {
281         if (isdigit((unsigned char) *ipAddrStr))
282         {
283             ipAddr[index] *= 10;
284             ipAddr[index] += *ipAddrStr - '0';
285         }
286         else if ((unsigned char) *ipAddrStr == '.')
287         {
288             index++;
289             dotCount++;
290             ipAddr[index] = 0;
291         }
292         else
293         {
294             break;
295         }
296         ipAddrStr++;
297     }
298     if(*ipAddrStr == ':')
299     {
300         ipAddrStr++;
301         while (*ipAddrStr){
302             if (isdigit((unsigned char) *ipAddrStr))
303             {
304                 *port *= 10;
305                 *port += *ipAddrStr - '0';
306             }
307             else
308             {
309                 break;
310             }
311             ipAddrStr++;
312         }
313     }
314
315
316     if (ipAddr[0] < 255 && ipAddr[1] < 255 && ipAddr[2] < 255 && ipAddr[3] < 255
317             && dotCount == 3)
318     {
319         return 1;
320     }
321     else
322     {
323         return 0;
324     }
325 }
326
327 //-----------------------------------------------------------------------------
328 // Private internal function prototypes
329 //-----------------------------------------------------------------------------
330
331 static OCDoHandle GenerateInvocationHandle();
332 static OCStackResult initResources();
333 static void insertResource(OCResource *resource);
334 static OCResource *findResource(OCResource *resource);
335 static void insertResourceType(OCResource *resource,
336         OCResourceType *resourceType);
337 static OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle,
338         uint8_t index);
339 static void insertResourceInterface(OCResource *resource,
340         OCResourceInterface *resourceInterface);
341 static OCResourceInterface *findResourceInterfaceAtIndex(
342         OCResourceHandle handle, uint8_t index);
343 static void deleteResourceType(OCResourceType *resourceType);
344 static void deleteResourceInterface(OCResourceInterface *resourceInterface);
345 static void deleteResourceElements(OCResource *resource);
346 static int deleteResource(OCResource *resource);
347 static void deleteAllResources();
348 static void incrementSequenceNumber(OCResource * resPtr);
349 static OCStackResult verifyUriQueryLength(const char * inputUri,
350         uint16_t uriLen);
351 static uint8_t OCIsPacketTransferRequired(const char *request, const char *response, uint16_t size);
352 OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI);
353
354 //-----------------------------------------------------------------------------
355 // Public APIs
356 //-----------------------------------------------------------------------------
357
358 /**
359  * Initialize the OC Stack.  Must be called prior to starting the stack.
360  *
361  * @param ipAddr
362  *     IP Address of host device
363  * @param port
364  *     Port of host device
365  * @param mode
366  *     Host device is client, server, or client-server
367  *
368  * @return
369  *     OC_STACK_OK    - no errors
370  *     OC_STACK_ERROR - stack init error
371  */
372 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
373 {
374     OCStackResult result = OC_STACK_ERROR;
375     OC_LOG(INFO, TAG, PCF("Entering OCInit"));
376
377     if (ipAddr)
378     {
379         OC_LOG_V(INFO, TAG, "IP Address = %s", ipAddr);
380     }
381
382     switch (mode)
383     {
384     case OC_CLIENT:
385         OC_LOG(INFO, TAG, PCF("Client mode"));
386         break;
387     case OC_SERVER:
388         OC_LOG(INFO, TAG, PCF("Server mode"));
389         break;
390     case OC_CLIENT_SERVER:
391         OC_LOG(INFO, TAG, PCF("Client-server mode"));
392         break;
393     default:
394         OC_LOG(ERROR, TAG, PCF("Invalid mode"));
395         return OC_STACK_ERROR;
396         break;
397     }
398     myStackMode = mode;
399
400     defaultDeviceHandler = NULL;
401
402 #ifdef WITH_PRESENCE
403     PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
404 #endif // WITH_PRESENCE
405
406     // Make call to OCCoAP layer
407     result = OCInitCoAP(ipAddr, (uint16_t) port, myStackMode);
408     if (result == OC_STACK_OK)
409     {
410         stackState = OC_STACK_INITIALIZED;
411     }
412     // Initialize resource
413     if(result == OC_STACK_OK && myStackMode != OC_CLIENT)
414     {
415         result = initResources();
416     }
417     if(result != OC_STACK_OK)
418     {
419         OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
420     }
421     return result;
422 }
423
424 /**
425  * Stop the OC stack.  Use for a controlled shutdown.
426  * @return
427  *     OC_STACK_OK    - no errors
428  *     OC_STACK_ERROR - stack not initialized
429  */
430 OCStackResult OCStop()
431 {
432     OCStackResult result = OC_STACK_ERROR;
433
434     OC_LOG(INFO, TAG, PCF("Entering OCStop"));
435
436     if (stackState != OC_STACK_INITIALIZED)
437     {
438         OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
439         return OC_STACK_ERROR;
440     }
441
442     #ifdef WITH_PRESENCE
443     // Ensure that the TTL associated with ANY and ALL presence notifications originating from
444     // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
445     presenceResource.presenceTTL = 0;
446     #endif // WITH_PRESENCE
447
448     // Free memory dynamically allocated for resources
449     deleteAllResources();
450
451     // Make call to OCCoAP layer
452     if (OCStopCoAP() == OC_STACK_OK)
453     {
454         // Remove all observers
455         DeleteObserverList();
456         // Remove all the client callbacks
457         DeleteClientCBList();
458         stackState = OC_STACK_UNINITIALIZED;
459         result = OC_STACK_OK;
460     } else {
461         result = OC_STACK_ERROR;
462     }
463
464     // Deinit security blob
465     DeinitOCSecurityInfo();
466
467     if (result != OC_STACK_OK) {
468         OC_LOG(ERROR, TAG, PCF("Stack stop error"));
469     }
470
471     return result;
472 }
473
474 /**
475  * Verify the lengths of the URI and the query separately
476  *
477  * @param inputUri       - Input URI and query.
478  * @param uriLen         - The length of the initial URI with query.
479  *
480  * Note: The '?' that appears after the URI is not considered as
481  * a part of the query.
482  */
483 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
484 {
485     char *query;
486
487     query = strchr (inputUri, '?');
488
489     if (query != NULL)
490     {
491         if((query - inputUri) > MAX_URI_LENGTH)
492         {
493             return OC_STACK_INVALID_URI;
494         }
495
496         if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
497         {
498             return OC_STACK_INVALID_QUERY;
499         }
500     }
501     else if(uriLen > MAX_URI_LENGTH)
502     {
503         return OC_STACK_INVALID_URI;
504     }
505     return OC_STACK_OK;
506 }
507
508 /**
509  * Discover or Perform requests on a specified resource (specified by that Resource's respective URI).
510  *
511  * @param handle             - @ref OCDoHandle to refer to the request sent out on behalf of calling this API.
512  * @param method             - @ref OCMethod to perform on the resource
513  * @param requiredUri        - URI of the resource to interact with
514  * @param referenceUri       - URI of the reference resource
515  * @param request            - JSON encoded request
516  * @param qos                - quality of service
517  * @param cbData             - struct that contains asynchronous callback function that is invoked
518  *                             by the stack when discovery or resource interaction is complete
519  * @param options            - The address of an array containing the vendor specific header
520  *                             header options to be sent with the request
521  * @param numOptions         - Number of vendor specific header options to be included
522  *
523  * @return
524  *     OC_STACK_OK               - no errors
525  *     OC_STACK_INVALID_CALLBACK - invalid callback function pointer
526  *     OC_STACK_INVALID_METHOD   - invalid resource method
527  *     OC_STACK_INVALID_URI      - invalid required or reference URI
528  */
529
530 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
531                            const char *referenceUri, const char *request,
532                            OCQualityOfService qos, OCCallbackData *cbData,
533                            OCHeaderOption * options, uint8_t numOptions)
534 {
535     OCStackResult result = OC_STACK_ERROR;
536     OCCoAPToken token;
537     ClientCB *clientCB = NULL;
538     unsigned char * requestUri = NULL;
539     unsigned char * resourceType = NULL;
540     char * newUri = (char *)requiredUri;
541     (void) referenceUri;
542
543     OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
544
545     // Validate input parameters
546     VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
547     VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
548
549     TODO ("Need to form the final query by concatenating require and reference URI's");
550     VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
551
552     uint16_t uriLen = strlen(requiredUri);
553
554     // ToDo: We should also check if the requiredUri has a mutlicast address, then qos has to be OC_Low_QOS
555     switch (method)
556     {
557         case OC_REST_GET:
558         case OC_REST_PUT:
559         case OC_REST_POST:
560         case OC_REST_DELETE:
561         case OC_REST_OBSERVE:
562         case OC_REST_OBSERVE_ALL:
563         case OC_REST_CANCEL_OBSERVE:
564             break;
565         #ifdef WITH_PRESENCE
566         case OC_REST_PRESENCE:
567             break;
568         #endif
569         default:
570             result = OC_STACK_INVALID_METHOD;
571             goto exit;
572     }
573
574     if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
575     {
576         goto exit;
577     }
578
579     if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
580     {
581         result = OC_STACK_INVALID_PARAM;
582         goto exit;
583     }
584
585 #ifdef WITH_PRESENCE
586     if(method == OC_REST_PRESENCE)
587     {
588         result = getResourceType(requiredUri, &resourceType, &newUri);
589         if(resourceType) {
590             OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
591         }
592         else
593         {
594             OC_LOG(DEBUG, TAG, "Got Resource Type is NULL.");
595         }
596         if(result != OC_STACK_OK)
597         {
598             goto exit;
599         }
600     }
601 #endif // WITH_PRESENCE
602
603     requestUri = (unsigned char *) OCMalloc(uriLen + 1);
604     if(requestUri)
605     {
606         memcpy(requestUri, newUri, (uriLen + 1));
607     }
608     else
609     {
610         result = OC_STACK_NO_MEMORY;
611         goto exit;
612     }
613
614     *handle = GenerateInvocationHandle();
615     if(!*handle)
616     {
617         result = OC_STACK_NO_MEMORY;
618         goto exit;
619     }
620
621     // Generate token which will be used by OCStack to match responses received
622     // with the request
623     OCGenerateCoAPToken(&token);
624
625     if((result = AddClientCB(&clientCB, cbData, &token, handle, method, requestUri, resourceType))
626             != OC_STACK_OK)
627     {
628         result = OC_STACK_NO_MEMORY;
629         goto exit;
630     }
631
632     // Make call to OCCoAP layer
633     result = OCDoCoAPResource(method, qos, &token, newUri, request, options, numOptions);
634
635 exit:
636     if(newUri != requiredUri)
637     {
638         OCFree(newUri);
639     }
640     if (result != OC_STACK_OK)
641     {
642         OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
643         FindAndDeleteClientCB(clientCB);
644     }
645     return result;
646 }
647
648 /**
649  * Cancel a request associated with a specific @ref OCDoResource invocation.
650  *
651  * @param handle - Used to identify a specific OCDoResource invocation.
652  * @param qos    - used to specify Quality of Service (read below for more info)
653  * @param options- used to specify vendor specific header options when sending
654  *                 explicit observe cancellation
655  * @param numOptions- Number of header options to be included
656  *
657  * @return
658  *     OC_STACK_OK               - No errors; Success
659  *     OC_STACK_INVALID_PARAM    - The handle provided is invalid.
660  */
661 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
662         uint8_t numOptions) {
663     /*
664      * This ftn is implemented one of two ways in the case of observation:
665      *
666      * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
667      *      Remove the callback associated on client side.
668      *      When the next notification comes in from server,
669      *      reply with RESET message to server.
670      *      Keep in mind that the server will react to RESET only
671      *      if the last notification was sent ans CON
672      *
673      * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
674      *      and it is associated with an observe request
675      *      (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
676      *      Send CON Observe request to server with
677      *      observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
678      *      Remove the callback associated on client side.
679      */
680     OCStackResult ret = OC_STACK_OK;
681
682     if(!handle) {
683         return OC_STACK_INVALID_PARAM;
684     }
685
686     OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
687
688     ClientCB *clientCB = GetClientCB(NULL, handle, NULL);
689
690     if(clientCB) {
691         switch (clientCB->method)
692         {
693             case OC_REST_OBSERVE:
694             case OC_REST_OBSERVE_ALL:
695                 if(qos == OC_HIGH_QOS)
696                 {
697                     ret = OCDoCoAPResource(OC_REST_CANCEL_OBSERVE, qos,
698                             &(clientCB->token), (const char *) clientCB->requestUri, NULL, options,
699                             numOptions);
700                 }
701                 else
702                 {
703                     FindAndDeleteClientCB(clientCB);
704                 }
705                 break;
706             #ifdef WITH_PRESENCE
707             case OC_REST_PRESENCE:
708                 FindAndDeleteClientCB(clientCB);
709                 break;
710             #endif
711             default:
712                 return OC_STACK_INVALID_METHOD;
713         }
714     }
715     return ret;
716 }
717 #ifdef WITH_PRESENCE
718 OCStackResult OCProcessPresence()
719 {
720     OCStackResult result = OC_STACK_OK;
721     uint8_t ipAddr[4] = { 0 };
722     uint16_t port = 0;
723
724     OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
725     ClientCB* cbNode = NULL;
726     OCDevAddr dst;
727     OCClientResponse clientResponse;
728     OCResponse * response = NULL;
729
730     LL_FOREACH(cbList, cbNode) {
731         if(OC_REST_PRESENCE == cbNode->method)
732         {
733             if(cbNode->presence)
734             {
735                 uint32_t now = GetTime(0);
736                 OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
737                 OC_LOG_V(DEBUG, TAG, "----------------current ticks %d", now);
738
739
740                 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
741                 {
742                     goto exit;
743                 }
744
745                 if(cbNode->presence->TTLlevel < PresenceTimeOutSize){
746                     OC_LOG_V(DEBUG, TAG, "----------------timeout ticks %d",
747                             cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
748                 }
749
750                 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
751                 {
752                     OC_LOG(DEBUG, TAG, PCF("----------------No more timeout ticks"));
753                     if (ParseIPv4Address( cbNode->requestUri, ipAddr, &port))
754                     {
755                         OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
756                                 &dst);
757                         result = FormOCClientResponse(&clientResponse, OC_STACK_PRESENCE_TIMEOUT,
758                                 (OCDevAddr *) &dst, 0, NULL);
759                         if(result != OC_STACK_OK)
760                         {
761                             goto exit;
762                         }
763                         result = FormOCResponse(&response, cbNode, 0, &clientResponse);
764                         if(result != OC_STACK_OK)
765                         {
766                             goto exit;
767                         }
768
769                         // Increment the TTLLevel (going to a next state), so we don't keep
770                         // sending presence notification to client.
771                         cbNode->presence->TTLlevel++;
772                         OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d",
773                                                 cbNode->presence->TTLlevel);
774                     }
775                     else
776                     {
777                         result = OC_STACK_INVALID_IP;
778                         goto exit;
779                     }
780                     HandleStackResponses(response);
781                 }
782                 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
783                 {
784                     OC_LOG(DEBUG, TAG, PCF("time to test server presence =========="));
785                     OCCoAPToken token;
786                     OCGenerateCoAPToken(&token);
787                     result = OCDoCoAPResource(OC_REST_GET, OC_LOW_QOS,
788                             &token, (const char *)cbNode->requestUri, NULL, NULL, 0);
789                     if(result != OC_STACK_OK)
790                     {
791                         goto exit;
792                     }
793                     cbNode->presence->TTLlevel++;
794                     OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d", cbNode->presence->TTLlevel);
795                 }
796             }
797         }
798     }
799 exit:
800     if (result != OC_STACK_OK)
801     {
802         OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
803     }
804     return result;
805 }
806 #endif
807
808 /**
809  * Called in main loop of OC client or server.  Allows low-level processing of
810  * stack services.
811  *
812  * @return
813  *     OC_STACK_OK    - no errors
814  *     OC_STACK_ERROR - stack process error
815  */
816 OCStackResult OCProcess() {
817
818     OC_LOG(INFO, TAG, PCF("Entering OCProcess"));
819     #ifdef WITH_PRESENCE
820     OCProcessPresence();
821     #endif
822     OCProcessCoAP();
823
824     return OC_STACK_OK;
825 }
826
827 #ifdef WITH_PRESENCE
828 /**
829  * When operating in @ref OCServer or @ref OCClientServer mode, this API will start sending out
830  * presence notifications to clients via multicast. Once this API has been called with a success,
831  * clients may query for this server's presence and this server's stack will respond via multicast.
832  *
833  * Server can call this function when it comes online for the first time, or when it comes back
834  * online from offline mode, or when it re enters network.
835  *
836  * @param ttl - Time To Live in seconds
837  * Note: If ttl is '0', then the default stack value will be used (60 Seconds).
838  *
839  * @return
840  *     OC_STACK_OK      - No errors; Success
841  */
842 OCStackResult OCStartPresence(const uint32_t ttl)
843 {
844     OCChangeResourceProperty(
845             &(((OCResource *)presenceResource.handle)->resourceProperties),
846             OC_ACTIVE, 1);
847
848     if(ttl > 0)
849     {
850         presenceResource.presenceTTL = ttl;
851     }
852
853     if(OC_PRESENCE_UNINITIALIZED == presenceState)
854     {
855         OCDevAddr multiCastAddr;
856         OCCoAPToken token;
857
858         presenceState = OC_PRESENCE_INITIALIZED;
859         OCGenerateCoAPToken(&token);
860         OCBuildIPv4Address(224, 0, 1, 187, 5683, &multiCastAddr);
861         //add the presence observer
862         AddObserver(OC_PRESENCE_URI, NULL, 0, &token, &multiCastAddr,
863             (OCResource *)presenceResource.handle, OC_LOW_QOS);
864     }
865
866     // Each time OCStartPresence is called
867     // a different random 32-bit integer number is used
868     ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
869
870     return SendPresenceNotification(NULL);
871 }
872
873 /**
874  * When operating in @ref OCServer or @ref OCClientServer mode, this API will stop sending out
875  * presence notifications to clients via multicast. Once this API has been called with a success,
876  * this server's stack will not respond to clients querying for this server's presence.
877  *
878  * Server can call this function when it is terminating, going offline, or when going
879  * away from network.
880  *
881  * @return
882  *     OC_STACK_OK      - No errors; Success
883  */
884 OCStackResult OCStopPresence()
885 {
886     OCStackResult result = OC_STACK_ERROR;
887     //make resource inactive
888     result = OCChangeResourceProperty(
889             &(((OCResource *) presenceResource.handle)->resourceProperties),
890             OC_ACTIVE, 0);
891     result = SendPresenceNotification(NULL);
892
893     return result;
894 }
895 #endif
896
897
898 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
899 {
900     defaultDeviceHandler = entityHandler;
901
902     return OC_STACK_OK;
903 }
904
905 /**
906  * Create a resource
907  *
908  * @param handle - pointer to handle to newly created resource.  Set by ocstack.  Used to refer to resource
909  * @param resourceTypeName - name of resource type.  Example: "core.led"
910  * @param resourceInterfaceName - name of resource interface.  Example: "core.rw"
911  * @param uri - URI of the resource.  Example:  "/a/led"
912  * @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
913  *                        NULL for default entity handler
914  * @param resourceProperties - properties supported by resource.  Example: OC_DISCOVERABLE|OC_OBSERVABLE
915  *
916  * @return
917  *     OC_STACK_OK    - no errors
918  *     OC_STACK_ERROR - stack process error
919  */
920 OCStackResult OCCreateResource(OCResourceHandle *handle,
921         const char *resourceTypeName,
922         const char *resourceInterfaceName,
923         const char *uri, OCEntityHandler entityHandler,
924         uint8_t resourceProperties) {
925
926     OCResource *pointer = NULL;
927     char *str = NULL;
928     size_t size;
929     OCStackResult result = OC_STACK_ERROR;
930
931     OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
932
933     if(myStackMode == OC_CLIENT)
934     {
935         return result;
936     }
937     // Validate parameters
938     // Is it presented during resource discovery?
939     if (!handle || !resourceTypeName || !uri) {
940         OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
941         return OC_STACK_INVALID_PARAM;
942     }
943
944     if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0) {
945         resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
946     }
947
948     // Make sure resourceProperties bitmask has allowed properties specified
949     if (resourceProperties
950             > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE)) {
951         OC_LOG(ERROR, TAG, PCF("Invalid property"));
952         return OC_STACK_INVALID_PARAM;
953     }
954
955     // If the headResource is NULL, then no resources have been created...
956     pointer = headResource;
957     if (pointer) {
958         // At least one resources is in the resource list, so we need to search for
959         // repeated URLs, which are not allowed.  If a repeat is found, exit with an error
960         while (pointer) {
961             if (strcmp(uri, pointer->uri) == 0) {
962                 OC_LOG(ERROR, TAG, PCF("URI already in use"));
963                 return OC_STACK_INVALID_PARAM;
964             }
965             pointer = pointer->next;
966         }
967     }
968     // Create the pointer and insert it into the resource list
969     pointer = (OCResource *) OCMalloc(sizeof(OCResource));
970     if (!pointer) {
971         goto exit;
972     }
973     memset(pointer, 0, sizeof(OCResource));
974     pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
975
976     insertResource(pointer);
977
978     // Set the uri
979     size = strlen(uri) + 1;
980     str = (char *) OCMalloc(size);
981     if (!str) {
982         goto exit;
983     }
984     strncpy(str, uri, size);
985     pointer->uri = str;
986
987     // Set properties.  Set OC_ACTIVE
988     pointer->resourceProperties = (OCResourceProperty) (resourceProperties
989             | OC_ACTIVE);
990
991     // Add the resourcetype to the resource
992     result = BindResourceTypeToResource(pointer, resourceTypeName);
993     if (result != OC_STACK_OK) {
994         OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
995         goto exit;
996     }
997
998     // Add the resourceinterface to the resource
999     result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
1000     if (result != OC_STACK_OK) {
1001         OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
1002         goto exit;
1003     }
1004
1005     // If an entity handler has been passed, attach it to the newly created
1006     // resource.  Otherwise, set the default entity handler.
1007     if (entityHandler)
1008     {
1009         pointer->entityHandler = entityHandler;
1010     }
1011     else
1012     {
1013         pointer->entityHandler = defaultResourceEHandler;
1014     }
1015
1016     *handle = pointer;
1017     result = OC_STACK_OK;
1018
1019     #ifdef WITH_PRESENCE
1020     if(presenceResource.handle)
1021     {
1022         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1023         SendPresenceNotification(pointer->rsrcType);
1024     }
1025     #endif
1026 exit:
1027     if (result != OC_STACK_OK)
1028     {
1029         // Deep delete of resource and other dynamic elements that it contains
1030         deleteResource(pointer);
1031         OCFree(str);
1032     }
1033     return result;
1034 }
1035
1036
1037
1038 /**
1039  * Create a resource. with host ip address for remote resource
1040  *
1041  * @param handle - pointer to handle to newly created resource.  Set by ocstack.
1042  *                 Used to refer to resource
1043  * @param resourceTypeName - name of resource type.  Example: "core.led"
1044  * @param resourceInterfaceName - name of resource interface.  Example: "core.rw"
1045  * @param host - HOST address of the remote resource.  Example:  "coap://xxx.xxx.xxx.xxx:xxxxx"
1046  * @param uri - URI of the resource.  Example:  "/a/led"
1047  * @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
1048  *                        NULL for default entity handler
1049  * @param resourceProperties - properties supported by resource.
1050  *                             Example: OC_DISCOVERABLE|OC_OBSERVABLE
1051  *
1052  * @return
1053  *     OC_STACK_OK    - no errors
1054  *     OC_STACK_ERROR - stack process error
1055  */
1056
1057 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
1058         const char *resourceTypeName,
1059         const char *resourceInterfaceName,
1060         const char *host,
1061         const char *uri,
1062         OCEntityHandler entityHandler,
1063         uint8_t resourceProperties)
1064 {
1065     char *str = NULL;
1066     size_t size;
1067     OCStackResult result = OC_STACK_ERROR;
1068
1069     result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
1070                                 uri, entityHandler, resourceProperties);
1071
1072     if (result != OC_STACK_ERROR)
1073     {
1074         // Set the uri
1075         size = strlen(host) + 1;
1076         str = (char *) OCMalloc(size);
1077         if (!str)
1078         {
1079             return OC_STACK_ERROR;
1080         }
1081         strncpy(str, host, size);
1082         ((OCResource *) *handle)->host = str;
1083     }
1084
1085     return result;
1086 }
1087
1088 /**
1089  * Add a resource to a collection resource.
1090  *
1091  * @param collectionHandle - handle to the collection resource
1092  * @param resourceHandle - handle to resource to be added to the collection resource
1093  *
1094  * @return
1095  *     OC_STACK_OK    - no errors
1096  *     OC_STACK_ERROR - stack process error
1097  *     OC_STACK_INVALID_PARAM - invalid collectionhandle
1098  */
1099 OCStackResult OCBindResource(
1100         OCResourceHandle collectionHandle, OCResourceHandle resourceHandle) {
1101     OCResource *resource;
1102     uint8_t i;
1103
1104     OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
1105
1106     // Validate parameters
1107     VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
1108     VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
1109     // Container cannot contain itself
1110     if (collectionHandle == resourceHandle) {
1111         OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
1112         return OC_STACK_INVALID_PARAM;
1113     }
1114
1115     // Use the handle to find the resource in the resource linked list
1116     resource = findResource((OCResource *) collectionHandle);
1117     if (!resource) {
1118         OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
1119         return OC_STACK_INVALID_PARAM;
1120     }
1121
1122     // Look for an open slot to add add the child resource.
1123     // If found, add it and return success
1124     for (i = 0; i < MAX_CONTAINED_RESOURCES; i++) {
1125         if (!resource->rsrcResources[i]) {
1126             resource->rsrcResources[i] = (OCResource *) resourceHandle;
1127             OC_LOG(INFO, TAG, PCF("resource bound"));
1128             return OC_STACK_OK;
1129         }
1130     }
1131
1132     #ifdef WITH_PRESENCE
1133     if(presenceResource.handle)
1134     {
1135         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1136         SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
1137     }
1138     #endif
1139
1140     // Unable to add resourceHandle, so return error
1141     return OC_STACK_ERROR;
1142 }
1143
1144 /**
1145  * Remove a resource from a collection resource.
1146  *
1147  * @param collectionHandle - handle to the collection resource
1148  * @param resourceHandle - handle to resource to be added to the collection resource
1149  *
1150  * @return
1151  *     OC_STACK_OK    - no errors
1152  *     OC_STACK_ERROR - stack process error
1153  *     OC_STACK_INVALID_PARAM - invalid collectionHandle
1154  */
1155 OCStackResult OCUnBindResource(
1156         OCResourceHandle collectionHandle, OCResourceHandle resourceHandle) {
1157     OCResource *resource;
1158     uint8_t i;
1159
1160     OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
1161
1162     // Validate parameters
1163     VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
1164     VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
1165     // Container cannot contain itself
1166     if (collectionHandle == resourceHandle) {
1167         OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
1168         return OC_STACK_INVALID_PARAM;
1169     }
1170
1171     // Use the handle to find the resource in the resource linked list
1172     resource = findResource((OCResource *) collectionHandle);
1173     if (!resource) {
1174         OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
1175         return OC_STACK_INVALID_PARAM;
1176     }
1177
1178     // Look for an open slot to add add the child resource.
1179     // If found, add it and return success
1180     for (i = 0; i < MAX_CONTAINED_RESOURCES; i++) {
1181         if (resourceHandle == resource->rsrcResources[i]) {
1182             resource->rsrcResources[i] = (OCResource *) NULL;
1183             OC_LOG(INFO, TAG, PCF("resource unbound"));
1184             return OC_STACK_OK;
1185         }
1186     }
1187
1188     OC_LOG(INFO, TAG, PCF("resource not found in collection"));
1189
1190     #ifdef WITH_PRESENCE
1191     if(presenceResource.handle)
1192     {
1193         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1194         SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
1195     }
1196     #endif
1197
1198     // Unable to add resourceHandle, so return error
1199     return OC_STACK_ERROR;
1200 }
1201
1202 OCStackResult BindResourceTypeToResource(OCResource* resource,
1203                                             const char *resourceTypeName)
1204 {
1205     OCResourceType *pointer = NULL;
1206     char *str = NULL;
1207     size_t size;
1208     OCStackResult result = OC_STACK_ERROR;
1209
1210     OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
1211
1212     // Validate parameters
1213     VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
1214     // TODO:  Does resource attribute resentation really have to be maintained in stack?
1215     // Is it presented during resource discovery?
1216
1217     TODO ("Make sure that the resourcetypename doesn't already exist in the resource");
1218
1219     // Create the resourcetype and insert it into the resource list
1220     pointer = (OCResourceType *) OCMalloc(sizeof(OCResourceType));
1221     if (!pointer) {
1222         goto exit;
1223     }
1224     memset(pointer, 0, sizeof(OCResourceType));
1225
1226     // Set the resourceTypeName
1227     size = strlen(resourceTypeName) + 1;
1228     str = (char *) OCMalloc(size);
1229     if (!str) {
1230         goto exit;
1231     }
1232     strncpy(str, resourceTypeName, size);
1233     pointer->resourcetypename = str;
1234
1235     insertResourceType(resource, pointer);
1236     result = OC_STACK_OK;
1237
1238     exit: if (result != OC_STACK_OK) {
1239         OCFree(pointer);
1240         OCFree(str);
1241     }
1242
1243     return result;
1244 }
1245
1246 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
1247         const char *resourceInterfaceName)
1248 {
1249     OCResourceInterface *pointer = NULL;
1250     char *str = NULL;
1251     size_t size;
1252     OCStackResult result = OC_STACK_ERROR;
1253
1254     OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
1255
1256     // Validate parameters
1257     VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
1258
1259     TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
1260
1261     // Create the resourceinterface and insert it into the resource list
1262     pointer = (OCResourceInterface *) OCMalloc(sizeof(OCResourceInterface));
1263     if (!pointer) {
1264         goto exit;
1265     }
1266     memset(pointer, 0, sizeof(OCResourceInterface));
1267
1268     // Set the resourceinterface name
1269     size = strlen(resourceInterfaceName) + 1;
1270     str = (char *) OCMalloc(size);
1271     if (!str) {
1272         goto exit;
1273     }
1274     strncpy(str, resourceInterfaceName, size);
1275     pointer->name = str;
1276
1277     // Bind the resourceinterface to the resource
1278     insertResourceInterface(resource, pointer);
1279
1280     result = OC_STACK_OK;
1281
1282     exit: if (result != OC_STACK_OK) {
1283         OCFree(pointer);
1284         OCFree(str);
1285     }
1286
1287     return result;
1288 }
1289
1290 /**
1291  * Bind a resourcetype to a resource.
1292  *
1293  * @param handle - handle to the resource
1294  * @param resourceTypeName - name of resource type.  Example: "core.led"
1295  *
1296  * @return
1297  *     OC_STACK_OK    - no errors
1298  *     OC_STACK_ERROR - stack process error
1299  */
1300 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
1301         const char *resourceTypeName) {
1302
1303     OCStackResult result = OC_STACK_ERROR;
1304     OCResource *resource;
1305
1306     // Make sure resource exists
1307     resource = findResource((OCResource *) handle);
1308     if (!resource) {
1309         OC_LOG(ERROR, TAG, PCF("Resource not found"));
1310         return OC_STACK_ERROR;
1311     }
1312
1313     // call internal function
1314     result = BindResourceTypeToResource(resource, resourceTypeName);
1315
1316     #ifdef WITH_PRESENCE
1317     if(presenceResource.handle)
1318     {
1319         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1320         SendPresenceNotification(resource->rsrcType);
1321     }
1322     #endif
1323
1324     return result;
1325 }
1326
1327 /**
1328  * Bind a resourceinterface to a resource.
1329  *
1330  * @param handle - handle to the resource
1331  * @param resourceInterfaceName - name of resource interface.  Example: "oc.mi.b"
1332  *
1333  * @return
1334  *     OC_STACK_OK    - no errors
1335  *     OC_STACK_ERROR - stack process error
1336  */
1337
1338 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
1339         const char *resourceInterfaceName) {
1340
1341     OCStackResult result = OC_STACK_ERROR;
1342     OCResource *resource;
1343
1344     // Make sure resource exists
1345     resource = findResource((OCResource *) handle);
1346     if (!resource) {
1347         OC_LOG(ERROR, TAG, PCF("Resource not found"));
1348         return OC_STACK_ERROR;
1349     }
1350
1351     // call internal function
1352     result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
1353
1354     #ifdef WITH_PRESENCE
1355     if(presenceResource.handle)
1356     {
1357         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1358         SendPresenceNotification(resource->rsrcType);
1359     }
1360     #endif
1361
1362     return result;
1363 }
1364
1365 /**
1366  * Get the number of resources that have been created in the stack.
1367  *
1368  * @param numResources - pointer to count variable
1369  *
1370  * @return
1371  *     OC_STACK_OK    - no errors
1372  *     OC_STACK_ERROR - stack process error
1373
1374  */
1375 OCStackResult OCGetNumberOfResources(uint8_t *numResources) {
1376     OCResource *pointer = headResource;
1377
1378     OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
1379     VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
1380     *numResources = 0;
1381     while (pointer) {
1382         *numResources = *numResources + 1;
1383         pointer = pointer->next;
1384     }
1385     return OC_STACK_OK;
1386 }
1387
1388 /**
1389  * Get a resource handle by index.
1390  *
1391  * @param index - index of resource, 0 to Count - 1
1392  *
1393  * @return
1394  *    Resource handle - if found
1395  *    NULL - if not found
1396  */
1397 OCResourceHandle OCGetResourceHandle(uint8_t index) {
1398     OCResource *pointer = headResource;
1399     uint8_t i = 0;
1400
1401     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
1402
1403     // Iterate through the list
1404     while ((i < index) && pointer) {
1405         i++;
1406         pointer = pointer->next;
1407     }
1408     return (OCResourceHandle) pointer;
1409 }
1410
1411 /**
1412  * Delete resource specified by handle.  Deletes resource and all resourcetype and resourceinterface
1413  * linked lists.
1414  *
1415  * @param handle - handle of resource to be deleted
1416  *
1417  * @return
1418  *     OC_STACK_OK              - no errors
1419  *     OC_STACK_ERROR           - stack process error
1420  *     OC_STACK_NO_RESOURCE     - resource not found
1421  *     OC_STACK_INVALID_PARAM   - invalid param
1422  */
1423 OCStackResult OCDeleteResource(OCResourceHandle handle) {
1424     OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
1425
1426     if (!handle) {
1427         OC_LOG(ERROR, TAG, PCF("Invalid param"));
1428         return OC_STACK_INVALID_PARAM;
1429     }
1430
1431     OCResource *resource = findResource((OCResource *) handle);
1432     if (resource == NULL) {
1433         OC_LOG(ERROR, TAG, PCF("Resource not found"));
1434         return OC_STACK_NO_RESOURCE;
1435     }
1436
1437     if (deleteResource((OCResource *) handle) == 0) {
1438         OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
1439         return OC_STACK_ERROR;
1440     }
1441
1442     return OC_STACK_OK;
1443 }
1444
1445 /**
1446  * Get the URI of the resource specified by handle.
1447  *
1448  * @param handle - handle of resource
1449  * @return
1450  *    URI string - if resource found
1451  *    NULL - resource not found
1452  */
1453 const char *OCGetResourceUri(OCResourceHandle handle) {
1454     OCResource *resource;
1455     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
1456
1457     resource = findResource((OCResource *) handle);
1458     if (resource) {
1459         return resource->uri;
1460     }
1461     return (const char *) NULL;
1462 }
1463
1464 /**
1465  * Get the properties of the resource specified by handle.
1466  * NOTE: that after a resource is created, the OC_ACTIVE property is set
1467  * for the resource by the stack.
1468  *
1469  * @param handle - handle of resource
1470  * @return
1471  *    property bitmap - if resource found
1472  *    NULL - resource not found
1473  */
1474 uint8_t OCGetResourceProperties(OCResourceHandle handle) {
1475     OCResource *resource;
1476     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
1477
1478     resource = findResource((OCResource *) handle);
1479     if (resource) {
1480         return resource->resourceProperties;
1481     }
1482     return 0;
1483 }
1484
1485 /**
1486  * Get the number of resource types of the resource.
1487  *
1488  * @param handle - handle of resource
1489  * @param numResourceTypes - pointer to count variable
1490  *
1491  * @return
1492  *     OC_STACK_OK    - no errors
1493  *     OC_STACK_ERROR - stack process error
1494  */
1495 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
1496         uint8_t *numResourceTypes) {
1497     OCResource *resource;
1498     OCResourceType *pointer;
1499
1500     OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
1501     VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
1502     VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
1503
1504     *numResourceTypes = 0;
1505
1506     resource = findResource((OCResource *) handle);
1507     if (resource) {
1508         pointer = resource->rsrcType;
1509         while (pointer) {
1510             *numResourceTypes = *numResourceTypes + 1;
1511             pointer = pointer->next;
1512         }
1513     }
1514     return OC_STACK_OK;
1515 }
1516
1517 /**
1518  * Get name of resource type of the resource.
1519  *
1520  * @param handle - handle of resource
1521  * @param index - index of resource, 0 to Count - 1
1522  *
1523  * @return
1524  *    resource type name - if resource found
1525  *    NULL - resource not found
1526  */
1527 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index) {
1528     OCResourceType *resourceType;
1529
1530     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
1531
1532     resourceType = findResourceTypeAtIndex(handle, index);
1533     if (resourceType) {
1534         return resourceType->resourcetypename;
1535     }
1536     return (const char *) NULL;
1537 }
1538
1539
1540
1541 /**
1542  * Get the number of resource interfaces of the resource.
1543  *
1544  * @param handle - handle of resource
1545  * @param numResources - pointer to count variable
1546  *
1547  * @return
1548  *     OC_STACK_OK    - no errors
1549  *     OC_STACK_ERROR - stack process error
1550  */
1551 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
1552         uint8_t *numResourceInterfaces) {
1553     OCResourceInterface *pointer;
1554     OCResource *resource;
1555
1556     OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
1557
1558     VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
1559     VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
1560
1561     *numResourceInterfaces = 0;
1562     resource = findResource((OCResource *) handle);
1563     if (resource) {
1564         pointer = resource->rsrcInterface;
1565         while (pointer) {
1566             *numResourceInterfaces = *numResourceInterfaces + 1;
1567             pointer = pointer->next;
1568         }
1569     }
1570     return OC_STACK_OK;
1571 }
1572
1573 /**
1574  * Get name of resource interface of the resource.
1575  *
1576  * @param handle - handle of resource
1577  * @param index - index of resource, 0 to Count - 1
1578  *
1579  * @return
1580  *    resource interface name - if resource found
1581  *    NULL - resource not found
1582  */
1583 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index) {
1584     OCResourceInterface *resourceInterface;
1585
1586     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
1587
1588     resourceInterface = findResourceInterfaceAtIndex(handle, index);
1589     if (resourceInterface) {
1590         return resourceInterface->name;
1591     }
1592     return (const char *) NULL;
1593 }
1594
1595 /**
1596  * Get resource handle from the collection resource by index.
1597  *
1598  * @param collectionHandle - handle of collection resource
1599  * @param index - index of contained resource, 0 to Count - 1
1600  *
1601  * @return
1602  *    handle to resource - if resource found
1603  *    NULL - resource not found
1604  */
1605 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
1606         uint8_t index) {
1607     OCResource *resource;
1608
1609     OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
1610
1611     if (index >= MAX_CONTAINED_RESOURCES) {
1612         return NULL;
1613     }
1614
1615     resource = findResource((OCResource *) collectionHandle);
1616     if (!resource) {
1617         return NULL;
1618     }
1619
1620     return resource->rsrcResources[index];
1621 }
1622
1623 /**
1624  * Bind an entity handler to the resource.
1625  *
1626  * @param handle - handle to the resource that the contained resource is to be bound
1627  * @param entityHandler - entity handler function that is called by ocstack to handle requests, etc
1628  * @return
1629  *     OC_STACK_OK    - no errors
1630  *     OC_STACK_ERROR - stack process error
1631  */
1632 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
1633         OCEntityHandler entityHandler) {
1634     OCResource *resource;
1635
1636     OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
1637
1638     // Validate parameters
1639     VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
1640     //VERIFY_NON_NULL(entityHandler, ERROR, OC_STACK_INVALID_PARAM);
1641
1642     // Use the handle to find the resource in the resource linked list
1643     resource = findResource((OCResource *)handle);
1644     if (!resource) {
1645         OC_LOG(ERROR, TAG, PCF("Resource not found"));
1646         return OC_STACK_ERROR;
1647     }
1648
1649     // Bind the handler
1650     resource->entityHandler = entityHandler;
1651
1652     #ifdef WITH_PRESENCE
1653     if(presenceResource.handle)
1654     {
1655         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
1656         SendPresenceNotification(resource->rsrcType);
1657     }
1658     #endif
1659
1660     return OC_STACK_OK;
1661 }
1662
1663 /**
1664  * Get the entity handler for a resource.
1665  *
1666  * @param handle - handle of resource
1667  *
1668  * @return
1669  *    entity handler - if resource found
1670  *    NULL - resource not found
1671  */
1672 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) {
1673     OCResource *resource;
1674
1675     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
1676
1677     // Use the handle to find the resource in the resource linked list
1678     resource = findResource((OCResource *)handle);
1679     if (!resource) {
1680         OC_LOG(ERROR, TAG, PCF("Resource not found"));
1681         return NULL;
1682     }
1683
1684     // Bind the handler
1685     return resource->entityHandler;
1686 }
1687
1688 void incrementSequenceNumber(OCResource * resPtr)
1689 {
1690     // Increment the sequence number
1691     resPtr->sequenceNum += 1;
1692     if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
1693     {
1694         resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
1695     }
1696     return;
1697 }
1698
1699 #ifdef WITH_PRESENCE
1700 /**
1701  * Notify Presence subscribers that a resource has been modified
1702  *
1703  * @param resourceType - Handle to the resourceType linked list of resource
1704  *                       that was modified.
1705  * @param qos          - Quality Of Service
1706  *
1707  */
1708 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
1709 {
1710     OCResource *resPtr = NULL;
1711     OCStackResult result;
1712     OCMethod method = OC_REST_PRESENCE;
1713     uint32_t maxAge = 0;
1714     resPtr = findResource((OCResource *) presenceResource.handle);
1715     if(NULL == resPtr)
1716     {
1717         return OC_STACK_NO_RESOURCE;
1718     }
1719     if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
1720     {
1721         maxAge = presenceResource.presenceTTL;
1722     }
1723     else
1724     {
1725         maxAge = 0;
1726     }
1727
1728     result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
1729     return result;
1730 }
1731 #endif
1732
1733 /**
1734  * Notify observers that an observed value has changed.
1735  *
1736  * @param handle - handle of resource
1737  *
1738  * @return
1739  *     OC_STACK_OK    - no errors
1740  *     OC_STACK_NO_RESOURCE - invalid resource handle
1741  *     OC_STACK_NO_OBSERVERS - no more observers intrested in resource
1742  */
1743 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos) {
1744
1745     OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
1746
1747     OCResource *resPtr = NULL;
1748     OCStackResult result;
1749     OCMethod method = OC_REST_NOMETHOD;
1750     uint32_t maxAge = 0;
1751
1752     OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
1753     #ifdef WITH_PRESENCE
1754     if(handle == presenceResource.handle)
1755     {
1756         return OC_STACK_OK;
1757     }
1758     #endif // WITH_PRESENCE
1759     VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
1760
1761     // Verify that the resource exists
1762     resPtr = findResource ((OCResource *) handle);
1763     if (NULL == resPtr)
1764     {
1765         return OC_STACK_NO_RESOURCE;
1766     }
1767     else
1768     {
1769         //only increment in the case of regular observing (not presence)
1770         incrementSequenceNumber(resPtr);
1771         method = OC_REST_OBSERVE;
1772         maxAge = MAX_OBSERVE_AGE;
1773         #ifdef WITH_PRESENCE
1774         result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
1775         #else
1776         result = SendAllObserverNotification (method, resPtr, maxAge, qos);
1777         #endif
1778         return result;
1779     }
1780 }
1781
1782 OCStackResult
1783 OCNotifyListOfObservers (OCResourceHandle handle,
1784                          OCObservationId  *obsIdList,
1785                          uint8_t          numberOfIds,
1786                          unsigned char    *notificationJSONPayload,
1787                          OCQualityOfService qos)
1788 {
1789     OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
1790
1791     OCResource *resPtr = NULL;
1792     //TODO: we should allow the server to define this
1793     uint32_t maxAge = MAX_OBSERVE_AGE;
1794
1795     VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
1796     VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
1797     VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
1798
1799     // Verify that the resource exists
1800     resPtr = findResource ((OCResource *) handle);
1801     if (NULL == resPtr || myStackMode == OC_CLIENT)
1802     {
1803         return OC_STACK_NO_RESOURCE;
1804     }
1805     else
1806     {
1807         incrementSequenceNumber(resPtr);
1808     }
1809     return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
1810             notificationJSONPayload, maxAge, qos));
1811 }
1812
1813 /**
1814  * Send a response to a request.
1815  * The response can be a regular, slow, or block (i.e. a response that
1816  * is too large to be sent in a single PDU and must span multiple transmissions)
1817  *
1818  * @param response - pointer to structure that contains response parameters
1819  *
1820  * @return
1821  *     OC_STACK_OK                         - No errors; Success
1822  *     OC_STACK_INVALID_PARAM              - Invalid pointer to OCServerResponse
1823  *     OC_STACK_INVALID_REQUEST_HANDLE     - Request handle not found
1824  *     OC_STACK_PERSISTENT_BUFFER_REQUIRED - Block transfer needed for response, so a
1825  *                                           persistent response buffer is necessary
1826  */
1827 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
1828 {
1829     OCStackResult result = OC_STACK_ERROR;
1830     OCServerRequest *serverRequest = NULL;
1831
1832     OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
1833
1834     // Validate input parameters
1835     VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
1836     VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
1837
1838     // TODO: Placeholder for creating a response entry when implementing
1839     // block transfer feature
1840
1841     // If a response payload is present, check if block transfer is required
1842     if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
1843             (const char *)ehResponse->payload, ehResponse->payloadSize))
1844     {
1845         OC_LOG(INFO, TAG, PCF("Block transfer required"));
1846
1847         // Persistent response buffer is needed for block transfer
1848         if (!ehResponse->persistentBufferFlag)
1849         {
1850             OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
1851             return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
1852         }
1853         // TODO: Placeholder for block transfer handling
1854         // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
1855             // when implementing the block transfer feature
1856     }
1857     else
1858     {
1859         // Normal response
1860
1861         // Get pointer to request info
1862         serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
1863         if(serverRequest)
1864         {
1865             result = serverRequest->ehResponseHandler(ehResponse);
1866         }
1867     }
1868     return result;
1869 }
1870
1871 /**
1872  * Cancel a response.  Applies to a block response
1873  *
1874  * @param responseHandle - response handle set by stack in OCServerResponse after
1875  *                         OCDoResponse is called
1876  *
1877  * @return
1878  *     OC_STACK_OK               - No errors; Success
1879  *     OC_STACK_INVALID_PARAM    - The handle provided is invalid.
1880  */
1881 OCStackResult OCCancelResponse(OCResponseHandle responseHandle)
1882 {
1883     OCStackResult result = OC_STACK_NOTIMPL;
1884
1885     OC_LOG(INFO, TAG, PCF("Entering OCCancelResponse"));
1886
1887     // TODO: validate response handle
1888
1889     return result;
1890 }
1891
1892 //-----------------------------------------------------------------------------
1893 // Private internal function definitions
1894 //-----------------------------------------------------------------------------
1895 /**
1896  * Generate handle of OCDoResource invocation for callback management.
1897  */
1898 static OCDoHandle GenerateInvocationHandle()
1899 {
1900     OCDoHandle handle = NULL;
1901     // Generate token here, it will be deleted when the transaction is deleted
1902     handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
1903     if (handle)
1904     {
1905         OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
1906     }
1907
1908     return handle;
1909 }
1910 #ifdef WITH_PRESENCE
1911 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
1912         OCResourceProperty resourceProperties, uint8_t enable)
1913 {
1914     if (resourceProperties
1915             > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW)) {
1916         OC_LOG(ERROR, TAG, PCF("Invalid property"));
1917         return OC_STACK_INVALID_PARAM;
1918     }
1919     if(!enable)
1920     {
1921         *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
1922     }
1923     else
1924     {
1925         *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
1926     }
1927     return OC_STACK_OK;
1928 }
1929 #endif
1930
1931 /**
1932  * Initialize resource data structures, variables, etc.
1933  */
1934 OCStackResult initResources() {
1935     OCStackResult result = OC_STACK_OK;
1936     // Init application resource vars
1937     headResource = NULL;
1938     // Init Virtual Resources
1939     #ifdef WITH_PRESENCE
1940     presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL;
1941     //presenceResource.token = OCGenerateCoAPToken();
1942     result = OCCreateResource(&presenceResource.handle,
1943             OC_RSRVD_RESOURCE_TYPE_PRESENCE,
1944             "core.r",
1945             OC_PRESENCE_URI,
1946             NULL,
1947             OC_OBSERVABLE);
1948     //make resource inactive
1949     result = OCChangeResourceProperty(
1950             &(((OCResource *) presenceResource.handle)->resourceProperties),
1951             OC_ACTIVE, 0);
1952     #endif
1953     return result;
1954 }
1955
1956 /**
1957  * Add a resource to the end of the linked list of resources.
1958  *
1959  * @param resource - resource to be added
1960  */
1961 void insertResource(OCResource *resource) {
1962     OCResource *pointer;
1963
1964     if (!headResource) {
1965         headResource = resource;
1966     } else {
1967         pointer = headResource;
1968
1969         while (pointer->next) {
1970             pointer = pointer->next;
1971         }
1972         pointer->next = resource;
1973     }
1974     resource->next = NULL;
1975 }
1976
1977 /**
1978  * Find a resource in the linked list of resources.
1979  *
1980  * @param resource - resource to be found
1981  * @return
1982  *     NULL                - resource not found
1983  *     pointer to resource - pointer to resource that was found in the linked list
1984  */
1985 OCResource *findResource(OCResource *resource) {
1986     OCResource *pointer = headResource;
1987
1988     while (pointer) {
1989         if (pointer == resource) {
1990             return resource;
1991         }
1992         pointer = pointer->next;
1993     }
1994     return NULL;
1995 }
1996
1997 void deleteAllResources()
1998 {
1999     OCResource *pointer = headResource;
2000     OCResource *temp;
2001
2002     while (pointer)
2003     {
2004         temp = pointer->next;
2005         #ifdef WITH_PRESENCE
2006         if(pointer != (OCResource *) presenceResource.handle)
2007         {
2008             #endif // WITH_PRESENCE
2009             deleteResource(pointer);
2010             #ifdef WITH_PRESENCE
2011         }
2012         #endif // WITH_PRESENCE
2013         pointer = temp;
2014     }
2015
2016     #ifdef WITH_PRESENCE
2017     // Ensure that the last resource to be deleted is the presence resource. This allows for all
2018     // presence notification attributed to their deletion to be processed.
2019     deleteResource((OCResource *) presenceResource.handle);
2020     #endif // WITH_PRESENCE
2021 }
2022
2023 /**
2024  * Delete the resource from the linked list.
2025  *
2026  * @param resource - resource to be deleted
2027  * @return
2028  *    0 - error
2029  *    1 - success
2030  */
2031 int deleteResource(OCResource *resource) {
2032     OCResource *prev = NULL;
2033     OCResource *temp;
2034
2035     temp = headResource;
2036     while (temp) {
2037         if (temp == resource) {
2038             // Invalidate all Resource Properties.
2039             resource->resourceProperties = (OCResourceProperty) 0;
2040             #ifdef WITH_PRESENCE
2041             if(resource != (OCResource *) presenceResource.handle)
2042             {
2043             #endif // WITH_PRESENCE
2044                 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
2045             #ifdef WITH_PRESENCE
2046             }
2047
2048             if(presenceResource.handle)
2049             {
2050                 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2051                 if(resource != (OCResource *) presenceResource.handle)
2052                 {
2053                     SendPresenceNotification(resource->rsrcType);
2054                 }
2055                 else
2056                 {
2057                     SendPresenceNotification(NULL);
2058                 }
2059             }
2060         #endif
2061
2062             if (temp == headResource) {
2063                 headResource = temp->next;
2064             } else {
2065                 prev->next = temp->next;
2066             }
2067
2068             deleteResourceElements(temp);
2069             OCFree(temp);
2070             return 1;
2071         } else {
2072             prev = temp;
2073             temp = temp->next;
2074         }
2075     }
2076
2077     return 0;
2078 }
2079
2080 /**
2081  * Delete all of the dynamically allocated elements that were created for the resource.
2082  *
2083  * @param resource - specified resource
2084  */
2085 void deleteResourceElements(OCResource *resource) {
2086     if (!resource) {
2087         return;
2088     }
2089
2090     // remove URI
2091     OCFree(resource->uri);
2092
2093     // Delete resourcetype linked list
2094     deleteResourceType(resource->rsrcType);
2095
2096     // Delete resourceinterface linked list
2097     deleteResourceInterface(resource->rsrcInterface);
2098 }
2099
2100 /**
2101  * Delete all of the dynamically allocated elements that were created for the resource type.
2102  *
2103  * @param resourceType - specified resource type
2104  */
2105 void deleteResourceType(OCResourceType *resourceType) {
2106     OCResourceType *pointer = resourceType;
2107     OCResourceType *next;
2108
2109     while (pointer) {
2110         next = pointer->next;
2111         OCFree(pointer->resourcetypename);
2112         OCFree(pointer);
2113         pointer = next;
2114     }
2115 }
2116
2117 /**
2118  * Delete all of the dynamically allocated elements that were created for the resource interface.
2119  *
2120  * @param resourceInterface - specified resource interface
2121  */
2122 void deleteResourceInterface(OCResourceInterface *resourceInterface) {
2123     OCResourceInterface *pointer = resourceInterface;
2124     OCResourceInterface *next;
2125
2126     while (pointer) {
2127         next = pointer->next;
2128         OCFree(pointer->name);
2129         OCFree(pointer);
2130         pointer = next;
2131     }
2132 }
2133
2134 /**
2135  * Insert a resource type into a resource's resource type linked list.
2136  *
2137  * @param resource - resource where resource type is to be inserted
2138  * @param resourceType - resource type to be inserted
2139  */
2140 void insertResourceType(OCResource *resource, OCResourceType *resourceType) {
2141     OCResourceType *pointer;
2142
2143     if (resource && !resource->rsrcType) {
2144         resource->rsrcType = resourceType;
2145     } else {
2146         if(resource)
2147         {
2148             pointer = resource->rsrcType;
2149         }
2150         else
2151         {
2152             pointer = resourceType;
2153         }
2154         while (pointer->next) {
2155             pointer = pointer->next;
2156         }
2157         pointer->next = resourceType;
2158     }
2159     resourceType->next = NULL;
2160 }
2161
2162 /**
2163  * Get a resource type at the specified index within a resource.
2164  *
2165  * @param handle - handle of resource
2166  * @param index - index of resource type
2167  *
2168  * @return
2169  *    resourcetype - if found
2170  *    NULL - not found
2171  */
2172 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index) {
2173     OCResource *resource;
2174     OCResourceType *pointer;
2175     uint8_t i;
2176
2177     // Find the specified resource
2178     resource = findResource((OCResource *) handle);
2179     if (!resource) {
2180         return NULL;
2181     }
2182
2183     // Make sure a resource has a resourcetype
2184     if (!resource->rsrcType) {
2185         return NULL;
2186     }
2187
2188     // Iterate through the list
2189     pointer = resource->rsrcType;
2190     i = 0;
2191     while ((i < index) && pointer) {
2192         i++;
2193         pointer = pointer->next;
2194     }
2195     return pointer;
2196 }
2197
2198 /**
2199  * Finds a resource type in an OCResourceType link-list.
2200  *
2201  * @param resourceTypeList - the link-list to be searched through
2202  * @param resourceTypeName - the key to search for
2203  *
2204  * @return
2205  *      resourceType that matches the key (ie. resourceTypeName)
2206  *      NULL - either an invalid parameter or this function was unable to find the key.
2207  */
2208 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
2209 {
2210     if(resourceTypeList && resourceTypeName)
2211     {
2212         OCResourceType * rtPointer = resourceTypeList;
2213         while(resourceTypeName && rtPointer)
2214         {
2215             if(rtPointer->resourcetypename &&
2216                     strcmp(resourceTypeName, (const char *)
2217                     (rtPointer->resourcetypename)) == 0)
2218             {
2219                 break;
2220             }
2221             rtPointer = rtPointer->next;
2222         }
2223         return rtPointer;
2224     }
2225     return NULL;
2226 }
2227 /**
2228  * Insert a resource interface into a resource's resource interface linked list.
2229  *
2230  * @param resource - resource where resource interface is to be inserted
2231  * @param resourceInterface - resource interface to be inserted
2232  */
2233 void insertResourceInterface(OCResource *resource,
2234         OCResourceInterface *resourceInterface) {
2235     OCResourceInterface *pointer;
2236
2237     if (!resource->rsrcInterface) {
2238         resource->rsrcInterface = resourceInterface;
2239     } else {
2240         pointer = resource->rsrcInterface;
2241         while (pointer->next) {
2242             pointer = pointer->next;
2243         }
2244         pointer->next = resourceInterface;
2245     }
2246     resourceInterface->next = NULL;
2247 }
2248
2249 /**
2250  * Get a resource interface at the specified index within a resource.
2251  *
2252  * @param handle - handle of resource
2253  * @param index - index of resource interface
2254  *
2255  * @return
2256  *    resourceinterface - if found
2257  *    NULL - not found
2258  */
2259 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
2260         uint8_t index) {
2261     OCResource *resource;
2262     OCResourceInterface *pointer;
2263     uint8_t i = 0;
2264
2265     // Find the specified resource
2266     resource = findResource((OCResource *) handle);
2267     if (!resource) {
2268         return NULL;
2269     }
2270
2271     // Make sure a resource has a resourceinterface
2272     if (!resource->rsrcInterface) {
2273         return NULL;
2274     }
2275
2276     // Iterate through the list
2277     pointer = resource->rsrcInterface;
2278
2279     while ((i < index) && pointer) {
2280         i++;
2281         pointer = pointer->next;
2282     }
2283     return pointer;
2284 }
2285
2286 /**
2287  * Determine if a request/response must be sent in a block transfer because it is too large to be
2288  * sent in a single PDU.  This function can be used for either a request or a response
2289  *
2290  * @param request  - NULL or pointer to request
2291  * @param response - NULL or pointer to response
2292  * @param size     - 0 or size of the request/response.  If 0, strlen is used for determining
2293  *                   the length of the request/response
2294  *
2295  * @return
2296  *    0 - packet transfer NOT required (i.e. normal request/response)
2297  *    1 - packet transfer required (i.e. block transfer needed)
2298  */
2299 uint8_t OCIsPacketTransferRequired(const char *request, const char *response, uint16_t size)
2300 {
2301     uint8_t result = 0;
2302
2303     // Determine if we are checking a request or a response
2304     if (request)
2305     {
2306         // If size is greater than 0, use it for the request size value, otherwise
2307         // assume request is null terminated and use strlen for size value
2308         if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
2309         {
2310             result = 1;
2311         }
2312     }
2313     else if (response)
2314     {
2315         // If size is greater than 0, use it for the response size value, otherwise
2316         // assume response is null terminated and use strlen for size value
2317         if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
2318         {
2319             result = 1;
2320         }
2321     }
2322     return result;
2323 }
2324
2325 /**
2326  * Retrieves a resource type based upon a uri string if the uri string contains only just one
2327  * resource attribute (and that has to be of type "rt").
2328  *
2329  * @remark This API malloc's memory for the resource type and newURI. Do not malloc resourceType
2330  * or newURI before passing in.
2331  *
2332  * @param uri - Valid URI for "requiredUri" parameter to OCDoResource API.
2333  * @param resourceType - The resource type to be populated; pass by reference.
2334  * @param newURI - Return URI without resourceType appended to the end of it. This is used to
2335  *                 ensure that the uri parameter is not modified; pass by reference.
2336  *
2337  * @return
2338  *  OC_STACK_INVALID_URI   - Returns this if the URI is invalid/NULL.
2339  *  OC_STACK_INVALID_PARAM - Returns this if the resourceType parameter is invalid/NULL.
2340  *  OC_STACK_OK            - Success
2341  */
2342 OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI)
2343 {
2344     if(!uri)
2345     {
2346         return OC_STACK_INVALID_URI;
2347     }
2348     if(!resourceType || !newURI)
2349     {
2350         return OC_STACK_INVALID_PARAM;
2351     }
2352     char * leftToken = NULL;
2353     char * tempURI = (char *) OCMalloc(strlen(uri) + 1);
2354     if(!tempURI)
2355     {
2356         goto exit;
2357     }
2358     strcpy(tempURI, uri);
2359     leftToken = strtok((char *)tempURI, "?");
2360
2361     while(leftToken != NULL)
2362     {
2363         if(strncmp(leftToken, "rt=", 3) == 0)
2364         {
2365             *resourceType = (unsigned char *) OCMalloc(strlen(leftToken)-3);
2366             if(!*resourceType)
2367             {
2368                 goto exit;
2369             }
2370             strcpy((char *)*resourceType, ((const char *)&leftToken[3]));
2371             break;
2372         }
2373         leftToken = strtok(NULL, "?");
2374     }
2375
2376     *newURI = tempURI;
2377
2378     return OC_STACK_OK;
2379
2380     exit:
2381         return OC_STACK_NO_MEMORY;
2382 }