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