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