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