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