Merge branch 'master' into resource-manipulation
[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
141         cJSON_Delete(putJson);
142     }
143
144     cJSON_AddStringToObject(json,"href",gResourceUri);
145     cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
146     cJSON_AddBoolToObject(format, "state", currLightResource->state);
147     cJSON_AddNumberToObject(format, "power", currLightResource->power);
148
149     jsonResponse = cJSON_Print(json);
150     cJSON_Delete(json);
151
152     return jsonResponse;
153 }
154
155 /*
156  * Very simple example of query parsing.
157  * The query may have multiple filters separated by ';'.
158  * It is upto the entity handler to parse the query for the individual filters,
159  * VALIDATE them and respond as it sees fit.
160
161  * This function only returns false if the query is exactly "power<X" and
162  * current power is greater than X. If X cannot be parsed for an int,
163  * true is returned.
164  */
165 bool checkIfQueryForPowerPassed(char * query)
166 {
167     if (query && strncmp(query, "power<", strlen("power<")) == 0)
168     {
169         char * pointerToOperator = strstr(query, "<");
170
171         if (pointerToOperator)
172         {
173             int powerRequested = atoi(pointerToOperator + 1);
174             if (Light.power > powerRequested)
175             {
176                 OC_LOG_V(INFO, TAG, "Current power: %d. Requested: <%d", Light.power
177                             , powerRequested);
178                 return false;
179             }
180         }
181     }
182     return true;
183 }
184
185 /*
186  * Application should validate and process these as desired.
187  */
188 OCEntityHandlerResult ValidateQueryParams (OCEntityHandlerRequest *entityHandlerRequest)
189 {
190     OC_LOG_V(INFO, TAG, PCF("Received query %s"), entityHandlerRequest->query);
191     OC_LOG(INFO, TAG, PCF("Not processing query"));
192     return OC_EH_OK;
193 }
194
195 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
196         char *payload, uint16_t maxPayloadSize)
197 {
198     OCEntityHandlerResult ehResult;
199     bool queryPassed = checkIfQueryForPowerPassed(ehRequest->query);
200
201     // Empty payload if the query has no match.
202     if (queryPassed)
203     {
204         char *getResp = constructJsonResponse(ehRequest);
205         if(!getResp)
206         {
207             OC_LOG(ERROR, TAG, "constructJsonResponse failed");
208             return OC_EH_ERROR;
209         }
210
211         if (maxPayloadSize > strlen (getResp))
212         {
213             strncpy(payload, getResp, strlen(getResp));
214             ehResult = OC_EH_OK;
215         }
216         else
217         {
218             OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
219                     maxPayloadSize);
220             ehResult = OC_EH_ERROR;
221         }
222
223         free(getResp);
224     }
225     else
226     {
227         ehResult = OC_EH_OK;
228     }
229
230     return ehResult;
231 }
232
233 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
234         char *payload, uint16_t maxPayloadSize)
235 {
236     OCEntityHandlerResult ehResult;
237     char *putResp = constructJsonResponse(ehRequest);
238
239     if(!putResp)
240     {
241         OC_LOG(ERROR, TAG, "Failed to construct Json response");
242         return OC_EH_ERROR;
243     }
244
245     if (maxPayloadSize > strlen ((char *)putResp))
246     {
247         strncpy(payload, putResp, strlen((char *)putResp));
248         ehResult = OC_EH_OK;
249     }
250     else
251     {
252         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
253                 maxPayloadSize);
254         ehResult = OC_EH_ERROR;
255     }
256
257     free(putResp);
258
259     return ehResult;
260 }
261
262 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
263         OCEntityHandlerResponse *response, char *payload, uint16_t maxPayloadSize)
264 {
265     OCEntityHandlerResult ehResult = OC_EH_OK;
266     char *respPLPost_light = NULL;
267     cJSON *json;
268     cJSON *format;
269
270     /*
271      * The entity handler determines how to process a POST request.
272      * Per the REST paradigm, POST can also be used to update representation of existing
273      * resource or create a new resource.
274      * In the sample below, if the POST is for /a/light then a new instance of the Light
275      * resource is created with default representation (if representation is included in
276      * POST payload it can be used as initial values) as long as the instance is
277      * lesser than max new instance count. Once max instance count is reached, POST on
278      * /a/light updated the representation of /a/light (just like PUT)
279      */
280
281     if (ehRequest->resource == Light.handle)
282     {
283         if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
284         {
285             // Create new Light instance
286             char newLightUri[URI_MAXSIZE];
287             snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
288
289             json = cJSON_CreateObject();
290             cJSON_AddStringToObject(json,"href",gResourceUri);
291             cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
292             cJSON_AddStringToObject(format, "createduri", (char *) newLightUri);
293
294             if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
295             {
296                 OC_LOG (INFO, TAG, "Created new Light instance\n");
297                 gLightInstance[gCurrLightInstance].state = 0;
298                 gLightInstance[gCurrLightInstance].power = 0;
299                 gCurrLightInstance++;
300                 respPLPost_light = cJSON_Print(json);
301                 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
302                 ehResult = OC_EH_RESOURCE_CREATED;
303             }
304
305             cJSON_Delete(json);
306         }
307         else
308         {
309             // Update repesentation of /a/light
310             Light.state = true;
311             Light.power = 11;
312             respPLPost_light = constructJsonResponse(ehRequest);
313         }
314     }
315     else
316     {
317         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
318         {
319             if (ehRequest->resource == gLightInstance[i].handle)
320             {
321                 gLightInstance[i].state = true;
322                 gLightInstance[i].power = 22;
323                 if (i == 0)
324                 {
325                     respPLPost_light = constructJsonResponse(ehRequest);
326                     break;
327                 }
328                 else if (i == 1)
329                 {
330                     respPLPost_light = constructJsonResponse(ehRequest);
331                 }
332             }
333         }
334     }
335
336     if ((respPLPost_light != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_light)))
337     {
338         strncpy(payload, respPLPost_light, strlen((char *)respPLPost_light));
339     }
340     else
341     {
342         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
343                 maxPayloadSize);
344         ehResult = OC_EH_ERROR;
345     }
346
347     free(respPLPost_light);
348     return ehResult;
349 }
350
351 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest,
352         char *payload, uint16_t maxPayloadSize)
353 {
354     if(ehRequest == NULL)
355     {
356         OC_LOG(INFO, TAG, "The ehRequest is NULL");
357         return OC_EH_ERROR;
358     }
359     OCEntityHandlerResult ehResult = OC_EH_OK;
360
361     OC_LOG_V(INFO, TAG, "\n\nExecuting %s for resource %d ", __func__, ehRequest->resource);
362
363     /*
364      * In the sample below, the application will:
365      * 1a. pass the delete request to the c stack
366      * 1b. internally, the c stack figures out what needs to be done and does it accordingly
367      *    (e.g. send observers notification, remove observers...)
368      * 1c. the c stack returns with the result whether the request is fullfilled.
369      * 2. optionally, app removes observers out of its array 'interestedObservers'
370      */
371
372     const char* deleteResponse = NULL;
373
374     if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
375     {
376         //Step 1: Ask stack to do the work.
377         OCStackResult result = OCDeleteResource(ehRequest->resource);
378
379         if (result == OC_STACK_OK)
380         {
381             OC_LOG (INFO, TAG, "\n\nDelete Resource operation succeeded.");
382             ehResult = OC_EH_OK;
383             deleteResponse = responsePayloadDeleteOk;
384
385             //Step 2: clear observers who wanted to observe this resource at the app level.
386             for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
387             {
388                 if (interestedObservers[i].resourceHandle == ehRequest->resource)
389                 {
390                     interestedObservers[i].valid = false;
391                     interestedObservers[i].observationId = 0;
392                     interestedObservers[i].resourceHandle = NULL;
393                 }
394             }
395         }
396         else if (result == OC_STACK_NO_RESOURCE)
397         {
398             OC_LOG(INFO, TAG, "\n\nThe resource doesn't exist or it might have been deleted.");
399             deleteResponse = responsePayloadResourceDoesNotExist;
400             ehResult = OC_EH_RESOURCE_DELETED;
401         }
402         else
403         {
404             OC_LOG(INFO, TAG, "\n\nEncountered error from OCDeleteResource().");
405             deleteResponse = responsePayloadDeleteNotOK;
406             ehResult = OC_EH_ERROR;
407         }
408     }
409     else if (ehRequest->resource != Light.handle)
410     {
411         //Let's this app not supporting DELETE on some resources so
412         //consider the DELETE request is received for a non-support resource.
413         OC_LOG_V(INFO, TAG, "\n\nThe request is received for a non-support resource.");
414         deleteResponse = responsePayloadDeleteResourceNotSupported;
415         ehResult = OC_EH_FORBIDDEN;
416     }
417
418     if (maxPayloadSize > strlen ((char *)deleteResponse))
419     {
420         strncpy(payload, deleteResponse, strlen((char *)deleteResponse));
421     }
422     else
423     {
424         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
425                 maxPayloadSize);
426         ehResult = OC_EH_ERROR;
427     }
428
429     return ehResult;
430 }
431
432 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest,
433         char *payload, uint16_t maxPayloadSize)
434 {
435     OC_LOG_V(INFO, TAG, "\n\nExecuting %s ", __func__);
436
437     const char* response = NULL;
438     response = responsePayloadResourceDoesNotExist;
439
440     if ( (ehRequest != NULL) &&
441          (maxPayloadSize > strlen ((char *)response)) )
442     {
443         strncpy((char *)payload, response, strlen((char *)response));
444     }
445     else
446     {
447         OC_LOG_V (ERROR, TAG, "Response buffer: %d bytes is too small",
448                 maxPayloadSize);
449     }
450
451     return OC_EH_RESOURCE_NOT_FOUND;
452 }
453
454 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
455 {
456     OC_LOG_V (INFO, TAG, "Received observation registration request with observation Id %d",
457             ehRequest->obsInfo.obsId);
458     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
459     {
460         if (interestedObservers[i].valid == false)
461         {
462             interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
463             interestedObservers[i].valid = true;
464             gLightUnderObservation = 1;
465             break;
466         }
467     }
468 }
469
470 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
471 {
472     bool clientStillObserving = false;
473
474     OC_LOG_V (INFO, TAG, "Received observation deregistration request for observation Id %d",
475             ehRequest->obsInfo.obsId);
476     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
477     {
478         if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
479         {
480             interestedObservers[i].valid = false;
481         }
482         if (interestedObservers[i].valid == true)
483         {
484             // Even if there is one single client observing we continue notifying entity handler
485             clientStillObserving = true;
486         }
487     }
488     if (clientStillObserving == false)
489         gLightUnderObservation = 0;
490 }
491
492 OCEntityHandlerResult
493 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
494         OCEntityHandlerRequest *entityHandlerRequest, char* uri)
495 {
496     OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
497
498     OCEntityHandlerResult ehResult = OC_EH_OK;
499     OCEntityHandlerResponse response;
500     char payload[MAX_RESPONSE_LENGTH] = {0};
501
502     // Validate pointer
503     if (!entityHandlerRequest)
504     {
505         OC_LOG (ERROR, TAG, "Invalid request pointer");
506         return OC_EH_ERROR;
507     }
508     // Initialize certain response fields
509     response.numSendVendorSpecificHeaderOptions = 0;
510     memset(response.sendVendorSpecificHeaderOptions, 0,
511             sizeof response.sendVendorSpecificHeaderOptions);
512     memset(response.resourceUri, 0, sizeof response.resourceUri);
513
514
515     if (flag & OC_REQUEST_FLAG)
516     {
517         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
518
519         if (entityHandlerRequest->resource == NULL)
520         {
521             OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
522             ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest,
523                            payload, sizeof(payload) - 1);
524         }
525         else if (OC_REST_GET == entityHandlerRequest->method)
526         {
527             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
528             ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
529         }
530         else if (OC_REST_PUT == entityHandlerRequest->method)
531         {
532             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
533             ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
534         }
535         else if (OC_REST_DELETE == entityHandlerRequest->method)
536         {
537             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
538             ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
539         }
540         else
541         {
542             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
543                       entityHandlerRequest->method);
544             ehResult = OC_EH_ERROR;
545         }
546                // If the result isn't an error or forbidden, send response
547         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
548         {
549             // Format the response.  Note this requires some info about the request
550             response.requestHandle = entityHandlerRequest->requestHandle;
551             response.resourceHandle = entityHandlerRequest->resource;
552             response.ehResult = ehResult;
553             response.payload = payload;
554             response.payloadSize = strlen(payload);
555             // Indicate that response is NOT in a persistent buffer
556             response.persistentBufferFlag = 0;
557
558             // Send the response
559             if (OCDoResponse(&response) != OC_STACK_OK)
560             {
561                 OC_LOG(ERROR, TAG, "Error sending response");
562                 ehResult = OC_EH_ERROR;
563             }
564         }
565     }
566     if (flag & OC_OBSERVE_FLAG)
567     {
568         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
569         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
570         {
571             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
572         }
573         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
574         {
575             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
576         }
577     }
578
579     return ehResult;
580 }
581
582 OCEntityHandlerResult
583 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
584         OCEntityHandlerRequest *entityHandlerRequest)
585 {
586     // This is callback is associated with the 2 presence notification
587     // resources. They are non-operational.
588     return OC_EH_OK;
589 }
590
591 OCEntityHandlerResult
592 OCEntityHandlerCb (OCEntityHandlerFlag flag,
593         OCEntityHandlerRequest *entityHandlerRequest)
594 {
595     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
596
597     OCEntityHandlerResult ehResult = OC_EH_OK;
598     OCEntityHandlerResponse response;
599     char payload[MAX_RESPONSE_LENGTH] = {0};
600
601     // Validate pointer
602     if (!entityHandlerRequest)
603     {
604         OC_LOG (ERROR, TAG, "Invalid request pointer");
605         return OC_EH_ERROR;
606     }
607
608     // Initialize certain response fields
609     response.numSendVendorSpecificHeaderOptions = 0;
610     memset(response.sendVendorSpecificHeaderOptions,
611             0, sizeof response.sendVendorSpecificHeaderOptions);
612     memset(response.resourceUri, 0, sizeof response.resourceUri);
613
614     if (flag & OC_REQUEST_FLAG)
615     {
616         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
617
618         if (OC_REST_GET == entityHandlerRequest->method)
619         {
620             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
621             ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
622         }
623         else if (OC_REST_PUT == entityHandlerRequest->method)
624         {
625             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
626             ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
627         }
628         else if (OC_REST_POST == entityHandlerRequest->method)
629         {
630             OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
631             ehResult = ProcessPostRequest (entityHandlerRequest, &response, payload, sizeof(payload) - 1);
632         }
633         else if (OC_REST_DELETE == entityHandlerRequest->method)
634         {
635             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
636             ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
637         }
638         else
639         {
640             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
641                       entityHandlerRequest->method);
642             ehResult = OC_EH_ERROR;
643         }
644         // If the result isn't an error or forbidden, send response
645         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
646         {
647             // Format the response.  Note this requires some info about the request
648             response.requestHandle = entityHandlerRequest->requestHandle;
649             response.resourceHandle = entityHandlerRequest->resource;
650             response.ehResult = ehResult;
651             response.payload = payload;
652             response.payloadSize = strlen(payload);
653             // Indicate that response is NOT in a persistent buffer
654             response.persistentBufferFlag = 0;
655
656             // Handle vendor specific options
657             if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
658                     entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
659             {
660                 OC_LOG (INFO, TAG, "Received vendor specific options");
661                 uint8_t i = 0;
662                 OCHeaderOption * rcvdOptions =
663                         entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
664                 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
665                 {
666                     if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
667                     {
668                         OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
669                                 ((OCHeaderOption)rcvdOptions[i]).optionID );
670
671                         OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
672                             MAX_HEADER_OPTION_DATA_LENGTH);
673                     }
674                 }
675                 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
676                 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
677                 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
678                 sendOptions[0].protocolID = OC_COAP_ID;
679                 sendOptions[0].optionID = 2248;
680                 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
681                 sendOptions[0].optionLength = 10;
682                 sendOptions[1].protocolID = OC_COAP_ID;
683                 sendOptions[1].optionID = 2600;
684                 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
685                 sendOptions[1].optionLength = 10;
686                 response.numSendVendorSpecificHeaderOptions = 2;
687             }
688
689             // Send the response
690             if (OCDoResponse(&response) != OC_STACK_OK)
691             {
692                 OC_LOG(ERROR, TAG, "Error sending response");
693                 ehResult = OC_EH_ERROR;
694             }
695         }
696     }
697     if (flag & OC_OBSERVE_FLAG)
698     {
699         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
700
701         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
702         {
703             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
704             ProcessObserveRegister (entityHandlerRequest);
705         }
706         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
707         {
708             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
709             ProcessObserveDeregister (entityHandlerRequest);
710         }
711     }
712
713     return ehResult;
714 }
715
716 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
717 void handleSigInt(int signum)
718 {
719     if (signum == SIGINT)
720     {
721         gQuitFlag = 1;
722     }
723 }
724
725 void *ChangeLightRepresentation (void *param)
726 {
727     (void)param;
728     OCStackResult result = OC_STACK_ERROR;
729
730     uint8_t j = 0;
731     uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
732     OCObservationId obsNotify[numNotifies];
733
734     while (!gQuitFlag)
735     {
736         sleep(3);
737         Light.power += 5;
738         if (gLightUnderObservation)
739         {
740             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
741             if (gObserveNotifyType == 1)
742             {
743                 // Notify list of observers. Alternate observers on the list will be notified.
744                 j = 0;
745                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
746                 {
747                     if (interestedObservers[i].valid == true)
748                     {
749                         obsNotify[j] = interestedObservers[i].observationId;
750                         j++;
751                     }
752                 }
753
754                 cJSON *json = cJSON_CreateObject();
755                 cJSON *format;
756                 cJSON_AddStringToObject(json,"href",gResourceUri);
757                 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
758                 cJSON_AddBoolToObject(format, "state", Light.state);
759                 cJSON_AddNumberToObject(format, "power", Light.power);
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(5);
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 }