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