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