Merge "Updated the .gitignore"
[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 <stdlib.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <pthread.h>
28 #include "ocstack.h"
29 #include "logger.h"
30 #include "cJSON.h"
31 #include "ocserver.h"
32
33 //string length of "/a/light/" + std::numeric_limits<int>::digits10 + '\0'"
34 // 9 + 9 + 1 = 19
35 const int URI_MAXSIZE = 19;
36
37 static int gObserveNotifyType = 3;
38
39 int gQuitFlag = 0;
40 int gLightUnderObservation = 0;
41
42 static LightResource Light;
43 // This variable determines instance number of the Light resource.
44 // Used by POST method to create a new instance of Light resource.
45 static int gCurrLightInstance = 0;
46
47 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
48
49 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
50
51 #ifdef WITH_PRESENCE
52 static int stopPresenceCount = 10;
53 #endif
54
55 //TODO: Follow the pattern used in constructJsonResponse() when the payload is decided.
56 const char responsePayloadDeleteOk[] = "{App determines payload: Delete Resource operation succeeded.}";
57 const char responsePayloadDeleteNotOK[] = "{App determines payload: Delete Resource operation failed.}";
58 const char responsePayloadResourceDoesNotExist[] = "{App determines payload: The resource does not exist.}";
59 const char responsePayloadDeleteResourceNotSupported[] =
60         "{App determines payload: The request is received for a non-support resource.}";
61
62
63 char *gResourceUri= (char *)"/a/light";
64
65 static uint16_t OC_WELL_KNOWN_PORT = 5683;
66
67 //This function takes the request as an input and returns the response
68 //in JSON format.
69 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
70 {
71     cJSON *json = cJSON_CreateObject();
72     cJSON *format;
73     char *jsonResponse;
74     LightResource *currLightResource = &Light;
75
76     if (ehRequest->resource == gLightInstance[0].handle)
77     {
78         currLightResource = &gLightInstance[0];
79         gResourceUri = (char *) "a/light/0";
80     }
81     else if (ehRequest->resource == gLightInstance[1].handle)
82     {
83         currLightResource = &gLightInstance[1];
84         gResourceUri = (char *) "a/light/1";
85     }
86
87     if(OC_REST_PUT == ehRequest->method)
88     {
89         cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload);
90         currLightResource->state = ( !strcmp(cJSON_GetObjectItem(putJson,"state")->valuestring,
91                 "on") ? true:false);
92         currLightResource->power = cJSON_GetObjectItem(putJson,"power")->valuedouble;
93         cJSON_Delete(putJson);
94     }
95
96     cJSON_AddStringToObject(json,"href",gResourceUri);
97     cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
98     cJSON_AddStringToObject(format, "state", (char *) (currLightResource->state ? "on":"off"));
99     cJSON_AddNumberToObject(format, "power", currLightResource->power);
100
101     jsonResponse = cJSON_Print(json);
102     cJSON_Delete(json);
103
104     return jsonResponse;
105 }
106
107 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, char *payload, uint16_t maxPayloadSize)
108 {
109     OCEntityHandlerResult ehResult;
110     char *getResp = constructJsonResponse(ehRequest);
111
112     if (maxPayloadSize > strlen ((char *)getResp))
113     {
114         strncpy(payload, getResp, strlen((char *)getResp));
115         ehResult = OC_EH_OK;
116     }
117     else
118     {
119         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
120                 maxPayloadSize);
121         ehResult = OC_EH_ERROR;
122     }
123
124     free(getResp);
125
126     return ehResult;
127 }
128
129 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, char *payload, uint16_t maxPayloadSize)
130 {
131     OCEntityHandlerResult ehResult;
132     char *putResp = constructJsonResponse(ehRequest);
133
134     if (maxPayloadSize > strlen ((char *)putResp))
135     {
136         strncpy(payload, putResp, strlen((char *)putResp));
137         ehResult = OC_EH_OK;
138     }
139     else
140     {
141         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
142                 maxPayloadSize);
143         ehResult = OC_EH_ERROR;
144     }
145
146     free(putResp);
147
148     return ehResult;
149 }
150
151 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, OCEntityHandlerResponse *response, char *payload, uint16_t maxPayloadSize)
152 {
153     OCEntityHandlerResult ehResult = OC_EH_OK;
154     char *respPLPost_light = NULL;
155     cJSON *json;
156     cJSON *format;
157
158     /*
159      * The entity handler determines how to process a POST request.
160      * Per the REST paradigm, POST can also be used to update representation of existing
161      * resource or create a new resource.
162      * In the sample below, if the POST is for /a/light then a new instance of the Light
163      * resource is created with default representation (if representation is included in
164      * POST payload it can be used as initial values) as long as the instance is
165      * lesser than max new instance count. Once max instance count is reached, POST on
166      * /a/light updated the representation of /a/light (just like PUT)
167      */
168
169     if (ehRequest->resource == Light.handle)
170     {
171         if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
172         {
173             // Create new Light instance
174             char newLightUri[URI_MAXSIZE];
175             snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
176
177             json = cJSON_CreateObject();
178             cJSON_AddStringToObject(json,"href",gResourceUri);
179             cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
180             cJSON_AddStringToObject(format, "createduri", (char *) newLightUri);
181
182             if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
183             {
184                 OC_LOG (INFO, TAG, "Created new Light instance\n");
185                 gLightInstance[gCurrLightInstance].state = 0;
186                 gLightInstance[gCurrLightInstance].power = 0;
187                 gCurrLightInstance++;
188                 respPLPost_light = cJSON_Print(json);
189                 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
190                 ehResult = OC_EH_RESOURCE_CREATED;
191             }
192
193             cJSON_Delete(json);
194         }
195         else
196         {
197             // Update repesentation of /a/light
198             Light.state = true;
199             Light.power = 11;
200             respPLPost_light = constructJsonResponse(ehRequest);
201         }
202     }
203     else
204     {
205         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
206         {
207             if (ehRequest->resource == gLightInstance[i].handle)
208             {
209                 gLightInstance[i].state = true;
210                 gLightInstance[i].power = 22;
211                 if (i == 0)
212                 {
213                     respPLPost_light = constructJsonResponse(ehRequest);
214                     break;
215                 }
216                 else if (i == 1)
217                 {
218                     respPLPost_light = constructJsonResponse(ehRequest);
219                 }
220             }
221         }
222     }
223
224     if ((respPLPost_light != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_light)))
225     {
226         strncpy(payload, respPLPost_light, strlen((char *)respPLPost_light));
227     }
228     else
229     {
230         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
231                 maxPayloadSize);
232         ehResult = OC_EH_ERROR;
233     }
234
235     free(respPLPost_light);
236     return ehResult;
237 }
238
239 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest, char *payload, uint16_t maxPayloadSize)
240 {
241     if(ehRequest == NULL)
242     {
243         OC_LOG(INFO, TAG, "The ehRequest is NULL");
244         return OC_EH_ERROR;
245     }
246     OCEntityHandlerResult ehResult = OC_EH_OK;
247
248     OC_LOG_V(INFO, TAG, "\n\nExecuting %s for resource %d ", __func__, ehRequest->resource);
249
250     /*
251      * In the sample below, the application will:
252      * 1a. pass the delete request to the c stack
253      * 1b. internally, the c stack figures out what needs to be done and does it accordingly
254      *    (e.g. send observers notification, remove observers...)
255      * 1c. the c stack returns with the result whether the request is fullfilled.
256      * 2. optionally, app removes observers out of its array 'interestedObservers'
257      */
258
259     const char* deleteResponse = NULL;
260
261     if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
262     {
263         //Step 1: Ask stack to do the work.
264         OCStackResult result = OCDeleteResource(ehRequest->resource);
265
266         if (result == OC_STACK_OK)
267         {
268             OC_LOG (INFO, TAG, "\n\nDelete Resource operation succeeded.");
269             ehResult = OC_EH_OK;
270             deleteResponse = responsePayloadDeleteOk;
271
272             //Step 2: clear observers who wanted to observe this resource at the app level.
273             for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
274             {
275                 if (interestedObservers[i].resourceHandle == ehRequest->resource)
276                 {
277                     interestedObservers[i].valid = false;
278                     interestedObservers[i].observationId = 0;
279                     interestedObservers[i].resourceHandle = NULL;
280                 }
281             }
282         }
283         else if (result == OC_STACK_NO_RESOURCE)
284         {
285             OC_LOG(INFO, TAG, "\n\nThe resource doesn't exist or it might have been deleted.");
286             deleteResponse = responsePayloadResourceDoesNotExist;
287             ehResult = OC_EH_RESOURCE_DELETED;
288         }
289         else
290         {
291             OC_LOG(INFO, TAG, "\n\nEncountered error from OCDeleteResource().");
292             deleteResponse = responsePayloadDeleteNotOK;
293             ehResult = OC_EH_ERROR;
294         }
295     }
296     else if (ehRequest->resource != Light.handle)
297     {
298         //Let's this app not supporting DELETE on some resources so
299         //consider the DELETE request is received for a non-support resource.
300         OC_LOG_V(INFO, TAG, "\n\nThe request is received for a non-support resource.");
301         deleteResponse = responsePayloadDeleteResourceNotSupported;
302         ehResult = OC_EH_FORBIDDEN;
303     }
304
305     if (maxPayloadSize > strlen ((char *)deleteResponse))
306     {
307         strncpy(payload, deleteResponse, strlen((char *)deleteResponse));
308     }
309     else
310     {
311         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
312                 maxPayloadSize);
313         ehResult = OC_EH_ERROR;
314     }
315
316     return ehResult;
317 }
318
319 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest, char *payload, uint16_t maxPayloadSize)
320 {
321     OC_LOG_V(INFO, TAG, "\n\nExecuting %s ", __func__);
322
323     const char* response = NULL;
324     response = responsePayloadResourceDoesNotExist;
325
326     if ( (ehRequest != NULL) &&
327          (maxPayloadSize > strlen ((char *)response)) )
328     {
329         strncpy((char *)payload, response, strlen((char *)response));
330     }
331     else
332     {
333         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
334                 maxPayloadSize);
335     }
336
337     return OC_EH_RESOURCE_DELETED;
338 }
339
340 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
341 {
342     OC_LOG_V (INFO, TAG, "Received observation registration request with observation Id %d",
343             ehRequest->obsInfo.obsId);
344     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
345     {
346         if (interestedObservers[i].valid == false)
347         {
348             interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
349             interestedObservers[i].valid = true;
350             gLightUnderObservation = 1;
351             break;
352         }
353     }
354 }
355
356 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
357 {
358     bool clientStillObserving = false;
359
360     OC_LOG_V (INFO, TAG, "Received observation deregistration request for observation Id %d",
361             ehRequest->obsInfo.obsId);
362     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
363     {
364         if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
365         {
366             interestedObservers[i].valid = false;
367         }
368         if (interestedObservers[i].valid == true)
369         {
370             // Even if there is one single client observing we continue notifying entity handler
371             clientStillObserving = true;
372         }
373     }
374     if (clientStillObserving == false)
375         gLightUnderObservation = 0;
376 }
377
378 OCEntityHandlerResult
379 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
380         OCEntityHandlerRequest *entityHandlerRequest, char* uri)
381 {
382     OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
383
384     OCEntityHandlerResult ehResult = OC_EH_OK;
385     OCEntityHandlerResponse response;
386     char payload[MAX_RESPONSE_LENGTH] = {0};
387
388     // Validate pointer
389     if (!entityHandlerRequest)
390     {
391         OC_LOG (ERROR, TAG, "Invalid request pointer");
392         return OC_EH_ERROR;
393     }
394
395     // Initialize certain response fields
396     response.numSendVendorSpecificHeaderOptions = 0;
397     memset(response.sendVendorSpecificHeaderOptions, 0, sizeof response.sendVendorSpecificHeaderOptions);
398     memset(response.resourceUri, 0, sizeof response.resourceUri);
399
400     if (flag & OC_INIT_FLAG)
401     {
402         OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
403     }
404     if (flag & OC_REQUEST_FLAG)
405     {
406         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
407         if (entityHandlerRequest->resource == NULL) {
408             OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
409             ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest, payload, sizeof(payload) - 1);
410         }
411         else if (OC_REST_GET == entityHandlerRequest->method)
412         {
413             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
414             ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
415         }
416         else if (OC_REST_PUT == entityHandlerRequest->method)
417         {
418             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
419             ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
420         }
421         else if (OC_REST_DELETE == entityHandlerRequest->method)
422         {
423             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
424             ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
425         }
426         else
427         {
428             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
429                     entityHandlerRequest->method);
430             ehResult = OC_EH_ERROR;
431         }
432
433         // If the result isn't an error or forbidden, send response
434         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
435         {
436             // Format the response.  Note this requires some info about the request
437             response.requestHandle = entityHandlerRequest->requestHandle;
438             response.resourceHandle = entityHandlerRequest->resource;
439             response.ehResult = ehResult;
440             response.payload = (unsigned char *)payload;
441             response.payloadSize = strlen(payload);
442             // Indicate that response is NOT in a persistent buffer
443             response.persistentBufferFlag = 0;
444
445             // Send the response
446             if (OCDoResponse(&response) != OC_STACK_OK)
447             {
448                 OC_LOG(ERROR, TAG, "Error sending response");
449                 ehResult = OC_EH_ERROR;
450             }
451         }
452     }
453     if (flag & OC_OBSERVE_FLAG)
454     {
455         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
456         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
457         {
458             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
459         }
460         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
461         {
462             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
463         }
464     }
465
466     return ehResult;
467 }
468
469
470 OCEntityHandlerResult
471 OCEntityHandlerCb (OCEntityHandlerFlag flag,
472         OCEntityHandlerRequest *entityHandlerRequest)
473 {
474     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
475
476     OCEntityHandlerResult ehResult = OC_EH_OK;
477     OCEntityHandlerResponse response;
478     char payload[MAX_RESPONSE_LENGTH] = {0};
479
480     // Validate pointer
481     if (!entityHandlerRequest)
482     {
483         OC_LOG (ERROR, TAG, "Invalid request pointer");
484         return OC_EH_ERROR;
485     }
486
487     // Initialize certain response fields
488     response.numSendVendorSpecificHeaderOptions = 0;
489     memset(response.sendVendorSpecificHeaderOptions, 0, sizeof response.sendVendorSpecificHeaderOptions);
490     memset(response.resourceUri, 0, sizeof response.resourceUri);
491
492     if (flag & OC_INIT_FLAG)
493     {
494         OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
495     }
496     if (flag & OC_REQUEST_FLAG)
497     {
498         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
499         if (OC_REST_GET == entityHandlerRequest->method)
500         {
501             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
502             ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
503         }
504         else if (OC_REST_PUT == entityHandlerRequest->method)
505         {
506             OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
507             ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
508         }
509         else if (OC_REST_POST == entityHandlerRequest->method)
510         {
511             OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
512             ehResult = ProcessPostRequest (entityHandlerRequest, &response, payload, sizeof(payload) - 1);
513         }
514         else if (OC_REST_DELETE == entityHandlerRequest->method)
515         {
516             OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
517             ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
518         }
519         else
520         {
521             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
522                     entityHandlerRequest->method);
523         }
524
525         // If the result isn't an error or forbidden, send response
526         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
527         {
528             // Format the response.  Note this requires some info about the request
529             response.requestHandle = entityHandlerRequest->requestHandle;
530             response.resourceHandle = entityHandlerRequest->resource;
531             response.ehResult = ehResult;
532             response.payload = (unsigned char *)payload;
533             response.payloadSize = strlen(payload);
534             // Indicate that response is NOT in a persistent buffer
535             response.persistentBufferFlag = 0;
536
537             // Handle vendor specific options
538             if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
539                     entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
540             {
541                 OC_LOG (INFO, TAG, "Received vendor specific options");
542                 uint8_t i = 0;
543                 OCHeaderOption * rcvdOptions = entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
544                 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
545                 {
546                     if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
547                     {
548                         OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
549                                 ((OCHeaderOption)rcvdOptions[i]).optionID );
550                         OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
551                                 ((OCHeaderOption)rcvdOptions[i]).optionLength);
552                     }
553                 }
554                 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
555                 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
556                 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
557                 sendOptions[0].protocolID = OC_COAP_ID;
558                 sendOptions[0].optionID = 2248;
559                 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
560                 sendOptions[0].optionLength = 10;
561                 sendOptions[1].protocolID = OC_COAP_ID;
562                 sendOptions[1].optionID = 2600;
563                 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
564                 sendOptions[1].optionLength = 10;
565                 response.numSendVendorSpecificHeaderOptions = 2;
566             }
567
568             // Send the response
569             if (OCDoResponse(&response) != OC_STACK_OK)
570             {
571                 OC_LOG(ERROR, TAG, "Error sending response");
572                 ehResult = OC_EH_ERROR;
573             }
574         }
575     }
576     if (flag & OC_OBSERVE_FLAG)
577     {
578         OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
579
580         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
581         {
582             OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
583             ProcessObserveRegister (entityHandlerRequest);
584         }
585         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
586         {
587             OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
588             ProcessObserveDeregister (entityHandlerRequest);
589         }
590     }
591
592     return ehResult;
593 }
594
595 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
596 void handleSigInt(int signum) {
597     if (signum == SIGINT) {
598         gQuitFlag = 1;
599     }
600 }
601
602 void *ChangeLightRepresentation (void *param)
603 {
604     (void)param;
605     OCStackResult result = OC_STACK_ERROR;
606
607     uint8_t j = 0;
608     uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
609     OCObservationId obsNotify[numNotifies];
610
611     while (!gQuitFlag)
612     {
613         sleep(10);
614         Light.power += 5;
615         if (gLightUnderObservation)
616         {
617             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
618             if (gObserveNotifyType == 1)
619             {
620                 // Notify list of observers. Alternate observers on the list will be notified.
621                 j = 0;
622                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
623                 {
624                     if (interestedObservers[i].valid == true)
625                     {
626                         obsNotify[j] = interestedObservers[i].observationId;
627                         j++;
628                     }
629                 }
630
631                 cJSON *json = cJSON_CreateObject();
632                 cJSON *format;
633                 cJSON_AddStringToObject(json,"href",gResourceUri);
634                 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
635                 cJSON_AddStringToObject(format, "state", (char *) (Light.state ? "on":"off"));
636                 cJSON_AddNumberToObject(format, "power", Light.power);
637                 char * obsResp = cJSON_Print(json);
638                 cJSON_Delete(json);
639                 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
640                         (unsigned char *)obsResp, OC_NA_QOS);
641                 free(obsResp);
642             }
643             else if (gObserveNotifyType == 0)
644             {
645                 // Notifying all observers
646                 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
647                 if (OC_STACK_NO_OBSERVERS == result)
648                 {
649                     OC_LOG (INFO, TAG,
650                             "=======> No more observers exist, stop sending observations");
651                     gLightUnderObservation = 0;
652                 }
653             }
654             else
655             {
656                 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
657             }
658         }
659 #ifdef WITH_PRESENCE
660         if(stopPresenceCount > 0)
661         {
662             OC_LOG_V(INFO, TAG, "================ presence count %d", stopPresenceCount);
663         }
664         if(!stopPresenceCount--)
665         {
666             OC_LOG(INFO, TAG, "================ stopping presence");
667             OCStopPresence();
668         }
669 #endif
670     }
671     return NULL;
672 }
673
674 static void PrintUsage()
675 {
676     OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
677     OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
678     OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
679 }
680
681 int main(int argc, char* argv[])
682 {
683     uint8_t addr[20] = {0};
684     uint8_t* paddr = NULL;
685     uint16_t port = OC_WELL_KNOWN_PORT;
686     uint8_t ifname[] = "eth0";
687     pthread_t threadId;
688     int opt;
689
690     while ((opt = getopt(argc, argv, "o:")) != -1)
691     {
692         switch(opt)
693         {
694             case 'o':
695                 gObserveNotifyType = atoi(optarg);
696                 break;
697             default:
698                 PrintUsage();
699                 return -1;
700         }
701     }
702
703     if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
704     {
705         PrintUsage();
706         return -1;
707     }
708
709     OC_LOG(DEBUG, TAG, "OCServer is starting...");
710     /*Get Ip address on defined interface and initialize coap on it with random port number
711      * this port number will be used as a source port in all coap communications*/
712     if ( OCGetInterfaceAddress(ifname, sizeof(ifname), AF_INET, addr,
713                 sizeof(addr)) == ERR_SUCCESS)
714     {
715         OC_LOG_V(INFO, TAG, "Starting ocserver on address %s:%d",addr,port);
716         paddr = addr;
717     }
718
719     if (OCInit((char *) paddr, port, OC_SERVER) != OC_STACK_OK) {
720         OC_LOG(ERROR, TAG, "OCStack init error");
721         return 0;
722     }
723 #ifdef WITH_PRESENCE
724     if (OCStartPresence(0) != OC_STACK_OK) {
725         OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
726         return 0;
727     }
728 #endif
729
730     OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb);
731
732     /*
733      * Declare and create the example resource: Light
734      */
735     createLightResource(gResourceUri, &Light);
736
737     // Initialize observations data structure for the resource
738     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
739     {
740         interestedObservers[i].valid = false;
741     }
742
743     /*
744      * Create a thread for changing the representation of the Light
745      */
746     pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
747
748     // Break from loop with Ctrl-C
749     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
750     signal(SIGINT, handleSigInt);
751     while (!gQuitFlag) {
752         if (OCProcess() != OC_STACK_OK) {
753             OC_LOG(ERROR, TAG, "OCStack process error");
754             return 0;
755         }
756
757         sleep(2);
758     }
759
760     /*
761      * Cancel the Light thread and wait for it to terminate
762      */
763     pthread_cancel(threadId);
764     pthread_join(threadId, NULL);
765
766     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
767
768     if (OCStop() != OC_STACK_OK) {
769         OC_LOG(ERROR, TAG, "OCStack process error");
770     }
771
772     return 0;
773 }
774
775 int createLightResource (char *uri, LightResource *lightResource)
776 {
777     if (!uri)
778     {
779         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
780         return -1;
781     }
782
783     lightResource->state = false;
784     lightResource->power= 0;
785     OCStackResult res = OCCreateResource(&(lightResource->handle),
786             "core.light",
787             "oc.mi.def",
788             uri,
789             OCEntityHandlerCb,
790             OC_DISCOVERABLE|OC_OBSERVABLE);
791     OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
792
793     return 0;
794 }