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