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