e203bb56876b999f3307de239a8b98f281bf7139
[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     return ehResult;
526 }
527
528 OCEntityHandlerResult
529 OCNOPEntityHandlerCb (OCEntityHandlerFlag /*flag*/,
530                       OCEntityHandlerRequest * /*entityHandlerRequest*/,
531                       void* /*callbackParam*/)
532 {
533     // This is callback is associated with the 2 presence notification
534     // resources. They are non-operational.
535     return OC_EH_OK;
536 }
537
538 OCEntityHandlerResult
539 OCEntityHandlerCb (OCEntityHandlerFlag flag,
540         OCEntityHandlerRequest *entityHandlerRequest, void* /*callback*/)
541 {
542     OIC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
543
544     OCEntityHandlerResult ehResult = OC_EH_OK;
545     OCEntityHandlerResponse response = { 0, 0, OC_EH_ERROR, 0, 0, { },{ 0 }, false };
546
547     // Validate pointer
548     if (!entityHandlerRequest)
549     {
550         OIC_LOG (ERROR, TAG, "Invalid request pointer");
551         return OC_EH_ERROR;
552     }
553
554     // Initialize certain response fields
555     response.numSendVendorSpecificHeaderOptions = 0;
556     memset(response.sendVendorSpecificHeaderOptions,
557             0, sizeof response.sendVendorSpecificHeaderOptions);
558     memset(response.resourceUri, 0, sizeof response.resourceUri);
559     OCRepPayload* payload = nullptr;
560
561     if (flag & OC_REQUEST_FLAG)
562     {
563         OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
564
565         if (OC_REST_GET == entityHandlerRequest->method)
566         {
567             OIC_LOG (INFO, TAG, "Received OC_REST_GET from client");
568             ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
569         }
570         else if (OC_REST_PUT == entityHandlerRequest->method)
571         {
572             OIC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
573             ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
574         }
575         else if (OC_REST_POST == entityHandlerRequest->method)
576         {
577             OIC_LOG (INFO, TAG, "Received OC_REST_POST from client");
578             ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload);
579         }
580         else if (OC_REST_DELETE == entityHandlerRequest->method)
581         {
582             OIC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
583             ehResult = ProcessDeleteRequest (entityHandlerRequest);
584         }
585         else
586         {
587             OIC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
588                       entityHandlerRequest->method);
589             ehResult = OC_EH_ERROR;
590         }
591         // If the result isn't an error or forbidden, send response
592         if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
593         {
594             // Format the response.  Note this requires some info about the request
595             response.requestHandle = entityHandlerRequest->requestHandle;
596             response.resourceHandle = entityHandlerRequest->resource;
597             response.ehResult = ehResult;
598             response.payload = reinterpret_cast<OCPayload*>(payload);
599             // Indicate that response is NOT in a persistent buffer
600             response.persistentBufferFlag = 0;
601
602             // Handle vendor specific options
603             if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
604                     entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
605             {
606                 OIC_LOG (INFO, TAG, "Received vendor specific options");
607                 uint8_t i = 0;
608                 OCHeaderOption * rcvdOptions =
609                         entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
610                 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
611                 {
612                     if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
613                     {
614                         OIC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
615                                 ((OCHeaderOption)rcvdOptions[i]).optionID );
616
617                         OIC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
618                             MAX_HEADER_OPTION_DATA_LENGTH);
619                     }
620                 }
621
622                 OCHeaderOption* sendOptions = response.sendVendorSpecificHeaderOptions;
623                 size_t numOptions = response.numSendVendorSpecificHeaderOptions;
624                 // Check if the option header has already existed before adding it in.
625                 uint8_t optionData[MAX_HEADER_OPTION_DATA_LENGTH];
626                 size_t optionDataSize = sizeof(optionData);
627                 uint16_t actualDataSize = 0;
628                 OCGetHeaderOption(response.sendVendorSpecificHeaderOptions,
629                                   response.numSendVendorSpecificHeaderOptions,
630                                   2248,
631                                   optionData,
632                                   optionDataSize,
633                                   &actualDataSize);
634                 if (actualDataSize == 0)
635                 {
636                     uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
637                     uint16_t optionID2 = 2248;
638                     size_t optionDataSize2 = sizeof(option2);
639                     OCSetHeaderOption(sendOptions,
640                                       &numOptions,
641                                       optionID2,
642                                       option2,
643                                       optionDataSize2);
644                 }
645
646                 OCGetHeaderOption(response.sendVendorSpecificHeaderOptions,
647                                   response.numSendVendorSpecificHeaderOptions,
648                                   2600,
649                                   optionData,
650                                   optionDataSize,
651                                   &actualDataSize);
652                 if (actualDataSize == 0)
653                 {
654                     uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
655                     uint16_t optionID3 = 2600;
656                     size_t optionDataSize3 = sizeof(option3);
657                     OCSetHeaderOption(sendOptions,
658                                       &numOptions,
659                                       optionID3,
660                                       option3,
661                                       optionDataSize3);
662                 }
663                 response.numSendVendorSpecificHeaderOptions = 2;
664             }
665
666             // Send the response
667             if (OCDoResponse(&response) != OC_STACK_OK)
668             {
669                 OIC_LOG(ERROR, TAG, "Error sending response");
670                 ehResult = OC_EH_ERROR;
671             }
672         }
673     }
674     if (flag & OC_OBSERVE_FLAG)
675     {
676         OIC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
677
678         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
679         {
680             OIC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
681             ProcessObserveRegister (entityHandlerRequest);
682         }
683         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
684         {
685             OIC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
686             ProcessObserveDeregister (entityHandlerRequest);
687         }
688     }
689
690     OCPayloadDestroy(response.payload);
691     return ehResult;
692 }
693
694 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
695 void handleSigInt(int signum)
696 {
697     if (signum == SIGINT)
698     {
699         gQuitFlag = 1;
700     }
701 }
702
703 void *ChangeLightRepresentation (void *param)
704 {
705     (void)param;
706     OCStackResult result = OC_STACK_ERROR;
707
708     uint8_t j = 0;
709     OCObservationId obsNotify[(SAMPLE_MAX_NUM_OBSERVATIONS)/2];
710
711     while (!gQuitFlag)
712     {
713         sleep(3);
714         Light.power += 5;
715         if (gLightUnderObservation)
716         {
717             OIC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
718             if (gObserveNotifyType == 1)
719             {
720                 // Notify list of observers. Alternate observers on the list will be notified.
721                 j = 0;
722                 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
723                 {
724                     if (interestedObservers[i].valid == true)
725                     {
726                         obsNotify[j] = interestedObservers[i].observationId;
727                         j++;
728                     }
729                 }
730
731                 OCRepPayload* payload = getPayload(gResourceUri, Light.power, Light.state);
732                 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
733                         payload, OC_NA_QOS);
734                 OCRepPayloadDestroy(payload);
735             }
736             else if (gObserveNotifyType == 0)
737             {
738                 // Notifying all observers
739                 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
740                 if (OC_STACK_NO_OBSERVERS == result)
741                 {
742                     OIC_LOG (INFO, TAG,
743                             "=======> No more observers exist, stop sending observations");
744                     gLightUnderObservation = 0;
745                 }
746             }
747             else
748             {
749                 OIC_LOG (ERROR, TAG, "Incorrect notification type selected");
750             }
751         }
752     }
753     return NULL;
754 }
755
756 #ifdef WITH_PRESENCE
757 void *presenceNotificationGenerator(void *param)
758 {
759     uint8_t secondsBeforePresence = 10;
760     OIC_LOG_V(INFO, TAG, "Will send out presence in %u seconds", secondsBeforePresence);
761     sleep(secondsBeforePresence);
762     (void)param;
763     OCDoHandle presenceNotificationHandles[numPresenceResources];
764     OCStackResult res = OC_STACK_OK;
765
766     std::array<std::string, numPresenceResources> presenceNotificationResources { {
767         std::string("core.fan"),
768         std::string("core.led") } };
769     std::array<std::string, numPresenceResources> presenceNotificationUris { {
770         std::string("/a/fan"),
771         std::string("/a/led") } };
772
773     for(int i=0; i<numPresenceResources; i++)
774     {
775         if(res == OC_STACK_OK)
776         {
777             sleep(1);
778             res = OCCreateResource(&presenceNotificationHandles[i],
779                     presenceNotificationResources.at(i).c_str(),
780                     OC_RSRVD_INTERFACE_DEFAULT,
781                     presenceNotificationUris.at(i).c_str(),
782                     OCNOPEntityHandlerCb,
783                     NULL,
784                     OC_DISCOVERABLE|OC_OBSERVABLE);
785         }
786         if(res != OC_STACK_OK)
787         {
788             OIC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
789                     "%s with result %s.", presenceNotificationResources.at(i).c_str(),
790                     getResult(res));
791             break;
792         }
793         OIC_LOG_V(INFO, TAG, PCF("Created %s for presence notification"),
794                                 presenceNotificationUris[i].c_str());
795     }
796     sleep(5);
797     for(int i=0; i<numPresenceResources; i++)
798     {
799         if(res == OC_STACK_OK)
800         {
801             res = OCDeleteResource(presenceNotificationHandles[i]);
802         }
803         if(res != OC_STACK_OK)
804         {
805             OIC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
806                     "resource %s.", presenceNotificationResources.at(i).c_str());
807             break;
808         }
809         OIC_LOG_V(INFO, TAG, PCF("Deleted %s for presence notification"),
810                                 presenceNotificationUris[i].c_str());
811     }
812
813     OIC_LOG(INFO, TAG, "================ stopping presence");
814     OCStopPresence();
815
816     return NULL;
817 }
818 #endif
819
820 int createLightResource (char *uri, LightResource *lightResource)
821 {
822     if (!uri)
823     {
824         OIC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
825         return -1;
826     }
827
828     lightResource->state = false;
829     lightResource->power= 0;
830     OCStackResult res = OCCreateResource(&(lightResource->handle),
831             "core.light",
832             "oc.mi.def",
833             uri,
834             OCEntityHandlerCb,
835             NULL,
836             OC_DISCOVERABLE|OC_OBSERVABLE);
837     OIC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
838
839     return 0;
840 }
841
842 void DeletePlatformInfo()
843 {
844     free (platformInfo.platformID);
845     free (platformInfo.manufacturerName);
846     free (platformInfo.manufacturerUrl);
847     free (platformInfo.modelNumber);
848     free (platformInfo.dateOfManufacture);
849     free (platformInfo.platformVersion);
850     free (platformInfo.operatingSystemVersion);
851     free (platformInfo.hardwareVersion);
852     free (platformInfo.firmwareVersion);
853     free (platformInfo.supportUrl);
854     free (platformInfo.systemTime);
855 }
856
857 void DeleteDeviceInfo()
858 {
859     free (deviceInfo.deviceName);
860     free (deviceInfo.specVersion);
861     OCFreeOCStringLL (deviceInfo.dataModelVersions);
862 }
863
864 bool DuplicateString(char** targetString, const char* sourceString)
865 {
866     if(!sourceString)
867     {
868         return false;
869     }
870     else
871     {
872         *targetString = (char *) malloc(strlen(sourceString) + 1);
873
874         if(*targetString)
875         {
876             strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
877             return true;
878         }
879     }
880     return false;
881 }
882
883 OCStackResult SetPlatformInfo(const char* platformID, const char *manufacturerName,
884     const char *manufacturerUrl, const char *modelNumber, const char *dateOfManufacture,
885     const char *platformVersion, const char* operatingSystemVersion, const char* hardwareVersion,
886     const char *firmwareVersion, const char* supportUrl, const char* systemTime)
887 {
888
889     bool success = true;
890
891     if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_PLATFORM_NAME_LENGTH))
892     {
893         return OC_STACK_INVALID_PARAM;
894     }
895
896     if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_PLATFORM_URL_LENGTH))
897     {
898         return OC_STACK_INVALID_PARAM;
899     }
900
901     if(!DuplicateString(&platformInfo.platformID, platformID))
902     {
903         success = false;
904     }
905
906     if(!DuplicateString(&platformInfo.manufacturerName, manufacturerName))
907     {
908         success = false;
909     }
910
911     if(!DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl))
912     {
913         success = false;
914     }
915
916     if(!DuplicateString(&platformInfo.modelNumber, modelNumber))
917     {
918         success = false;
919     }
920
921     if(!DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture))
922     {
923         success = false;
924     }
925
926     if(!DuplicateString(&platformInfo.platformVersion, platformVersion))
927     {
928         success = false;
929     }
930
931     if(!DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion))
932     {
933         success = false;
934     }
935
936     if(!DuplicateString(&platformInfo.hardwareVersion, hardwareVersion))
937     {
938         success = false;
939     }
940
941     if(!DuplicateString(&platformInfo.firmwareVersion, firmwareVersion))
942     {
943         success = false;
944     }
945
946     if(!DuplicateString(&platformInfo.supportUrl, supportUrl))
947     {
948         success = false;
949     }
950
951     if(!DuplicateString(&platformInfo.systemTime, systemTime))
952     {
953         success = false;
954     }
955
956     if(success)
957     {
958         return OC_STACK_OK;
959     }
960
961     DeletePlatformInfo();
962     return OC_STACK_ERROR;
963 }
964
965 OCStackResult SetDeviceInfo(const char* deviceName, const char* specVersion, const char* dataModelVersions)
966 {
967     if(!DuplicateString(&deviceInfo.deviceName, deviceName))
968     {
969         return OC_STACK_ERROR;
970     }
971     if(!DuplicateString(&deviceInfo.specVersion, specVersion))
972     {
973         return OC_STACK_ERROR;
974     }
975     OCFreeOCStringLL(deviceInfo.dataModelVersions);
976     deviceInfo.dataModelVersions = OCCreateOCStringLL(dataModelVersions);
977     if (!deviceInfo.dataModelVersions)
978     {
979         return OC_STACK_ERROR;
980     }
981     return OC_STACK_OK;
982 }
983
984 static void PrintUsage()
985 {
986     OIC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
987     OIC_LOG(INFO, TAG, "-o 0 : Notify all observers");
988     OIC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
989 }
990
991 #ifdef RA_ADAPTER
992 static void jidbound(char *jid)
993 {
994     OIC_LOG_V(INFO, TAG, "\n\n    Bound JID: %s\n\n", jid);
995 }
996 #endif
997
998 int main(int argc, char* argv[])
999 {
1000
1001 #ifdef RA_ADAPTER
1002     char host[] = "localhost";
1003     char user[] = "test1";
1004     char pass[] = "intel123";
1005     char empstr[] = "";
1006     OCRAInfo_t rainfo = {};
1007
1008     rainfo.hostname = host;
1009     rainfo.port = 5222;
1010     rainfo.xmpp_domain = host;
1011     rainfo.username = user;
1012     rainfo.password = pass;
1013     rainfo.resource = empstr;
1014     rainfo.user_jid = empstr;
1015     rainfo.jidbound = jidbound;
1016 #endif
1017
1018     int opt = 0;
1019     while ((opt = getopt(argc, argv, "o:s:p:d:u:w:r:j:")) != -1)
1020     {
1021         switch(opt)
1022         {
1023             case 'o':
1024                 gObserveNotifyType = atoi(optarg);
1025                 break;
1026 #ifdef RA_ADAPTER
1027             case 's':
1028                 rainfo.hostname = optarg;
1029                 break;
1030             case 'p':
1031                 rainfo.port = atoi(optarg);
1032                 break;
1033             case 'd':
1034                 rainfo.xmpp_domain = optarg;
1035                 break;
1036             case 'u':
1037                 rainfo.username = optarg;
1038                 break;
1039             case 'w':
1040                 rainfo.password = optarg;
1041                 break;
1042             case 'j':
1043                 rainfo.user_jid = optarg;
1044                 break;
1045             case 'r':
1046                 rainfo.resource = optarg;
1047                 break;
1048 #endif
1049             default:
1050                 PrintUsage();
1051                 return -1;
1052         }
1053     }
1054
1055     if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
1056     {
1057         PrintUsage();
1058         return -1;
1059     }
1060
1061 #ifdef RA_ADAPTER
1062     OCSetRAInfo(&rainfo);
1063 #endif
1064
1065     OIC_LOG(DEBUG, TAG, "OCServer is starting...");
1066
1067     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
1068     {
1069         OIC_LOG(ERROR, TAG, "OCStack init error");
1070         return 0;
1071     }
1072 #ifdef WITH_PRESENCE
1073     if (OCStartPresence(0) != OC_STACK_OK)
1074     {
1075         OIC_LOG(ERROR, TAG, "OCStack presence/discovery error");
1076         return 0;
1077     }
1078 #endif
1079
1080     OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb, NULL);
1081
1082     OCStackResult registrationResult =
1083         SetPlatformInfo(platformID, manufacturerName, manufacturerLink, modelNumber,
1084             dateOfManufacture, platformVersion,  operatingSystemVersion,  hardwareVersion,
1085             firmwareVersion,  supportLink, systemTime);
1086
1087     if (registrationResult != OC_STACK_OK)
1088     {
1089         OIC_LOG(INFO, TAG, "Platform info setting failed locally!");
1090         exit (EXIT_FAILURE);
1091     }
1092
1093     registrationResult = OCSetPlatformInfo(platformInfo);
1094
1095     if (registrationResult != OC_STACK_OK)
1096     {
1097         OIC_LOG(INFO, TAG, "Platform Registration failed!");
1098         exit (EXIT_FAILURE);
1099     }
1100
1101     registrationResult = SetDeviceInfo(deviceName, specVersion, dataModelVersions);
1102
1103     if (registrationResult != OC_STACK_OK)
1104     {
1105         OIC_LOG(INFO, TAG, "Device info setting failed locally!");
1106         exit (EXIT_FAILURE);
1107     }
1108
1109     OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.d.tv");
1110
1111     registrationResult = OCSetDeviceInfo(deviceInfo);
1112
1113     if (registrationResult != OC_STACK_OK)
1114     {
1115         OIC_LOG(INFO, TAG, "Device Registration failed!");
1116         exit (EXIT_FAILURE);
1117     }
1118
1119     /*
1120      * Declare and create the example resource: Light
1121      */
1122     createLightResource(gResourceUri, &Light);
1123
1124     // Initialize observations data structure for the resource
1125     for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
1126     {
1127         interestedObservers[i].valid = false;
1128     }
1129
1130
1131     /*
1132      * Create a thread for generating changes that cause presence notifications
1133      * to be sent to clients
1134      */
1135
1136     #ifdef WITH_PRESENCE
1137     pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
1138     #endif
1139
1140     // Break from loop with Ctrl-C
1141     OIC_LOG(INFO, TAG, "Entering ocserver main loop...");
1142
1143     DeletePlatformInfo();
1144     DeleteDeviceInfo();
1145
1146     signal(SIGINT, handleSigInt);
1147
1148     while (!gQuitFlag)
1149     {
1150         if (OCProcess() != OC_STACK_OK)
1151         {
1152             OIC_LOG(ERROR, TAG, "OCStack process error");
1153             return 0;
1154         }
1155     }
1156
1157     if (observeThreadStarted)
1158     {
1159 #ifdef HAVE_PTHREAD_H
1160         pthread_cancel(threadId_observe);
1161         pthread_join(threadId_observe, NULL);
1162 #endif
1163     }
1164
1165 #ifdef HAVE_PTHREAD_H
1166     pthread_cancel(threadId_presence);
1167     pthread_join(threadId_presence, NULL);
1168 #endif
1169
1170     OIC_LOG(INFO, TAG, "Exiting ocserver main loop...");
1171
1172     if (OCStop() != OC_STACK_OK)
1173     {
1174         OIC_LOG(ERROR, TAG, "OCStack process error");
1175     }
1176
1177     return 0;
1178 }