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