Imported Upstream version 0.9.2
[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, char* uri, void* callbackParam)
418 {
419     OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
420
421     OCEntityHandlerResult ehResult = OC_EH_OK;
422     OCEntityHandlerResponse response;
423
424     // Validate pointer
425     if (!entityHandlerRequest)
426     {
427         OC_LOG (ERROR, TAG, "Invalid request pointer");
428         return OC_EH_ERROR;
429     }
430     // Initialize certain response fields
431     response.numSendVendorSpecificHeaderOptions = 0;
432     memset(response.sendVendorSpecificHeaderOptions, 0,
433             sizeof response.sendVendorSpecificHeaderOptions);
434     memset(response.resourceUri, 0, sizeof response.resourceUri);
435     OCRepPayload* payload = nullptr;
436
437
438     if (flag & OC_REQUEST_FLAG)
439     {
440         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
441
442         if (entityHandlerRequest->resource == NULL)
443         {
444             OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
445             ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest);
446         }
447         else if (OC_REST_GET == entityHandlerRequest->method)
448         {
449             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
450             ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
451         }
452         else if (OC_REST_PUT == entityHandlerRequest->method)
453         {
454             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
455             ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
456         }
457         else if (OC_REST_DELETE == entityHandlerRequest->method)
458         {
459             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
460             ehResult = ProcessDeleteRequest (entityHandlerRequest);
461         }
462         else
463         {
464             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
465                       entityHandlerRequest->method);
466             ehResult = OC_EH_ERROR;
467         }
468                // If the result isn't an error or forbidden, send response
469         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
470         {
471             // Format the response.  Note this requires some info about the request
472             response.requestHandle = entityHandlerRequest->requestHandle;
473             response.resourceHandle = entityHandlerRequest->resource;
474             response.ehResult = ehResult;
475             response.payload = reinterpret_cast<OCPayload*>(payload);
476             // Indicate that response is NOT in a persistent buffer
477             response.persistentBufferFlag = 0;
478
479             // Send the response
480             if (OCDoResponse(&response) != OC_STACK_OK)
481             {
482                 OC_LOG(ERROR, TAG, "Error sending response");
483                 ehResult = OC_EH_ERROR;
484             }
485         }
486     }
487     if (flag & OC_OBSERVE_FLAG)
488     {
489         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
490         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
491         {
492             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
493         }
494         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
495         {
496             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
497         }
498     }
499
500     return ehResult;
501 }
502
503 OCEntityHandlerResult
504 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
505         OCEntityHandlerRequest *entityHandlerRequest, void* callbackParam)
506 {
507     // This is callback is associated with the 2 presence notification
508     // resources. They are non-operational.
509     return OC_EH_OK;
510 }
511
512 OCEntityHandlerResult
513 OCEntityHandlerCb (OCEntityHandlerFlag flag,
514         OCEntityHandlerRequest *entityHandlerRequest, void* callback)
515 {
516     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
517
518     OCEntityHandlerResult ehResult = OC_EH_OK;
519     OCEntityHandlerResponse response = { 0 };
520
521     // Validate pointer
522     if (!entityHandlerRequest)
523     {
524         OC_LOG (ERROR, TAG, "Invalid request pointer");
525         return OC_EH_ERROR;
526     }
527
528     // Initialize certain response fields
529     response.numSendVendorSpecificHeaderOptions = 0;
530     memset(response.sendVendorSpecificHeaderOptions,
531             0, sizeof response.sendVendorSpecificHeaderOptions);
532     memset(response.resourceUri, 0, sizeof response.resourceUri);
533     OCRepPayload* payload = nullptr;
534
535     if (flag & OC_REQUEST_FLAG)
536     {
537         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
538
539         if (OC_REST_GET == entityHandlerRequest->method)
540         {
541             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
542             ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
543         }
544         else if (OC_REST_PUT == entityHandlerRequest->method)
545         {
546             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
547             ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
548         }
549         else if (OC_REST_POST == entityHandlerRequest->method)
550         {
551             OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
552             ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload);
553         }
554         else if (OC_REST_DELETE == entityHandlerRequest->method)
555         {
556             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
557             ehResult = ProcessDeleteRequest (entityHandlerRequest);
558         }
559         else
560         {
561             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
562                       entityHandlerRequest->method);
563             ehResult = OC_EH_ERROR;
564         }
565         // If the result isn't an error or forbidden, send response
566         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
567         {
568             // Format the response.  Note this requires some info about the request
569             response.requestHandle = entityHandlerRequest->requestHandle;
570             response.resourceHandle = entityHandlerRequest->resource;
571             response.ehResult = ehResult;
572             response.payload = reinterpret_cast<OCPayload*>(payload);
573             // Indicate that response is NOT in a persistent buffer
574             response.persistentBufferFlag = 0;
575
576             // Handle vendor specific options
577             if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
578                     entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
579             {
580                 OC_LOG (INFO, TAG, "Received vendor specific options");
581                 uint8_t i = 0;
582                 OCHeaderOption * rcvdOptions =
583                         entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
584                 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
585                 {
586                     if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
587                     {
588                         OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
589                                 ((OCHeaderOption)rcvdOptions[i]).optionID );
590
591                         OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
592                             MAX_HEADER_OPTION_DATA_LENGTH);
593                     }
594                 }
595                 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
596                 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
597                 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
598                 sendOptions[0].protocolID = OC_COAP_ID;
599                 sendOptions[0].optionID = 2248;
600                 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
601                 sendOptions[0].optionLength = 10;
602                 sendOptions[1].protocolID = OC_COAP_ID;
603                 sendOptions[1].optionID = 2600;
604                 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
605                 sendOptions[1].optionLength = 10;
606                 response.numSendVendorSpecificHeaderOptions = 2;
607             }
608
609             // Send the response
610             if (OCDoResponse(&response) != OC_STACK_OK)
611             {
612                 OC_LOG(ERROR, TAG, "Error sending response");
613                 ehResult = OC_EH_ERROR;
614             }
615         }
616     }
617     if (flag & OC_OBSERVE_FLAG)
618     {
619         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
620
621         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
622         {
623             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
624             ProcessObserveRegister (entityHandlerRequest);
625         }
626         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
627         {
628             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
629             ProcessObserveDeregister (entityHandlerRequest);
630         }
631     }
632
633     OCPayloadDestroy(response.payload);
634     return ehResult;
635 }
636
637 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
638 void handleSigInt(int signum)
639 {
640     if (signum == SIGINT)
641     {
642         gQuitFlag = 1;
643     }
644 }
645
646 void *ChangeLightRepresentation (void *param)
647 {
648     (void)param;
649     OCStackResult result = OC_STACK_ERROR;
650
651     uint8_t j = 0;
652     uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
653     OCObservationId obsNotify[numNotifies];
654
655     while (!gQuitFlag)
656     {
657         sleep(3);
658         Light.power += 5;
659         if (gLightUnderObservation)
660         {
661             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
662             if (gObserveNotifyType == 1)
663             {
664                 // Notify list of observers. Alternate observers on the list will be notified.
665                 j = 0;
666                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
667                 {
668                     if (interestedObservers[i].valid == true)
669                     {
670                         obsNotify[j] = interestedObservers[i].observationId;
671                         j++;
672                     }
673                 }
674
675                 OCRepPayload* payload = getPayload(gResourceUri, Light.power, Light.state);
676                 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
677                         payload, OC_NA_QOS);
678                 OCRepPayloadDestroy(payload);
679             }
680             else if (gObserveNotifyType == 0)
681             {
682                 // Notifying all observers
683                 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
684                 if (OC_STACK_NO_OBSERVERS == result)
685                 {
686                     OC_LOG (INFO, TAG,
687                             "=======> No more observers exist, stop sending observations");
688                     gLightUnderObservation = 0;
689                 }
690             }
691             else
692             {
693                 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
694             }
695         }
696 #ifdef WITH_PRESENCE
697         if(stopPresenceCount > 0)
698         {
699             OC_LOG_V(INFO, TAG, "================  Counting down to stop presence %d", stopPresenceCount);
700         }
701         if(!stopPresenceCount--)
702         {
703             OC_LOG(INFO, TAG, "================ stopping presence");
704             OCStopPresence();
705         }
706 #endif
707     }
708     return NULL;
709 }
710
711 #ifdef WITH_PRESENCE
712 void *presenceNotificationGenerator(void *param)
713 {
714     sleep(10);
715     (void)param;
716     OCDoHandle presenceNotificationHandles[numPresenceResources];
717     OCStackResult res = OC_STACK_OK;
718
719     std::array<std::string, numPresenceResources> presenceNotificationResources { {
720         std::string("core.fan"),
721         std::string("core.led") } };
722     std::array<std::string, numPresenceResources> presenceNotificationUris { {
723         std::string("/a/fan"),
724         std::string("/a/led") } };
725
726     for(int i=0; i<numPresenceResources; i++)
727     {
728         if(res == OC_STACK_OK)
729         {
730             sleep(1);
731             res = OCCreateResource(&presenceNotificationHandles[i],
732                     presenceNotificationResources.at(i).c_str(),
733                     OC_RSRVD_INTERFACE_DEFAULT,
734                     presenceNotificationUris.at(i).c_str(),
735                     OCNOPEntityHandlerCb,
736                     NULL,
737                     OC_DISCOVERABLE|OC_OBSERVABLE);
738         }
739         if(res != OC_STACK_OK)
740         {
741             OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
742                     "%s with result %s.", presenceNotificationResources.at(i).c_str(),
743                     getResult(res));
744             break;
745         }
746         OC_LOG_V(INFO, TAG, PCF("Created %s for presence notification"),
747                                 presenceNotificationUris[i].c_str());
748     }
749     sleep(5);
750     for(int i=0; i<numPresenceResources; i++)
751     {
752         if(res == OC_STACK_OK)
753         {
754             res = OCDeleteResource(presenceNotificationHandles[i]);
755         }
756         if(res != OC_STACK_OK)
757         {
758             OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
759                     "resource %s.", presenceNotificationResources.at(i).c_str());
760             break;
761         }
762         OC_LOG_V(INFO, TAG, PCF("Deleted %s for presence notification"),
763                                 presenceNotificationUris[i].c_str());
764     }
765     return NULL;
766 }
767 #endif
768
769 int createLightResource (char *uri, LightResource *lightResource)
770 {
771     if (!uri)
772     {
773         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
774         return -1;
775     }
776
777     lightResource->state = false;
778     lightResource->power= 0;
779     OCStackResult res = OCCreateResource(&(lightResource->handle),
780             "core.light",
781             "oc.mi.def",
782             uri,
783             OCEntityHandlerCb,
784             NULL,
785             OC_DISCOVERABLE|OC_OBSERVABLE);
786     OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
787
788     return 0;
789 }
790
791 void DeletePlatformInfo()
792 {
793     free (platformInfo.platformID);
794     free (platformInfo.manufacturerName);
795     free (platformInfo.manufacturerUrl);
796     free (platformInfo.modelNumber);
797     free (platformInfo.dateOfManufacture);
798     free (platformInfo.platformVersion);
799     free (platformInfo.operatingSystemVersion);
800     free (platformInfo.hardwareVersion);
801     free (platformInfo.firmwareVersion);
802     free (platformInfo.supportUrl);
803     free (platformInfo.systemTime);
804 }
805
806 void DeleteDeviceInfo()
807 {
808     free (deviceInfo.deviceName);
809 }
810
811 bool DuplicateString(char** targetString, const char* sourceString)
812 {
813     if(!sourceString)
814     {
815         return false;
816     }
817     else
818     {
819         *targetString = (char *) malloc(strlen(sourceString) + 1);
820
821         if(*targetString)
822         {
823             strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
824             return true;
825         }
826     }
827     return false;
828 }
829
830 OCStackResult SetPlatformInfo(const char* platformID, const char *manufacturerName,
831     const char *manufacturerUrl, const char *modelNumber, const char *dateOfManufacture,
832     const char *platformVersion, const char* operatingSystemVersion, const char* hardwareVersion,
833     const char *firmwareVersion, const char* supportUrl, const char* systemTime)
834 {
835
836     bool success = true;
837
838     if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
839     {
840         return OC_STACK_INVALID_PARAM;
841     }
842
843     if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
844     {
845         return OC_STACK_INVALID_PARAM;
846     }
847
848     if(!DuplicateString(&platformInfo.platformID, platformID))
849     {
850         success = false;
851     }
852
853     if(!DuplicateString(&platformInfo.manufacturerName, manufacturerName))
854     {
855         success = false;
856     }
857
858     if(!DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl))
859     {
860         success = false;
861     }
862
863     if(!DuplicateString(&platformInfo.modelNumber, modelNumber))
864     {
865         success = false;
866     }
867
868     if(!DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture))
869     {
870         success = false;
871     }
872
873     if(!DuplicateString(&platformInfo.platformVersion, platformVersion))
874     {
875         success = false;
876     }
877
878     if(!DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion))
879     {
880         success = false;
881     }
882
883     if(!DuplicateString(&platformInfo.hardwareVersion, hardwareVersion))
884     {
885         success = false;
886     }
887
888     if(!DuplicateString(&platformInfo.firmwareVersion, firmwareVersion))
889     {
890         success = false;
891     }
892
893     if(!DuplicateString(&platformInfo.supportUrl, supportUrl))
894     {
895         success = false;
896     }
897
898     if(!DuplicateString(&platformInfo.systemTime, systemTime))
899     {
900         success = false;
901     }
902
903     if(success)
904     {
905         return OC_STACK_OK;
906     }
907
908     DeletePlatformInfo();
909     return OC_STACK_ERROR;
910 }
911
912 OCStackResult SetDeviceInfo(const char* deviceName)
913 {
914     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
915     {
916         return OC_STACK_ERROR;
917     }
918     return OC_STACK_OK;
919 }
920
921 static void PrintUsage()
922 {
923     OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
924     OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
925     OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
926 }
927
928 int main(int argc, char* argv[])
929 {
930     pthread_t threadId;
931     pthread_t threadId_presence;
932     int opt;
933
934     while ((opt = getopt(argc, argv, "o:")) != -1)
935     {
936         switch(opt)
937         {
938             case 'o':
939                 gObserveNotifyType = atoi(optarg);
940                 break;
941             default:
942                 PrintUsage();
943                 return -1;
944         }
945     }
946
947     if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
948     {
949         PrintUsage();
950         return -1;
951     }
952     #ifdef RA_ADAPTER
953     OCRAInfo_t rainfo;
954     rainfo.hostname = "localhost";
955     rainfo.port = 5222;
956     rainfo.xmpp_domain = "localhost";
957     rainfo.username = "test1";
958     rainfo.password = "intel123";
959     rainfo.resource = "";
960     rainfo.user_jid = "";
961
962     OCSetRAInfo(&rainfo);
963     #endif
964
965     OC_LOG(DEBUG, TAG, "OCServer is starting...");
966
967     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
968     {
969         OC_LOG(ERROR, TAG, "OCStack init error");
970         return 0;
971     }
972 #ifdef WITH_PRESENCE
973     if (OCStartPresence(0) != OC_STACK_OK)
974     {
975         OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
976         return 0;
977     }
978 #endif
979
980     OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb, NULL);
981
982     OCStackResult registrationResult =
983         SetPlatformInfo(platformID, manufacturerName, manufacturerUrl, modelNumber,
984             dateOfManufacture, platformVersion,  operatingSystemVersion,  hardwareVersion,
985             firmwareVersion,  supportUrl, systemTime);
986
987     if (registrationResult != OC_STACK_OK)
988     {
989         OC_LOG(INFO, TAG, "Platform info setting failed locally!");
990         exit (EXIT_FAILURE);
991     }
992
993     registrationResult = OCSetPlatformInfo(platformInfo);
994
995     if (registrationResult != OC_STACK_OK)
996     {
997         OC_LOG(INFO, TAG, "Platform Registration failed!");
998         exit (EXIT_FAILURE);
999     }
1000
1001     registrationResult = SetDeviceInfo(deviceName);
1002
1003     if (registrationResult != OC_STACK_OK)
1004     {
1005         OC_LOG(INFO, TAG, "Device info setting failed locally!");
1006         exit (EXIT_FAILURE);
1007     }
1008
1009     registrationResult = OCSetDeviceInfo(deviceInfo);
1010
1011     if (registrationResult != OC_STACK_OK)
1012     {
1013         OC_LOG(INFO, TAG, "Device Registration failed!");
1014         exit (EXIT_FAILURE);
1015     }
1016
1017     /*
1018      * Declare and create the example resource: Light
1019      */
1020     createLightResource(gResourceUri, &Light);
1021
1022     // Initialize observations data structure for the resource
1023     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
1024     {
1025         interestedObservers[i].valid = false;
1026     }
1027
1028     /*
1029      * Create a thread for changing the representation of the Light
1030      */
1031     pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
1032
1033     /*
1034      * Create a thread for generating changes that cause presence notifications
1035      * to be sent to clients
1036      */
1037
1038     #ifdef WITH_PRESENCE
1039     pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
1040     #endif
1041
1042     // Break from loop with Ctrl-C
1043     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
1044
1045     DeletePlatformInfo();
1046     DeleteDeviceInfo();
1047
1048     signal(SIGINT, handleSigInt);
1049
1050     while (!gQuitFlag)
1051     {
1052         if (OCProcess() != OC_STACK_OK)
1053         {
1054             OC_LOG(ERROR, TAG, "OCStack process error");
1055             return 0;
1056         }
1057
1058         sleep(2);
1059     }
1060
1061     /*
1062      * Cancel the Light thread and wait for it to terminate
1063      */
1064     pthread_cancel(threadId);
1065     pthread_join(threadId, NULL);
1066     pthread_cancel(threadId_presence);
1067     pthread_join(threadId_presence, NULL);
1068
1069     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
1070
1071     if (OCStop() != OC_STACK_OK)
1072     {
1073         OC_LOG(ERROR, TAG, "OCStack process error");
1074     }
1075
1076     return 0;
1077 }