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