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