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