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