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