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