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