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