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