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