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