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