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