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