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