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