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