Fix klocwork issues in C samples
[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 "cJSON.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 //TODO: Follow the pattern used in constructJsonResponse() when the payload is decided.
59 const char responsePayloadDeleteOk[] =
60         "{App determines payload: Delete Resource operation succeeded.}";
61 const char responsePayloadDeleteNotOK[] =
62         "{App determines payload: Delete Resource operation failed.}";
63 const char responsePayloadResourceDoesNotExist[] =
64         "{App determines payload: The resource does not exist.}";
65 const char responsePayloadDeleteResourceNotSupported[] =
66         "{App determines payload: The request is received for a non-support resource.}";
67
68
69 char *gResourceUri= (char *)"/a/light";
70 const char *contentType = "myContentType";
71 const char *dateOfManufacture = "myDateOfManufacture";
72 const char *deviceName = "myDeviceName";
73 const char *deviceUUID = "myDeviceUUID";
74 const char *firmwareVersion = "myFirmwareVersion";
75 const char *hostName = "myHostName";
76 const char *manufacturerName = "myManufacturerNa";
77 const char *manufacturerUrl = "myManufacturerUrl";
78 const char *modelNumber = "myModelNumber";
79 const char *platformVersion = "myPlatformVersion";
80 const char *supportUrl = "mySupportUrl";
81 const char *version = "myVersion";
82
83 OCDeviceInfo deviceInfo;
84
85 //This function takes the request as an input and returns the response
86 //in JSON format.
87 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
88 {
89     cJSON *json = cJSON_CreateObject();
90     cJSON *format;
91     char *jsonResponse;
92     LightResource *currLightResource = &Light;
93
94     if (ehRequest->resource == gLightInstance[0].handle)
95     {
96         currLightResource = &gLightInstance[0];
97         gResourceUri = (char *) "a/light/0";
98     }
99     else if (ehRequest->resource == gLightInstance[1].handle)
100     {
101         currLightResource = &gLightInstance[1];
102         gResourceUri = (char *) "a/light/1";
103     }
104
105     if(OC_REST_PUT == ehRequest->method)
106     {
107         // Get cJSON pointer to query
108         cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload);
109
110         // Get root of JSON payload, then the 1st resource.
111         cJSON* carrier = cJSON_GetObjectItem(putJson, "oc");
112         carrier = cJSON_GetArrayItem(carrier, 0);
113         carrier = cJSON_GetObjectItem(carrier, "rep");
114
115         currLightResource->power = cJSON_GetObjectItem(carrier,"power")->valueint;
116         currLightResource->state = cJSON_GetObjectItem(carrier,"state")->valueint;
117
118         cJSON_Delete(putJson);
119     }
120
121     cJSON_AddStringToObject(json,"href",gResourceUri);
122     cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
123     cJSON_AddBoolToObject(format, "state", currLightResource->state);
124     cJSON_AddNumberToObject(format, "power", currLightResource->power);
125
126     jsonResponse = cJSON_Print(json);
127     cJSON_Delete(json);
128
129     return jsonResponse;
130 }
131
132 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
133         char *payload, uint16_t maxPayloadSize)
134 {
135     OCEntityHandlerResult ehResult;
136     char *getResp = constructJsonResponse(ehRequest);
137
138     if (maxPayloadSize > strlen ((char *)getResp))
139     {
140         strncpy(payload, getResp, strlen((char *)getResp));
141         ehResult = OC_EH_OK;
142     }
143     else
144     {
145         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
146                 maxPayloadSize);
147         ehResult = OC_EH_ERROR;
148     }
149
150     free(getResp);
151
152     return ehResult;
153 }
154
155 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
156         char *payload, uint16_t maxPayloadSize)
157 {
158     OCEntityHandlerResult ehResult;
159     char *putResp = constructJsonResponse(ehRequest);
160
161     if (maxPayloadSize > strlen ((char *)putResp))
162     {
163         strncpy(payload, putResp, strlen((char *)putResp));
164         ehResult = OC_EH_OK;
165     }
166     else
167     {
168         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
169                 maxPayloadSize);
170         ehResult = OC_EH_ERROR;
171     }
172
173     free(putResp);
174
175     return ehResult;
176 }
177
178 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
179         OCEntityHandlerResponse *response, char *payload, uint16_t maxPayloadSize)
180 {
181     OCEntityHandlerResult ehResult = OC_EH_OK;
182     char *respPLPost_light = NULL;
183     cJSON *json;
184     cJSON *format;
185
186     /*
187      * The entity handler determines how to process a POST request.
188      * Per the REST paradigm, POST can also be used to update representation of existing
189      * resource or create a new resource.
190      * In the sample below, if the POST is for /a/light then a new instance of the Light
191      * resource is created with default representation (if representation is included in
192      * POST payload it can be used as initial values) as long as the instance is
193      * lesser than max new instance count. Once max instance count is reached, POST on
194      * /a/light updated the representation of /a/light (just like PUT)
195      */
196
197     if (ehRequest->resource == Light.handle)
198     {
199         if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
200         {
201             // Create new Light instance
202             char newLightUri[URI_MAXSIZE];
203             snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
204
205             json = cJSON_CreateObject();
206             cJSON_AddStringToObject(json,"href",gResourceUri);
207             cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
208             cJSON_AddStringToObject(format, "createduri", (char *) newLightUri);
209
210             if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
211             {
212                 OC_LOG (INFO, TAG, "Created new Light instance\n");
213                 gLightInstance[gCurrLightInstance].state = 0;
214                 gLightInstance[gCurrLightInstance].power = 0;
215                 gCurrLightInstance++;
216                 respPLPost_light = cJSON_Print(json);
217                 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
218                 ehResult = OC_EH_RESOURCE_CREATED;
219             }
220
221             cJSON_Delete(json);
222         }
223         else
224         {
225             // Update repesentation of /a/light
226             Light.state = true;
227             Light.power = 11;
228             respPLPost_light = constructJsonResponse(ehRequest);
229         }
230     }
231     else
232     {
233         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
234         {
235             if (ehRequest->resource == gLightInstance[i].handle)
236             {
237                 gLightInstance[i].state = true;
238                 gLightInstance[i].power = 22;
239                 if (i == 0)
240                 {
241                     respPLPost_light = constructJsonResponse(ehRequest);
242                     break;
243                 }
244                 else if (i == 1)
245                 {
246                     respPLPost_light = constructJsonResponse(ehRequest);
247                 }
248             }
249         }
250     }
251
252     if ((respPLPost_light != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_light)))
253     {
254         strncpy(payload, respPLPost_light, strlen((char *)respPLPost_light));
255     }
256     else
257     {
258         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
259                 maxPayloadSize);
260         ehResult = OC_EH_ERROR;
261     }
262
263     free(respPLPost_light);
264     return ehResult;
265 }
266
267 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest,
268         char *payload, uint16_t maxPayloadSize)
269 {
270     if(ehRequest == NULL)
271     {
272         OC_LOG(INFO, TAG, "The ehRequest is NULL");
273         return OC_EH_ERROR;
274     }
275     OCEntityHandlerResult ehResult = OC_EH_OK;
276
277     OC_LOG_V(INFO, TAG, "\n\nExecuting %s for resource %d ", __func__, ehRequest->resource);
278
279     /*
280      * In the sample below, the application will:
281      * 1a. pass the delete request to the c stack
282      * 1b. internally, the c stack figures out what needs to be done and does it accordingly
283      *    (e.g. send observers notification, remove observers...)
284      * 1c. the c stack returns with the result whether the request is fullfilled.
285      * 2. optionally, app removes observers out of its array 'interestedObservers'
286      */
287
288     const char* deleteResponse = NULL;
289
290     if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
291     {
292         //Step 1: Ask stack to do the work.
293         OCStackResult result = OCDeleteResource(ehRequest->resource);
294
295         if (result == OC_STACK_OK)
296         {
297             OC_LOG (INFO, TAG, "\n\nDelete Resource operation succeeded.");
298             ehResult = OC_EH_OK;
299             deleteResponse = responsePayloadDeleteOk;
300
301             //Step 2: clear observers who wanted to observe this resource at the app level.
302             for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
303             {
304                 if (interestedObservers[i].resourceHandle == ehRequest->resource)
305                 {
306                     interestedObservers[i].valid = false;
307                     interestedObservers[i].observationId = 0;
308                     interestedObservers[i].resourceHandle = NULL;
309                 }
310             }
311         }
312         else if (result == OC_STACK_NO_RESOURCE)
313         {
314             OC_LOG(INFO, TAG, "\n\nThe resource doesn't exist or it might have been deleted.");
315             deleteResponse = responsePayloadResourceDoesNotExist;
316             ehResult = OC_EH_RESOURCE_DELETED;
317         }
318         else
319         {
320             OC_LOG(INFO, TAG, "\n\nEncountered error from OCDeleteResource().");
321             deleteResponse = responsePayloadDeleteNotOK;
322             ehResult = OC_EH_ERROR;
323         }
324     }
325     else if (ehRequest->resource != Light.handle)
326     {
327         //Let's this app not supporting DELETE on some resources so
328         //consider the DELETE request is received for a non-support resource.
329         OC_LOG_V(INFO, TAG, "\n\nThe request is received for a non-support resource.");
330         deleteResponse = responsePayloadDeleteResourceNotSupported;
331         ehResult = OC_EH_FORBIDDEN;
332     }
333
334     if (maxPayloadSize > strlen ((char *)deleteResponse))
335     {
336         strncpy(payload, deleteResponse, strlen((char *)deleteResponse));
337     }
338     else
339     {
340         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
341                 maxPayloadSize);
342         ehResult = OC_EH_ERROR;
343     }
344
345     return ehResult;
346 }
347
348 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest,
349         char *payload, uint16_t maxPayloadSize)
350 {
351     OC_LOG_V(INFO, TAG, "\n\nExecuting %s ", __func__);
352
353     const char* response = NULL;
354     response = responsePayloadResourceDoesNotExist;
355
356     if ( (ehRequest != NULL) &&
357          (maxPayloadSize > strlen ((char *)response)) )
358     {
359         strncpy((char *)payload, response, strlen((char *)response));
360     }
361     else
362     {
363         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
364                 maxPayloadSize);
365     }
366
367     return OC_EH_RESOURCE_DELETED;
368 }
369
370 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
371 {
372     OC_LOG_V (INFO, TAG, "Received observation registration request with observation Id %d",
373             ehRequest->obsInfo.obsId);
374     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
375     {
376         if (interestedObservers[i].valid == false)
377         {
378             interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
379             interestedObservers[i].valid = true;
380             gLightUnderObservation = 1;
381             break;
382         }
383     }
384 }
385
386 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
387 {
388     bool clientStillObserving = false;
389
390     OC_LOG_V (INFO, TAG, "Received observation deregistration request for observation Id %d",
391             ehRequest->obsInfo.obsId);
392     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
393     {
394         if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
395         {
396             interestedObservers[i].valid = false;
397         }
398         if (interestedObservers[i].valid == true)
399         {
400             // Even if there is one single client observing we continue notifying entity handler
401             clientStillObserving = true;
402         }
403     }
404     if (clientStillObserving == false)
405         gLightUnderObservation = 0;
406 }
407
408 OCEntityHandlerResult
409 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
410         OCEntityHandlerRequest *entityHandlerRequest, char* uri)
411 {
412     OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
413
414     OCEntityHandlerResult ehResult = OC_EH_OK;
415     OCEntityHandlerResponse response;
416     char payload[MAX_RESPONSE_LENGTH] = {0};
417
418     // Validate pointer
419     if (!entityHandlerRequest)
420     {
421         OC_LOG (ERROR, TAG, "Invalid request pointer");
422         return OC_EH_ERROR;
423     }
424
425     // Initialize certain response fields
426     response.numSendVendorSpecificHeaderOptions = 0;
427     memset(response.sendVendorSpecificHeaderOptions, 0,
428             sizeof response.sendVendorSpecificHeaderOptions);
429     memset(response.resourceUri, 0, sizeof response.resourceUri);
430
431     if (flag & OC_INIT_FLAG)
432     {
433         OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
434     }
435     if (flag & OC_REQUEST_FLAG)
436     {
437         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
438         if (entityHandlerRequest->resource == NULL)
439         {
440             OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
441             ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest,
442                     payload, sizeof(payload) - 1);
443         }
444         else if (OC_REST_GET == entityHandlerRequest->method)
445         {
446             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
447             ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
448         }
449         else if (OC_REST_PUT == entityHandlerRequest->method)
450         {
451             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
452             ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
453         }
454         else if (OC_REST_DELETE == entityHandlerRequest->method)
455         {
456             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
457             ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
458         }
459         else
460         {
461             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
462                     entityHandlerRequest->method);
463             ehResult = OC_EH_ERROR;
464         }
465
466         // If the result isn't an error or forbidden, send response
467         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
468         {
469             // Format the response.  Note this requires some info about the request
470             response.requestHandle = entityHandlerRequest->requestHandle;
471             response.resourceHandle = entityHandlerRequest->resource;
472             response.ehResult = ehResult;
473             response.payload = (unsigned char *)payload;
474             response.payloadSize = strlen(payload);
475             // Indicate that response is NOT in a persistent buffer
476             response.persistentBufferFlag = 0;
477
478             // Send the response
479             if (OCDoResponse(&response) != OC_STACK_OK)
480             {
481                 OC_LOG(ERROR, TAG, "Error sending response");
482                 ehResult = OC_EH_ERROR;
483             }
484         }
485     }
486     if (flag & OC_OBSERVE_FLAG)
487     {
488         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
489         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
490         {
491             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
492         }
493         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
494         {
495             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
496         }
497     }
498
499     return ehResult;
500 }
501
502 OCEntityHandlerResult
503 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
504         OCEntityHandlerRequest *entityHandlerRequest)
505 {
506     // This is callback is associated with the 2 presence notification
507     // resources. They are non-operational.
508     return OC_EH_OK;
509 }
510
511 OCEntityHandlerResult
512 OCEntityHandlerCb (OCEntityHandlerFlag flag,
513         OCEntityHandlerRequest *entityHandlerRequest)
514 {
515     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
516
517     OCEntityHandlerResult ehResult = OC_EH_OK;
518     OCEntityHandlerResponse response;
519     char payload[MAX_RESPONSE_LENGTH] = {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
534     if (flag & OC_INIT_FLAG)
535     {
536         OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
537     }
538     if (flag & OC_REQUEST_FLAG)
539     {
540         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
541         if (OC_REST_GET == entityHandlerRequest->method)
542         {
543             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
544             ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
545         }
546         else if (OC_REST_PUT == entityHandlerRequest->method)
547         {
548             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
549             ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
550         }
551         else if (OC_REST_POST == entityHandlerRequest->method)
552         {
553             OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
554             ehResult = ProcessPostRequest (entityHandlerRequest,
555                     &response, payload, sizeof(payload) - 1);
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, payload, sizeof(payload) - 1);
561         }
562         else
563         {
564             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
565                     entityHandlerRequest->method);
566         }
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 = (unsigned char *)payload;
576             response.payloadSize = strlen(payload);
577             // Indicate that response is NOT in a persistent buffer
578             response.persistentBufferFlag = 0;
579
580             // Handle vendor specific options
581             if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
582                     entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
583             {
584                 OC_LOG (INFO, TAG, "Received vendor specific options");
585                 uint8_t i = 0;
586                 OCHeaderOption * rcvdOptions =
587                         entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
588                 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
589                 {
590                     if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
591                     {
592                         OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
593                                 ((OCHeaderOption)rcvdOptions[i]).optionID );
594                         OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
595                                 ((OCHeaderOption)rcvdOptions[i]).optionLength);
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     return ehResult;
637 }
638
639 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
640 void handleSigInt(int signum)
641 {
642     if (signum == SIGINT)
643     {
644         gQuitFlag = 1;
645     }
646 }
647
648 void *ChangeLightRepresentation (void *param)
649 {
650     (void)param;
651     OCStackResult result = OC_STACK_ERROR;
652
653     uint8_t j = 0;
654     uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
655     OCObservationId obsNotify[numNotifies];
656
657     while (!gQuitFlag)
658     {
659         sleep(10);
660         Light.power += 5;
661         if (gLightUnderObservation)
662         {
663             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
664             if (gObserveNotifyType == 1)
665             {
666                 // Notify list of observers. Alternate observers on the list will be notified.
667                 j = 0;
668                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
669                 {
670                     if (interestedObservers[i].valid == true)
671                     {
672                         obsNotify[j] = interestedObservers[i].observationId;
673                         j++;
674                     }
675                 }
676
677                 cJSON *json = cJSON_CreateObject();
678                 cJSON *format;
679                 cJSON_AddStringToObject(json,"href",gResourceUri);
680                 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
681                 cJSON_AddBoolToObject(format, "state", Light.state);
682                 cJSON_AddNumberToObject(format, "power", Light.power);
683                 char * obsResp = cJSON_Print(json);
684                 cJSON_Delete(json);
685                 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
686                         (unsigned char *)obsResp, OC_NA_QOS);
687                 free(obsResp);
688             }
689             else if (gObserveNotifyType == 0)
690             {
691                 // Notifying all observers
692                 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
693                 if (OC_STACK_NO_OBSERVERS == result)
694                 {
695                     OC_LOG (INFO, TAG,
696                             "=======> No more observers exist, stop sending observations");
697                     gLightUnderObservation = 0;
698                 }
699             }
700             else
701             {
702                 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
703             }
704         }
705 #ifdef WITH_PRESENCE
706         if(stopPresenceCount > 0)
707         {
708             OC_LOG_V(INFO, TAG, "================ presence count %d", stopPresenceCount);
709         }
710         if(!stopPresenceCount--)
711         {
712             OC_LOG(INFO, TAG, "================ stopping presence");
713             OCStopPresence();
714         }
715 #endif
716     }
717     return NULL;
718 }
719
720 void *presenceNotificationGenerator(void *param)
721 {
722     sleep(5);
723     (void)param;
724     OCDoHandle presenceNotificationHandles[numPresenceResources];
725     OCStackResult res = OC_STACK_OK;
726
727     std::array<std::string, numPresenceResources> presenceNotificationResources { {
728         std::string("core.fan"),
729         std::string("core.led") } };
730     std::array<std::string, numPresenceResources> presenceNotificationUris { {
731         std::string("/a/fan"),
732         std::string("/a/led") } };
733
734     for(int i=0; i<numPresenceResources; i++)
735     {
736         if(res == OC_STACK_OK)
737         {
738             sleep(1);
739             res = OCCreateResource(&presenceNotificationHandles[i],
740                     presenceNotificationResources.at(i).c_str(),
741                     "oc.mi.def",
742                     presenceNotificationUris.at(i).c_str(),
743                     OCNOPEntityHandlerCb,
744                     OC_DISCOVERABLE|OC_OBSERVABLE);
745         }
746         if(res != OC_STACK_OK)
747         {
748             OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
749                     "%s with result %s.", presenceNotificationResources.at(i).c_str(),
750                     getResult(res));
751             break;
752         }
753     }
754     sleep(5);
755     for(int i=0; i<numPresenceResources; i++)
756     {
757         if(res == OC_STACK_OK)
758         {
759             res = OCDeleteResource(presenceNotificationHandles[i]);
760         }
761         if(res != OC_STACK_OK)
762         {
763             OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
764                     "resource %s.", presenceNotificationResources.at(i).c_str());
765             break;
766         }
767     }
768     return NULL;
769 }
770
771 static void PrintUsage()
772 {
773     OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
774     OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
775     OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
776 }
777
778 int main(int argc, char* argv[])
779 {
780     pthread_t threadId;
781     pthread_t threadId_presence;
782     int opt;
783
784     while ((opt = getopt(argc, argv, "o:")) != -1)
785     {
786         switch(opt)
787         {
788             case 'o':
789                 gObserveNotifyType = atoi(optarg);
790                 break;
791             default:
792                 PrintUsage();
793                 return -1;
794         }
795     }
796
797     if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
798     {
799         PrintUsage();
800         return -1;
801     }
802
803     OC_LOG(DEBUG, TAG, "OCServer is starting...");
804
805     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
806     {
807         OC_LOG(ERROR, TAG, "OCStack init error");
808         return 0;
809     }
810 #ifdef WITH_PRESENCE
811     if (OCStartPresence(0) != OC_STACK_OK)
812     {
813         OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
814         return 0;
815     }
816 #endif
817
818     OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb);
819
820     OCStackResult deviceResult = SetDeviceInfo(contentType, dateOfManufacture, deviceName,
821             deviceUUID, firmwareVersion, hostName, manufacturerName,
822             manufacturerUrl, modelNumber, platformVersion, supportUrl, version);
823
824     if (deviceResult != OC_STACK_OK)
825     {
826         OC_LOG(INFO, TAG, "Device Registration failed!");
827         exit (EXIT_FAILURE);
828     }
829
830     deviceResult = OCSetDeviceInfo(deviceInfo);
831
832     if (deviceResult != OC_STACK_OK)
833     {
834         OC_LOG(INFO, TAG, "Device Registration failed!");
835         exit (EXIT_FAILURE);
836     }
837
838     /*
839      * Declare and create the example resource: Light
840      */
841     createLightResource(gResourceUri, &Light);
842
843     // Initialize observations data structure for the resource
844     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
845     {
846         interestedObservers[i].valid = false;
847     }
848
849     /*
850      * Create a thread for changing the representation of the Light
851      */
852     pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
853
854     /*
855      * Create a thread for generating changes that cause presence notifications
856      * to be sent to clients
857      */
858     pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
859
860     // Break from loop with Ctrl-C
861     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
862     DeleteDeviceInfo();
863     signal(SIGINT, handleSigInt);
864     while (!gQuitFlag)
865     {
866         if (OCProcess() != OC_STACK_OK)
867         {
868             OC_LOG(ERROR, TAG, "OCStack process error");
869             return 0;
870         }
871
872         sleep(2);
873     }
874
875     /*
876      * Cancel the Light thread and wait for it to terminate
877      */
878     pthread_cancel(threadId);
879     pthread_join(threadId, NULL);
880     pthread_cancel(threadId_presence);
881     pthread_join(threadId_presence, NULL);
882
883     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
884
885     if (OCStop() != OC_STACK_OK)
886     {
887         OC_LOG(ERROR, TAG, "OCStack process error");
888     }
889
890     return 0;
891 }
892
893 int createLightResource (char *uri, LightResource *lightResource)
894 {
895     if (!uri)
896     {
897         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
898         return -1;
899     }
900
901     lightResource->state = false;
902     lightResource->power= 0;
903     OCStackResult res = OCCreateResource(&(lightResource->handle),
904             "core.light",
905             "oc.mi.def",
906             uri,
907             OCEntityHandlerCb,
908             OC_DISCOVERABLE|OC_OBSERVABLE);
909     OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
910
911     return 0;
912 }
913
914 void DeleteDeviceInfo()
915 {
916     free(deviceInfo.contentType);
917     free(deviceInfo.dateOfManufacture);
918     free(deviceInfo.deviceName);
919     free(deviceInfo.deviceUUID);
920     free(deviceInfo.firmwareVersion);
921     free(deviceInfo.hostName);
922     free(deviceInfo.manufacturerName);
923     free(deviceInfo.manufacturerUrl);
924     free(deviceInfo.modelNumber);
925     free(deviceInfo.platformVersion);
926     free(deviceInfo.supportUrl);
927     free(deviceInfo.version);
928 }
929
930 bool DuplicateString(char** targetString, const char* sourceString)
931 {
932     if(!sourceString)
933     {
934         return false;
935     }
936     else
937     {
938         *targetString = (char *) malloc(strlen(sourceString) + 1);
939         if(*targetString)
940         {
941             strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
942             return true;
943         }
944     }
945     return false;
946 }
947
948 OCStackResult SetDeviceInfo(const char *contentType, const char *dateOfManufacture,
949         const char *deviceName, const char *deviceUUID, const char *firmwareVersion,
950         const char *hostName, const char *manufacturerName, const char *manufacturerUrl,
951         const char *modelNumber, const char *platformVersion, const char *supportUrl,
952         const char *version)
953 {
954
955     bool success = true;
956
957     if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
958     {
959         return OC_STACK_INVALID_PARAM;
960     }
961
962     if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
963     {
964         return OC_STACK_INVALID_PARAM;
965     }
966
967     if(!DuplicateString(&deviceInfo.contentType, contentType))
968     {
969         success = false;
970     }
971
972     if(!DuplicateString(&deviceInfo.dateOfManufacture, dateOfManufacture))
973     {
974         success = false;
975     }
976
977     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
978     {
979         success = false;
980     }
981
982     if(!DuplicateString(&deviceInfo.deviceUUID, deviceUUID))
983     {
984         success = false;
985     }
986
987     if(!DuplicateString(&deviceInfo.firmwareVersion, firmwareVersion))
988     {
989         success = false;
990     }
991
992     if(!DuplicateString(&deviceInfo.hostName, hostName))
993     {
994         success = false;
995     }
996
997     if(!DuplicateString(&deviceInfo.manufacturerName, manufacturerName))
998     {
999         success = false;
1000     }
1001
1002     if(!DuplicateString(&deviceInfo.manufacturerUrl, manufacturerUrl))
1003     {
1004         success = false;
1005     }
1006
1007     if(!DuplicateString(&deviceInfo.modelNumber, modelNumber))
1008     {
1009         success = false;
1010     }
1011
1012     if(!DuplicateString(&deviceInfo.platformVersion, platformVersion))
1013     {
1014         success = false;
1015     }
1016
1017     if(!DuplicateString(&deviceInfo.supportUrl, supportUrl))
1018     {
1019         success = false;
1020     }
1021
1022     if(!DuplicateString(&deviceInfo.version, version))
1023     {
1024         success = false;
1025     }
1026
1027     if(success)
1028     {
1029         return OC_STACK_OK;
1030     }
1031
1032     DeleteDeviceInfo();
1033     return OC_STACK_ERROR;
1034 }