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