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