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