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