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