d8869def094a9dae0cd9b85a1d7b36365eb773e1
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / tizen / SimpleClientServer / ocserver.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //
6 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 //      http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // Unless required by applicable law or agreed to in writing, software
15 // distributed under the License is distributed on an "AS IS" BASIS,
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 // See the License for the specific language governing permissions and
18 // limitations under the License.
19 //
20 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21
22 #include <glib.h>
23 #include <stdio.h>
24 #include <iostream>
25 #include <string.h>
26 #include <string>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <signal.h>
30 #include <pthread.h>
31 #include <array>
32 #include "ocstack.h"
33 #include "logger.h"
34 #include "ocpayload.h"
35 #include "ocserver.h"
36 using namespace std;
37
38 //string length of "/a/light/" + std::numeric_limits<int>::digits10 + '\0'"
39 // 9 + 9 + 1 = 19
40 const int URI_MAXSIZE = 19;
41
42 static int gObserveNotifyType = 3;
43
44 int gQuitFlag = 0;
45 int gLightUnderObservation = 0;
46
47 static LightResource Light;
48 // This variable determines instance number of the Light resource.
49 // Used by POST method to create a new instance of Light resource.
50 static int gCurrLightInstance = 0;
51
52 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
53
54 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
55
56 #ifdef WITH_PRESENCE
57 static int stopPresenceCount = 10;
58 #define numPresenceResources (2)
59 #endif
60
61 char *gResourceUri= (char *)"/a/light";
62 const char *dateOfManufacture = "myDateOfManufacture";
63 const char *deviceName = "myDeviceName";
64 const char *deviceUUID = "myDeviceUUID";
65 const char *firmwareVersion = "myFirmwareVersion";
66 const char *manufacturerName = "myName";
67 const char *operatingSystemVersion = "myOS";
68 const char *hardwareVersion = "myHardwareVersion";
69 const char* platformID = "myPlatformID";
70 const char *manufacturerUrl = "myManufacturerUrl";
71 const char *modelNumber = "myModelNumber";
72 const char *platformVersion = "myPlatformVersion";
73 const char *supportUrl = "mySupportUrl";
74 const char *version = "myVersion";
75 const char *systemTime = "2015-05-15T11.04";
76
77 // Entity handler should check for resourceTypeName and ResourceInterface in order to GET
78 // the existence of a known resource
79 const char *resourceTypeName = "core.light";
80 const char *resourceInterface = OC_RSRVD_INTERFACE_DEFAULT;
81
82 OCPlatformInfo platformInfo;
83 OCDeviceInfo deviceInfo;
84
85 OCRepPayload* getPayload(const char* uri, int64_t power, bool state)
86 {
87     OCRepPayload* payload = OCRepPayloadCreate();
88     if(!payload)
89     {
90         cout << "Failed to allocate Payload";
91         return nullptr;
92     }
93
94     OCRepPayloadSetUri(payload, uri);
95     OCRepPayloadSetPropBool(payload, "state", state);
96     OCRepPayloadSetPropInt(payload, "power", power);
97
98     return payload;
99 }
100
101 //This function takes the request as an input and returns the response
102 OCRepPayload* constructResponse(OCEntityHandlerRequest *ehRequest)
103 {
104     if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
105     {
106         cout << "Incoming payload not a representation";
107         return nullptr;
108     }
109
110     OCRepPayload* input = reinterpret_cast<OCRepPayload*>(ehRequest->payload);
111
112     LightResource *currLightResource = &Light;
113
114     if (ehRequest->resource == gLightInstance[0].handle)
115     {
116         currLightResource = &gLightInstance[0];
117         gResourceUri = (char *) "a/light/0";
118     }
119     else if (ehRequest->resource == gLightInstance[1].handle)
120     {
121         currLightResource = &gLightInstance[1];
122         gResourceUri = (char *) "a/light/1";
123     }
124
125     if(OC_REST_PUT == ehRequest->method)
126     {
127         // Get pointer to query
128         int64_t pow;
129         if(OCRepPayloadGetPropInt(input, "power", &pow))
130         {
131             currLightResource->power =pow;
132         }
133
134         bool state;
135         if(OCRepPayloadGetPropBool(input, "state", &state))
136         {
137             currLightResource->state = state;
138         }
139     }
140
141     return getPayload(gResourceUri, currLightResource->power, currLightResource->state);
142 }
143
144 /*
145  * Very simple example of query parsing.
146  * The query may have multiple filters separated by ';'.
147  * It is upto the entity handler to parse the query for the individual filters,
148  * VALIDATE them and respond as it sees fit.
149
150  * This function only returns false if the query is exactly "power<X" and
151  * current power is greater than X. If X cannot be parsed for an int,
152  * true is returned.
153  */
154 bool checkIfQueryForPowerPassed(char * query)
155 {
156     if (query && strncmp(query, "power<", strlen("power<")) == 0)
157     {
158         char * pointerToOperator = strstr(query, "<");
159
160         if (pointerToOperator)
161         {
162             int powerRequested = atoi(pointerToOperator + 1);
163             if (Light.power > powerRequested)
164             {
165                 cout << "\nCurrent power: "<< Light.power << "Requested: " << powerRequested;
166                 return false;
167             }
168         }
169     }
170     return true;
171 }
172
173 /*
174  * Application should validate and process these as desired.
175  */
176 OCEntityHandlerResult ValidateQueryParams (OCEntityHandlerRequest *entityHandlerRequest)
177 {
178     cout << "\nReceived query %s" << entityHandlerRequest->query;
179     cout << "\nNot processing query";
180     return OC_EH_OK;
181 }
182
183 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
184         OCRepPayload **payload)
185 {
186     OCEntityHandlerResult ehResult;
187     bool queryPassed = checkIfQueryForPowerPassed(ehRequest->query);
188
189     // Empty payload if the query has no match.
190     if (queryPassed)
191     {
192         OCRepPayload *getResp = constructResponse(ehRequest);
193         if(!getResp)
194         {
195             cout << "\nconstructResponse failed";
196             return OC_EH_ERROR;
197         }
198
199         *payload = getResp;
200         ehResult = OC_EH_OK;
201     }
202     else
203     {
204         ehResult = OC_EH_OK;
205     }
206
207     return ehResult;
208 }
209
210 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
211         OCRepPayload** payload)
212 {
213     OCEntityHandlerResult ehResult;
214     OCRepPayload *putResp = constructResponse(ehRequest);
215
216     if(!putResp)
217     {
218         cout << "\nFailed to construct response";
219         return OC_EH_ERROR;
220     }
221
222     *payload = putResp;
223     ehResult = OC_EH_OK;
224
225     return ehResult;
226 }
227
228 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
229         OCEntityHandlerResponse *response, OCRepPayload** payload)
230 {
231     OCEntityHandlerResult ehResult = OC_EH_OK;
232     OCRepPayload *respPLPost_light = nullptr;
233
234     /*
235      * The entity handler determines how to process a POST request.
236      * Per the REST paradigm, POST can also be used to update representation of existing
237      * resource or create a new resource.
238      * In the sample below, if the POST is for /a/light then a new instance of the Light
239      * resource is created with default representation (if representation is included in
240      * POST payload it can be used as initial values) as long as the instance is
241      * lesser than max new instance count. Once max instance count is reached, POST on
242      * /a/light updated the representation of /a/light (just like PUT).
243      */
244
245     if (ehRequest->resource == Light.handle)
246     {
247         if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
248         {
249             // Create new Light instance
250             char newLightUri[URI_MAXSIZE];
251             snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
252
253             respPLPost_light = OCRepPayloadCreate();
254             OCRepPayloadSetUri(respPLPost_light, gResourceUri);
255             OCRepPayloadSetPropString(respPLPost_light, "createduri", newLightUri);
256
257             if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
258             {
259                 cout << "\nCreated new Light instance";
260                 gLightInstance[gCurrLightInstance].state = 0;
261                 gLightInstance[gCurrLightInstance].power = 0;
262                 gCurrLightInstance++;
263                 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
264                 ehResult = OC_EH_RESOURCE_CREATED;
265             }
266         }
267         else
268         {
269             // Update repesentation of /a/light
270             Light.state = true;
271             Light.power = 11;
272             respPLPost_light = constructResponse(ehRequest);
273         }
274     }
275     else
276     {
277         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
278         {
279             if (ehRequest->resource == gLightInstance[i].handle)
280             {
281                 gLightInstance[i].state = true;
282                 gLightInstance[i].power = 22;
283                 if (i == 0)
284                 {
285                     respPLPost_light = constructResponse(ehRequest);
286                     break;
287                 }
288                 else if (i == 1)
289                 {
290                     respPLPost_light = constructResponse(ehRequest);
291                 }
292             }
293         }
294     }
295
296     if ((respPLPost_light != NULL))
297     {
298         *payload = respPLPost_light;
299     }
300     else
301     {
302         cout << "\n Payload was NULL";
303         ehResult = OC_EH_ERROR;
304     }
305
306     return ehResult;
307 }
308
309 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest)
310 {
311     if(ehRequest == NULL)
312     {
313         cout << "\nThe ehRequest is NULL";
314         return OC_EH_ERROR;
315     }
316     OCEntityHandlerResult ehResult = OC_EH_OK;
317
318     cout << "\nExecuting " << __func__ << " for resource " << ehRequest->resource;
319
320     /*
321      * In the sample below, the application will:
322      * 1a. pass the delete request to the c stack
323      * 1b. internally, the c stack figures out what needs to be done and does it accordingly
324      *    (e.g. send observers notification, remove observers...)
325      * 1c. the c stack returns with the result whether the request is fullfilled.
326      * 2. optionally, app removes observers out of its array 'interestedObservers'
327      */
328
329     if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
330     {
331         //Step 1: Ask stack to do the work.
332         OCStackResult result = OCDeleteResource(ehRequest->resource);
333
334         if (result == OC_STACK_OK)
335         {
336             cout << "\nDelete Resource operation succeeded.";
337             ehResult = OC_EH_OK;
338
339             //Step 2: clear observers who wanted to observe this resource at the app level.
340             for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
341             {
342                 if (interestedObservers[i].resourceHandle == ehRequest->resource)
343                 {
344                     interestedObservers[i].valid = false;
345                     interestedObservers[i].observationId = 0;
346                     interestedObservers[i].resourceHandle = NULL;
347                 }
348             }
349         }
350         else if (result == OC_STACK_NO_RESOURCE)
351         {
352             cout << "\nThe resource doesn't exist or it might have been deleted.";
353             ehResult = OC_EH_RESOURCE_DELETED;
354         }
355         else
356         {
357             cout << "\nEncountered error from OCDeleteResource().";
358             ehResult = OC_EH_ERROR;
359         }
360     }
361     else if (ehRequest->resource != Light.handle)
362     {
363         //Let's this app not supporting DELETE on some resources so
364         //consider the DELETE request is received for a non-support resource.
365         cout << "\nThe request is received for a non-support resource.";
366         ehResult = OC_EH_FORBIDDEN;
367     }
368
369     return ehResult;
370 }
371
372 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest)
373 {
374     cout << "\nExecuting " << __func__;
375
376     return OC_EH_RESOURCE_NOT_FOUND;
377 }
378
379 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
380 {
381     cout << "\nReceived observation registration request with observation Id "
382          << ehRequest->obsInfo.obsId;
383     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
384     {
385         if (interestedObservers[i].valid == false)
386         {
387             interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
388             interestedObservers[i].valid = true;
389             gLightUnderObservation = 1;
390             break;
391         }
392     }
393 }
394
395 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
396 {
397     bool clientStillObserving = false;
398
399     cout << "\nReceived observation deregistration request for observation Id "
400          << ehRequest->obsInfo.obsId;
401     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
402     {
403         if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
404         {
405             interestedObservers[i].valid = false;
406         }
407         if (interestedObservers[i].valid == true)
408         {
409             // Even if there is one single client observing we continue notifying entity handler
410             clientStillObserving = true;
411         }
412     }
413     if (clientStillObserving == false)
414         gLightUnderObservation = 0;
415 }
416
417 OCEntityHandlerResult
418 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
419         OCEntityHandlerRequest *entityHandlerRequest, char* uri, void* callbackParam)
420 {
421     cout << "\nInside device default entity handler - flags: " << flag << ", uri: %s" << uri;
422
423     OCEntityHandlerResult ehResult = OC_EH_OK;
424     OCEntityHandlerResponse response;
425
426     // Validate pointer
427     if (!entityHandlerRequest)
428     {
429         cout << "\nInvalid request pointer";
430         return OC_EH_ERROR;
431     }
432     // Initialize certain response fields
433     response.numSendVendorSpecificHeaderOptions = 0;
434     memset(response.sendVendorSpecificHeaderOptions, 0,
435             sizeof response.sendVendorSpecificHeaderOptions);
436     memset(response.resourceUri, 0, sizeof response.resourceUri);
437     OCRepPayload* payload = nullptr;
438
439
440     if (flag & OC_REQUEST_FLAG)
441     {
442         cout << "\nFlag includes OC_REQUEST_FLAG";
443
444         if (entityHandlerRequest->resource == NULL)
445         {
446             cout << "\nReceived request from client to a non-existing resource";
447             ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest);
448         }
449         else if (OC_REST_GET == entityHandlerRequest->method)
450         {
451             cout << "\nReceived OC_REST_GET from client";
452             ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
453         }
454         else if (OC_REST_PUT == entityHandlerRequest->method)
455         {
456             cout << "\nReceived OC_REST_PUT from client";
457             ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
458         }
459         else if (OC_REST_DELETE == entityHandlerRequest->method)
460         {
461             cout << "\nReceived OC_REST_DELETE from client";
462             ehResult = ProcessDeleteRequest (entityHandlerRequest);
463         }
464         else
465         {
466             cout << "\nReceived unsupported method " << entityHandlerRequest->method
467                 << " from client";
468             ehResult = OC_EH_ERROR;
469         }
470                // If the result isn't an error or forbidden, send response
471         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
472         {
473             // Format the response.  Note this requires some info about the request
474             response.requestHandle = entityHandlerRequest->requestHandle;
475             response.resourceHandle = entityHandlerRequest->resource;
476             response.ehResult = ehResult;
477             response.payload = reinterpret_cast<OCPayload*>(payload);
478             // Indicate that response is NOT in a persistent buffer
479             response.persistentBufferFlag = 0;
480
481             // Send the response
482             if (OCDoResponse(&response) != OC_STACK_OK)
483             {
484                 cout << "\nError sending response";
485                 ehResult = OC_EH_ERROR;
486             }
487         }
488     }
489     if (flag & OC_OBSERVE_FLAG)
490     {
491         cout << "\nFlag includes OC_OBSERVE_FLAG";
492         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
493         {
494             cout << "\nReceived OC_OBSERVE_REGISTER from client";
495         }
496         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
497         {
498             cout << "\nReceived OC_OBSERVE_DEREGISTER from client";
499         }
500     }
501
502     return ehResult;
503 }
504
505 OCEntityHandlerResult
506 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
507         OCEntityHandlerRequest *entityHandlerRequest, void* callbackParam)
508 {
509     // This is callback is associated with the 2 presence notification
510     // resources. They are non-operational.
511     return OC_EH_OK;
512 }
513
514 OCEntityHandlerResult
515 OCEntityHandlerCb (OCEntityHandlerFlag flag,
516         OCEntityHandlerRequest *entityHandlerRequest, void* callback)
517 {
518     cout << "\nInside entity handler - flags: " << flag;
519
520     OCEntityHandlerResult ehResult = OC_EH_OK;
521     OCEntityHandlerResponse response;
522
523     // Validate pointer
524     if (!entityHandlerRequest)
525     {
526         cout << "\nInvalid request pointer";
527         return OC_EH_ERROR;
528     }
529
530     // Initialize certain response fields
531     response.numSendVendorSpecificHeaderOptions = 0;
532     memset(response.sendVendorSpecificHeaderOptions,
533             0, sizeof response.sendVendorSpecificHeaderOptions);
534     memset(response.resourceUri, 0, sizeof response.resourceUri);
535     OCRepPayload* payload = nullptr;
536
537     if (flag & OC_REQUEST_FLAG)
538     {
539         cout << "\n=================================\n";
540         cout << "\nFlag includes OC_REQUEST_FLAG\n";
541
542         if (OC_REST_GET == entityHandlerRequest->method)
543         {
544             cout << "\nReceived OC_REST_GET from client";
545             ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
546             cout << "\n=================================\n";
547         }
548         else if (OC_REST_PUT == entityHandlerRequest->method)
549         {
550             cout << "\nReceived OC_REST_PUT from client";
551             ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
552             cout << "\n=================================\n";
553         }
554         else if (OC_REST_POST == entityHandlerRequest->method)
555         {
556             cout << "\nReceived OC_REST_POST from client";
557             ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload);
558             cout << "\n=================================\n";
559         }
560         else if (OC_REST_DELETE == entityHandlerRequest->method)
561         {
562             cout << "\nReceived OC_REST_DELETE from client";
563             ehResult = ProcessDeleteRequest (entityHandlerRequest);
564             cout << "\n=================================\n";
565         }
566         else
567         {
568             cout << "\nReceived unsupported method " << entityHandlerRequest->method << " from client";
569             ehResult = OC_EH_ERROR;
570         }
571         // If the result isn't an error or forbidden, send response
572         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
573         {
574             // Format the response.  Note this requires some info about the request
575             response.requestHandle = entityHandlerRequest->requestHandle;
576             response.resourceHandle = entityHandlerRequest->resource;
577             response.ehResult = ehResult;
578             response.payload = reinterpret_cast<OCPayload*>(payload);
579             // Indicate that response is NOT in a persistent buffer
580             response.persistentBufferFlag = 0;
581
582             // Handle vendor specific options
583             if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
584                     entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
585             {
586                 cout << "\nReceived vendor specific options";
587                 uint8_t i = 0;
588                 OCHeaderOption * rcvdOptions =
589                         entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
590                 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
591                 {
592                     if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
593                     {
594                         cout << "\nReceived option with ID " << ((OCHeaderOption)rcvdOptions[i]).optionID;
595                     }
596                 }
597                 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
598                 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
599                 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
600                 sendOptions[0].protocolID = OC_COAP_ID;
601                 sendOptions[0].optionID = 2248;
602                 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
603                 sendOptions[0].optionLength = 10;
604                 sendOptions[1].protocolID = OC_COAP_ID;
605                 sendOptions[1].optionID = 2600;
606                 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
607                 sendOptions[1].optionLength = 10;
608                 response.numSendVendorSpecificHeaderOptions = 2;
609             }
610
611             // Send the response
612             if (OCDoResponse(&response) != OC_STACK_OK)
613             {
614                 cout << "\nError sending response";
615                 ehResult = OC_EH_ERROR;
616             }
617         }
618     }
619     if (flag & OC_OBSERVE_FLAG)
620     {
621         cout << "\nFlag includes OC_OBSERVE_FLAG";
622
623         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
624         {
625             cout << "\nReceived OC_OBSERVE_REGISTER from client";
626             ProcessObserveRegister (entityHandlerRequest);
627         }
628         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
629         {
630             cout << "\nReceived OC_OBSERVE_DEREGISTER from client";
631             ProcessObserveDeregister (entityHandlerRequest);
632         }
633     }
634
635     return ehResult;
636 }
637
638 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
639 void handleSigInt(int signum)
640 {
641     if (signum == SIGINT)
642     {
643         gQuitFlag = 1;
644     }
645 }
646
647 void *ChangeLightRepresentation (void *param)
648 {
649     (void)param;
650     OCStackResult result = OC_STACK_ERROR;
651
652     uint8_t j = 0;
653     uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
654     OCObservationId obsNotify[numNotifies];
655
656     while (!gQuitFlag)
657     {
658         sleep(3);
659         Light.power += 5;
660         if (gLightUnderObservation)
661         {
662             cout << "\n=====> Notifying stack of new power level" << Light.power;
663             if (gObserveNotifyType == 1)
664             {
665                 // Notify list of observers. Alternate observers on the list will be notified.
666                 j = 0;
667                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
668                 {
669                     if (interestedObservers[i].valid == true)
670                     {
671                         obsNotify[j] = interestedObservers[i].observationId;
672                         j++;
673                     }
674                 }
675
676                 OCRepPayload* payload = getPayload(gResourceUri, Light.power, Light.state);
677                 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
678                         payload, OC_NA_QOS);
679                 OCRepPayloadDestroy(payload);
680             }
681             else if (gObserveNotifyType == 0)
682             {
683                 // Notifying all observers
684                 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
685                 if (OC_STACK_NO_OBSERVERS == result)
686                 {
687                     cout << "\n=====> No more observers exist, stop sending observations";
688                     gLightUnderObservation = 0;
689                 }
690             }
691             else
692             {
693                 cout << "\nIncorrect notification type selected";
694             }
695         }
696 #ifdef WITH_PRESENCE
697         if(stopPresenceCount > 0)
698         {
699             cout << "\n=====> Counting down to stop presence " << stopPresenceCount;
700         }
701         if(!stopPresenceCount--)
702         {
703             cout << "\n=====> stopping presence";
704             OCStopPresence();
705         }
706 #endif
707     }
708     return NULL;
709 }
710
711 #ifdef WITH_PRESENCE
712 void *presenceNotificationGenerator(void *param)
713 {
714     sleep(10);
715     (void)param;
716     OCDoHandle presenceNotificationHandles[numPresenceResources];
717     OCStackResult res = OC_STACK_OK;
718
719     std::array<std::string, numPresenceResources> presenceNotificationResources { {
720         std::string("core.fan"),
721         std::string("core.led") } };
722     std::array<std::string, numPresenceResources> presenceNotificationUris { {
723         std::string("/a/fan"),
724         std::string("/a/led") } };
725
726     for(int i=0; i<numPresenceResources; i++)
727     {
728         if(res == OC_STACK_OK)
729         {
730             sleep(1);
731             res = OCCreateResource(&presenceNotificationHandles[i],
732                     presenceNotificationResources.at(i).c_str(),
733                     OC_RSRVD_INTERFACE_DEFAULT,
734                     presenceNotificationUris.at(i).c_str(),
735                     OCNOPEntityHandlerCb,
736                     NULL,
737                     OC_DISCOVERABLE|OC_OBSERVABLE);
738         }
739         if(res != OC_STACK_OK)
740         {
741             cout << "\nPresence Notification Generator failed[" << getResult(res)
742                 << "] to create resource " << presenceNotificationResources.at(i).c_str();
743             break;
744         }
745         cout << "\nCreated " << presenceNotificationUris[i].c_str() << " for presence notification";
746     }
747     sleep(5);
748     for(int i=0; i<numPresenceResources; i++)
749     {
750         if(res == OC_STACK_OK)
751         {
752             res = OCDeleteResource(presenceNotificationHandles[i]);
753         }
754         if(res != OC_STACK_OK)
755         {
756             cout << "\nPresence Notification Generator failed to delete resource"
757                 << presenceNotificationResources.at(i).c_str();
758             break;
759         }
760         cout << "\nDeleted " << presenceNotificationUris[i].c_str() << " for presence notification";
761     }
762     return NULL;
763 }
764 #endif
765
766 int createLightResource (char *uri, LightResource *lightResource)
767 {
768     if (!uri)
769     {
770         cout << "\nResource URI cannot be NULL";
771         return -1;
772     }
773
774     lightResource->state = false;
775     lightResource->power= 0;
776     OCStackResult res = OCCreateResource(&(lightResource->handle),
777             "core.light",
778             "oc.mi.def",
779             uri,
780             OCEntityHandlerCb,
781             NULL,
782             OC_DISCOVERABLE|OC_OBSERVABLE);
783     cout << "\nCreated Light resource with result " << getResult(res);
784
785     return 0;
786 }
787
788 void DeletePlatformInfo()
789 {
790     free (platformInfo.platformID);
791     free (platformInfo.manufacturerName);
792     free (platformInfo.manufacturerUrl);
793     free (platformInfo.modelNumber);
794     free (platformInfo.dateOfManufacture);
795     free (platformInfo.platformVersion);
796     free (platformInfo.operatingSystemVersion);
797     free (platformInfo.hardwareVersion);
798     free (platformInfo.firmwareVersion);
799     free (platformInfo.supportUrl);
800     free (platformInfo.systemTime);
801 }
802
803 void DeleteDeviceInfo()
804 {
805     free (deviceInfo.deviceName);
806 }
807
808 bool DuplicateString(char** targetString, const char* sourceString)
809 {
810     if(!sourceString)
811     {
812         return false;
813     }
814     else
815     {
816         *targetString = (char *) malloc(strlen(sourceString) + 1);
817
818         if(*targetString)
819         {
820             strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
821             return true;
822         }
823     }
824     return false;
825 }
826
827 OCStackResult SetPlatformInfo(const char* platformID, const char *manufacturerName,
828     const char *manufacturerUrl, const char *modelNumber, const char *dateOfManufacture,
829     const char *platformVersion, const char* operatingSystemVersion, const char* hardwareVersion,
830     const char *firmwareVersion, const char* supportUrl, const char* systemTime)
831 {
832
833     bool success = true;
834
835     if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
836     {
837         return OC_STACK_INVALID_PARAM;
838     }
839
840     if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
841     {
842         return OC_STACK_INVALID_PARAM;
843     }
844
845     if(!DuplicateString(&platformInfo.platformID, platformID))
846     {
847         success = false;
848     }
849
850     if(!DuplicateString(&platformInfo.manufacturerName, manufacturerName))
851     {
852         success = false;
853     }
854
855     if(!DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl))
856     {
857         success = false;
858     }
859
860     if(!DuplicateString(&platformInfo.modelNumber, modelNumber))
861     {
862         success = false;
863     }
864
865     if(!DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture))
866     {
867         success = false;
868     }
869
870     if(!DuplicateString(&platformInfo.platformVersion, platformVersion))
871     {
872         success = false;
873     }
874
875     if(!DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion))
876     {
877         success = false;
878     }
879
880     if(!DuplicateString(&platformInfo.hardwareVersion, hardwareVersion))
881     {
882         success = false;
883     }
884
885     if(!DuplicateString(&platformInfo.firmwareVersion, firmwareVersion))
886     {
887         success = false;
888     }
889
890     if(!DuplicateString(&platformInfo.supportUrl, supportUrl))
891     {
892         success = false;
893     }
894
895     if(!DuplicateString(&platformInfo.systemTime, systemTime))
896     {
897         success = false;
898     }
899
900     if(success)
901     {
902         return OC_STACK_OK;
903     }
904
905     DeletePlatformInfo();
906     return OC_STACK_ERROR;
907 }
908
909 OCStackResult SetDeviceInfo(const char* deviceName)
910 {
911     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
912     {
913         return OC_STACK_ERROR;
914     }
915     return OC_STACK_OK;
916 }
917
918 static void PrintUsage()
919 {
920     cout << "\nUsage : ocserver -o <0|1>";
921     cout << "\n-o 0 : Notify all observers";
922     cout << "\n-o 1 : Notify list of observers";
923 }
924
925 int main(int argc, char* argv[])
926 {
927     pthread_t threadId;
928     pthread_t threadId_presence;
929     int opt;
930
931     while ((opt = getopt(argc, argv, "o:")) != -1)
932     {
933         switch(opt)
934         {
935             case 'o':
936                 gObserveNotifyType = atoi(optarg);
937                 break;
938             default:
939                 PrintUsage();
940                 return -1;
941         }
942     }
943
944     if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
945     {
946         PrintUsage();
947         return -1;
948     }
949
950     cout << "\nOCServer is starting...";
951
952     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
953     {
954         cout << "\nOCStack init error";
955         return 0;
956     }
957 #ifdef WITH_PRESENCE
958     if (OCStartPresence(0) != OC_STACK_OK)
959     {
960         cout << "\nOCStack presence/discovery error";
961         return 0;
962     }
963 #endif
964
965     OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb, NULL);
966
967     OCStackResult registrationResult =
968         SetPlatformInfo(platformID, manufacturerName, manufacturerUrl, modelNumber,
969             dateOfManufacture, platformVersion,  operatingSystemVersion,  hardwareVersion,
970             firmwareVersion,  supportUrl, systemTime);
971
972     if (registrationResult != OC_STACK_OK)
973     {
974         cout << "\nPlatform info setting failed locally!";
975         exit (EXIT_FAILURE);
976     }
977
978     registrationResult = OCSetPlatformInfo(platformInfo);
979
980     if (registrationResult != OC_STACK_OK)
981     {
982         cout << "\nPlatform Registration failed!";
983         exit (EXIT_FAILURE);
984     }
985
986     registrationResult = SetDeviceInfo(deviceName);
987
988     if (registrationResult != OC_STACK_OK)
989     {
990         cout << "\nDevice info setting failed locally!";
991         exit (EXIT_FAILURE);
992     }
993
994     registrationResult = OCSetDeviceInfo(deviceInfo);
995
996     if (registrationResult != OC_STACK_OK)
997     {
998         cout << "\nDevice Registration failed!";
999         exit (EXIT_FAILURE);
1000     }
1001
1002     /*
1003      * Declare and create the example resource: Light
1004      */
1005     createLightResource(gResourceUri, &Light);
1006
1007     // Initialize observations data structure for the resource
1008     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
1009     {
1010         interestedObservers[i].valid = false;
1011     }
1012
1013     /*
1014      * Create a thread for changing the representation of the Light
1015      */
1016     pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
1017
1018     /*
1019      * Create a thread for generating changes that cause presence notifications
1020      * to be sent to clients
1021      */
1022
1023     #ifdef WITH_PRESENCE
1024     pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
1025     #endif
1026
1027     // Break from loop with Ctrl-C
1028     cout << "\nEntering ocserver main loop...";
1029
1030     DeletePlatformInfo();
1031     DeleteDeviceInfo();
1032
1033     signal(SIGINT, handleSigInt);
1034
1035     while (!gQuitFlag)
1036     {
1037         if (OCProcess() != OC_STACK_OK)
1038         {
1039             cout << "\nOCStack process error";
1040             return 0;
1041         }
1042
1043         sleep(2);
1044     }
1045
1046     /*
1047      * Cancel the Light thread and wait for it to terminate
1048      */
1049     pthread_cancel(threadId);
1050     pthread_join(threadId, NULL);
1051     pthread_cancel(threadId_presence);
1052     pthread_join(threadId_presence, NULL);
1053
1054     cout << "\nExiting ocserver main loop...\n";
1055
1056     if (OCStop() != OC_STACK_OK)
1057     {
1058         cout << "\nOCStack process error";
1059     }
1060
1061     return 0;
1062 }