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