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