Modified ocserver to make presence flow clearer.
[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 (ERROR, TAG, "Response buffer: %d bytes is too small",
364                 maxPayloadSize);
365     }
366
367     return OC_EH_RESOURCE_NOT_FOUND;
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 = 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 = 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
595                         OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
596                             MAX_HEADER_OPTION_DATA_LENGTH);
597                     }
598                 }
599                 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
600                 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
601                 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
602                 sendOptions[0].protocolID = OC_COAP_ID;
603                 sendOptions[0].optionID = 2248;
604                 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
605                 sendOptions[0].optionLength = 10;
606                 sendOptions[1].protocolID = OC_COAP_ID;
607                 sendOptions[1].optionID = 2600;
608                 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
609                 sendOptions[1].optionLength = 10;
610                 response.numSendVendorSpecificHeaderOptions = 2;
611             }
612
613             // Send the response
614             if (OCDoResponse(&response) != OC_STACK_OK)
615             {
616                 OC_LOG(ERROR, TAG, "Error sending response");
617                 ehResult = OC_EH_ERROR;
618             }
619         }
620     }
621     if (flag & OC_OBSERVE_FLAG)
622     {
623         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
624
625         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
626         {
627             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
628             ProcessObserveRegister (entityHandlerRequest);
629         }
630         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
631         {
632             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
633             ProcessObserveDeregister (entityHandlerRequest);
634         }
635     }
636
637     return ehResult;
638 }
639
640 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
641 void handleSigInt(int signum)
642 {
643     if (signum == SIGINT)
644     {
645         gQuitFlag = 1;
646     }
647 }
648
649 void *ChangeLightRepresentation (void *param)
650 {
651     (void)param;
652     OCStackResult result = OC_STACK_ERROR;
653
654     uint8_t j = 0;
655     uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
656     OCObservationId obsNotify[numNotifies];
657
658     while (!gQuitFlag)
659     {
660         sleep(10);
661         Light.power += 5;
662         if (gLightUnderObservation)
663         {
664             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
665             if (gObserveNotifyType == 1)
666             {
667                 // Notify list of observers. Alternate observers on the list will be notified.
668                 j = 0;
669                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
670                 {
671                     if (interestedObservers[i].valid == true)
672                     {
673                         obsNotify[j] = interestedObservers[i].observationId;
674                         j++;
675                     }
676                 }
677
678                 cJSON *json = cJSON_CreateObject();
679                 cJSON *format;
680                 cJSON_AddStringToObject(json,"href",gResourceUri);
681                 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
682                 cJSON_AddBoolToObject(format, "state", Light.state);
683                 cJSON_AddNumberToObject(format, "power", Light.power);
684                 char * obsResp = cJSON_Print(json);
685                 cJSON_Delete(json);
686                 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
687                         obsResp, OC_NA_QOS);
688                 free(obsResp);
689             }
690             else if (gObserveNotifyType == 0)
691             {
692                 // Notifying all observers
693                 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
694                 if (OC_STACK_NO_OBSERVERS == result)
695                 {
696                     OC_LOG (INFO, TAG,
697                             "=======> No more observers exist, stop sending observations");
698                     gLightUnderObservation = 0;
699                 }
700             }
701             else
702             {
703                 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
704             }
705         }
706 #ifdef WITH_PRESENCE
707         if(stopPresenceCount > 0)
708         {
709             OC_LOG_V(INFO, TAG, "================  Counting down to stop presence %d", stopPresenceCount);
710         }
711         if(!stopPresenceCount--)
712         {
713             OC_LOG(INFO, TAG, "================ stopping presence");
714             OCStopPresence();
715         }
716 #endif
717     }
718     return NULL;
719 }
720
721 #ifdef WITH_PRESENCE
722 void *presenceNotificationGenerator(void *param)
723 {
724     sleep(5);
725     (void)param;
726     OCDoHandle presenceNotificationHandles[numPresenceResources];
727     OCStackResult res = OC_STACK_OK;
728
729     std::array<std::string, numPresenceResources> presenceNotificationResources { {
730         std::string("core.fan"),
731         std::string("core.led") } };
732     std::array<std::string, numPresenceResources> presenceNotificationUris { {
733         std::string("/a/fan"),
734         std::string("/a/led") } };
735
736     for(int i=0; i<numPresenceResources; i++)
737     {
738         if(res == OC_STACK_OK)
739         {
740             sleep(1);
741             res = OCCreateResource(&presenceNotificationHandles[i],
742                     presenceNotificationResources.at(i).c_str(),
743                     "oc.mi.def",
744                     presenceNotificationUris.at(i).c_str(),
745                     OCNOPEntityHandlerCb,
746                     OC_DISCOVERABLE|OC_OBSERVABLE);
747         }
748         if(res != OC_STACK_OK)
749         {
750             OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
751                     "%s with result %s.", presenceNotificationResources.at(i).c_str(),
752                     getResult(res));
753             break;
754         }
755         OC_LOG_V(INFO, TAG, PCF("Created %s for presence notification"),
756                                 presenceNotificationUris[i].c_str());
757     }
758     sleep(5);
759     for(int i=0; i<numPresenceResources; i++)
760     {
761         if(res == OC_STACK_OK)
762         {
763             res = OCDeleteResource(presenceNotificationHandles[i]);
764         }
765         if(res != OC_STACK_OK)
766         {
767             OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
768                     "resource %s.", presenceNotificationResources.at(i).c_str());
769             break;
770         }
771         OC_LOG_V(INFO, TAG, PCF("Deleted %s for presence notification"),
772                                 presenceNotificationUris[i].c_str());
773     }
774     return NULL;
775 }
776 #endif
777
778 static void PrintUsage()
779 {
780     OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
781     OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
782     OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
783 }
784
785 int main(int argc, char* argv[])
786 {
787     pthread_t threadId;
788     pthread_t threadId_presence;
789     int opt;
790
791     while ((opt = getopt(argc, argv, "o:")) != -1)
792     {
793         switch(opt)
794         {
795             case 'o':
796                 gObserveNotifyType = atoi(optarg);
797                 break;
798             default:
799                 PrintUsage();
800                 return -1;
801         }
802     }
803
804     if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
805     {
806         PrintUsage();
807         return -1;
808     }
809
810     OC_LOG(DEBUG, TAG, "OCServer is starting...");
811
812     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
813     {
814         OC_LOG(ERROR, TAG, "OCStack init error");
815         return 0;
816     }
817 #ifdef WITH_PRESENCE
818     if (OCStartPresence(0) != OC_STACK_OK)
819     {
820         OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
821         return 0;
822     }
823 #endif
824
825     OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb);
826
827     OCStackResult deviceResult = SetDeviceInfo(contentType, dateOfManufacture, deviceName,
828             deviceUUID, firmwareVersion, hostName, manufacturerName,
829             manufacturerUrl, modelNumber, platformVersion, supportUrl, version);
830
831     if (deviceResult != OC_STACK_OK)
832     {
833         OC_LOG(INFO, TAG, "Device Registration failed!");
834         exit (EXIT_FAILURE);
835     }
836
837     deviceResult = OCSetDeviceInfo(deviceInfo);
838
839     if (deviceResult != OC_STACK_OK)
840     {
841         OC_LOG(INFO, TAG, "Device Registration failed!");
842         exit (EXIT_FAILURE);
843     }
844
845     /*
846      * Declare and create the example resource: Light
847      */
848     createLightResource(gResourceUri, &Light);
849
850     // Initialize observations data structure for the resource
851     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
852     {
853         interestedObservers[i].valid = false;
854     }
855
856     /*
857      * Create a thread for changing the representation of the Light
858      */
859     pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
860
861     /*
862      * Create a thread for generating changes that cause presence notifications
863      * to be sent to clients
864      */
865
866     #ifdef WITH_PRESENCE
867     pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
868     #endif
869
870     // Break from loop with Ctrl-C
871     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
872     DeleteDeviceInfo();
873     signal(SIGINT, handleSigInt);
874     while (!gQuitFlag)
875     {
876         if (OCProcess() != OC_STACK_OK)
877         {
878             OC_LOG(ERROR, TAG, "OCStack process error");
879             return 0;
880         }
881
882         sleep(2);
883     }
884
885     /*
886      * Cancel the Light thread and wait for it to terminate
887      */
888     pthread_cancel(threadId);
889     pthread_join(threadId, NULL);
890     pthread_cancel(threadId_presence);
891     pthread_join(threadId_presence, NULL);
892
893     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
894
895     if (OCStop() != OC_STACK_OK)
896     {
897         OC_LOG(ERROR, TAG, "OCStack process error");
898     }
899
900     return 0;
901 }
902
903 int createLightResource (char *uri, LightResource *lightResource)
904 {
905     if (!uri)
906     {
907         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
908         return -1;
909     }
910
911     lightResource->state = false;
912     lightResource->power= 0;
913     OCStackResult res = OCCreateResource(&(lightResource->handle),
914             "core.light",
915             "oc.mi.def",
916             uri,
917             OCEntityHandlerCb,
918             OC_DISCOVERABLE|OC_OBSERVABLE);
919     OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
920
921     return 0;
922 }
923
924 void DeleteDeviceInfo()
925 {
926     free(deviceInfo.contentType);
927     free(deviceInfo.dateOfManufacture);
928     free(deviceInfo.deviceName);
929     free(deviceInfo.deviceUUID);
930     free(deviceInfo.firmwareVersion);
931     free(deviceInfo.hostName);
932     free(deviceInfo.manufacturerName);
933     free(deviceInfo.manufacturerUrl);
934     free(deviceInfo.modelNumber);
935     free(deviceInfo.platformVersion);
936     free(deviceInfo.supportUrl);
937     free(deviceInfo.version);
938 }
939
940 bool DuplicateString(char** targetString, const char* sourceString)
941 {
942     if(!sourceString)
943     {
944         return false;
945     }
946     else
947     {
948         *targetString = (char *) malloc(strlen(sourceString) + 1);
949
950         if(*targetString)
951         {
952             strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
953             return true;
954         }
955     }
956     return false;
957 }
958
959 OCStackResult SetDeviceInfo(const char *contentType, const char *dateOfManufacture,
960         const char *deviceName, const char *deviceUUID, const char *firmwareVersion,
961         const char *hostName, const char *manufacturerName, const char *manufacturerUrl,
962         const char *modelNumber, const char *platformVersion, const char *supportUrl,
963         const char *version)
964 {
965
966     bool success = true;
967
968     if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
969     {
970         return OC_STACK_INVALID_PARAM;
971     }
972
973     if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
974     {
975         return OC_STACK_INVALID_PARAM;
976     }
977
978     if(!DuplicateString(&deviceInfo.contentType, contentType))
979     {
980         success = false;
981     }
982
983     if(!DuplicateString(&deviceInfo.dateOfManufacture, dateOfManufacture))
984     {
985         success = false;
986     }
987
988     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
989     {
990         success = false;
991     }
992
993     if(!DuplicateString(&deviceInfo.deviceUUID, deviceUUID))
994     {
995         success = false;
996     }
997
998     if(!DuplicateString(&deviceInfo.firmwareVersion, firmwareVersion))
999     {
1000         success = false;
1001     }
1002
1003     if(!DuplicateString(&deviceInfo.hostName, hostName))
1004     {
1005         success = false;
1006     }
1007
1008     if(!DuplicateString(&deviceInfo.manufacturerName, manufacturerName))
1009     {
1010         success = false;
1011     }
1012
1013     if(!DuplicateString(&deviceInfo.manufacturerUrl, manufacturerUrl))
1014     {
1015         success = false;
1016     }
1017
1018     if(!DuplicateString(&deviceInfo.modelNumber, modelNumber))
1019     {
1020         success = false;
1021     }
1022
1023     if(!DuplicateString(&deviceInfo.platformVersion, platformVersion))
1024     {
1025         success = false;
1026     }
1027
1028     if(!DuplicateString(&deviceInfo.supportUrl, supportUrl))
1029     {
1030         success = false;
1031     }
1032
1033     if(!DuplicateString(&deviceInfo.version, version))
1034     {
1035         success = false;
1036     }
1037
1038     if(success)
1039     {
1040         return OC_STACK_OK;
1041     }
1042
1043     DeleteDeviceInfo();
1044     return OC_STACK_ERROR;
1045 }