Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / resource / examples / simpleserver.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 /// This sample provides steps to define an interface for a resource
23 /// (properties and methods) and host this resource on the server.
24 ///
25
26 #include <functional>
27
28 #include <pthread.h>
29 #include <mutex>
30 #include <condition_variable>
31
32 #include "OCPlatform.h"
33 #include "OCApi.h"
34
35 using namespace OC;
36 using namespace std;
37 namespace PH = std::placeholders;
38
39 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_server.dat";
40 int gObservation = 0;
41 void * ChangeLightRepresentation (void *param);
42 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest);
43
44 // Specifies where to notify all observers or list of observers
45 // false: notifies all observers
46 // true: notifies list of observers
47 bool isListOfObservers = false;
48
49 // Specifies secure or non-secure
50 // false: non-secure resource
51 // true: secure resource
52 bool isSecure = false;
53
54 /// Specifies whether Entity handler is going to do slow response or not
55 bool isSlowResponse = false;
56
57 // Forward declaring the entityHandler
58
59 /// This class represents a single resource named 'lightResource'. This resource has
60 /// two simple properties named 'state' and 'power'
61
62 class LightResource
63 {
64
65 public:
66     /// Access this property from a TB client
67     std::string m_name;
68     bool m_state;
69     int m_power;
70     std::string m_lightUri;
71     OCResourceHandle m_resourceHandle;
72     OCRepresentation m_lightRep;
73     ObservationIds m_interestedObservers;
74
75 public:
76     /// Constructor
77     LightResource()
78         :m_name("John's light"), m_state(false), m_power(0), m_lightUri("/a/light"),
79                 m_resourceHandle(nullptr) {
80         // Initialize representation
81         m_lightRep.setUri(m_lightUri);
82
83         m_lightRep.setValue("state", m_state);
84         m_lightRep.setValue("power", m_power);
85         m_lightRep.setValue("name", m_name);
86     }
87
88     /* Note that this does not need to be a member function: for classes you do not have
89     access to, you can accomplish this with a free function: */
90
91     /// This function internally calls registerResource API.
92     void createResource()
93     {
94         //URI of the resource
95         std::string resourceURI = m_lightUri;
96         //resource type name. In this case, it is light
97         std::string resourceTypeName = "core.light";
98         // resource interface.
99         std::string resourceInterface = DEFAULT_INTERFACE;
100
101         // OCResourceProperty is defined ocstack.h
102         uint8_t resourceProperty;
103         if(isSecure)
104         {
105             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
106         }
107         else
108         {
109             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
110         }
111         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
112
113         // This will internally create and register the resource.
114         OCStackResult result = OCPlatform::registerResource(
115                                     m_resourceHandle, resourceURI, resourceTypeName,
116                                     resourceInterface, cb, resourceProperty);
117
118         if (OC_STACK_OK != result)
119         {
120             cout << "Resource creation was unsuccessful\n";
121         }
122     }
123
124     OCStackResult createResource1()
125     {
126         // URI of the resource
127         std::string resourceURI = "/a/light1";
128         // resource type name. In this case, it is light
129         std::string resourceTypeName = "core.light";
130         // resource interface.
131         std::string resourceInterface = DEFAULT_INTERFACE;
132
133         // OCResourceProperty is defined ocstack.h
134         uint8_t resourceProperty;
135         if(isSecure)
136         {
137             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
138         }
139         else
140         {
141             resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
142         }
143         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
144
145         OCResourceHandle resHandle;
146
147         // This will internally create and register the resource.
148         OCStackResult result = OCPlatform::registerResource(
149                                     resHandle, resourceURI, resourceTypeName,
150                                     resourceInterface, cb, resourceProperty);
151
152         if (OC_STACK_OK != result)
153         {
154             cout << "Resource creation was unsuccessful\n";
155         }
156
157         return result;
158     }
159
160     OCResourceHandle getHandle()
161     {
162         return m_resourceHandle;
163     }
164
165     // Puts representation.
166     // Gets values from the representation and
167     // updates the internal state
168     void put(OCRepresentation& rep)
169     {
170         try {
171             if (rep.getValue("state", m_state))
172             {
173                 cout << "\t\t\t\t" << "state: " << m_state << endl;
174             }
175             else
176             {
177                 cout << "\t\t\t\t" << "state not found in the representation" << endl;
178             }
179
180             if (rep.getValue("power", m_power))
181             {
182                 cout << "\t\t\t\t" << "power: " << m_power << endl;
183             }
184             else
185             {
186                 cout << "\t\t\t\t" << "power not found in the representation" << endl;
187             }
188         }
189         catch (exception& e)
190         {
191             cout << e.what() << endl;
192         }
193
194     }
195
196     // Post representation.
197     // Post can create new resource or simply act like put.
198     // Gets values from the representation and
199     // updates the internal state
200     OCRepresentation post(OCRepresentation& rep)
201     {
202         static int first = 1;
203
204         // for the first time it tries to create a resource
205         if(first)
206         {
207             first = 0;
208
209             if(OC_STACK_OK == createResource1())
210             {
211                 OCRepresentation rep1;
212                 rep1.setValue("createduri", std::string("/a/light1"));
213
214                 return rep1;
215             }
216         }
217
218         // from second time onwards it just puts
219         put(rep);
220         return get();
221     }
222
223
224     // gets the updated representation.
225     // Updates the representation with latest internal state before
226     // sending out.
227     OCRepresentation get()
228     {
229         m_lightRep.setValue("state", m_state);
230         m_lightRep.setValue("power", m_power);
231
232         return m_lightRep;
233     }
234
235     void addType(const std::string& type) const
236     {
237         OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
238         if (OC_STACK_OK != result)
239         {
240             cout << "Binding TypeName to Resource was unsuccessful\n";
241         }
242     }
243
244     void addInterface(const std::string& interface) const
245     {
246         OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, interface);
247         if (OC_STACK_OK != result)
248         {
249             cout << "Binding TypeName to Resource was unsuccessful\n";
250         }
251     }
252
253 private:
254 // This is just a sample implementation of entity handler.
255 // Entity handler can be implemented in several ways by the manufacturer
256 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
257 {
258     cout << "\tIn Server CPP entity handler:\n";
259     OCEntityHandlerResult ehResult = OC_EH_ERROR;
260     if(request)
261     {
262         // Get the request type and request flag
263         std::string requestType = request->getRequestType();
264         int requestFlag = request->getRequestHandlerFlag();
265
266         if(requestFlag & RequestHandlerFlag::RequestFlag)
267         {
268             cout << "\t\trequestFlag : Request\n";
269             auto pResponse = std::make_shared<OC::OCResourceResponse>();
270             pResponse->setRequestHandle(request->getRequestHandle());
271             pResponse->setResourceHandle(request->getResourceHandle());
272
273             // Check for query params (if any)
274             QueryParamsMap queries = request->getQueryParameters();
275
276             if (!queries.empty())
277             {
278                 std::cout << "\nQuery processing upto entityHandler" << std::endl;
279             }
280             for (auto it : queries)
281             {
282                 std::cout << "Query key: " << it.first << " value : " << it.second
283                         << std:: endl;
284             }
285
286             // If the request type is GET
287             if(requestType == "GET")
288             {
289                 cout << "\t\t\trequestType : GET\n";
290                 if(isSlowResponse) // Slow response case
291                 {
292                     static int startedThread = 0;
293                     if(!startedThread)
294                     {
295                         std::thread t(handleSlowResponse, (void *)this, request);
296                         startedThread = 1;
297                         t.detach();
298                     }
299                     ehResult = OC_EH_SLOW;
300                 }
301                 else // normal response case.
302                 {
303                     pResponse->setErrorCode(200);
304                     pResponse->setResponseResult(OC_EH_OK);
305                     pResponse->setResourceRepresentation(get());
306                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
307                     {
308                         ehResult = OC_EH_OK;
309                     }
310                 }
311             }
312             else if(requestType == "PUT")
313             {
314                 cout << "\t\t\trequestType : PUT\n";
315                 OCRepresentation rep = request->getResourceRepresentation();
316
317                 // Do related operations related to PUT request
318                 // Update the lightResource
319                 put(rep);
320                 pResponse->setErrorCode(200);
321                 pResponse->setResponseResult(OC_EH_OK);
322                 pResponse->setResourceRepresentation(get());
323                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
324                 {
325                     ehResult = OC_EH_OK;
326                 }
327             }
328             else if(requestType == "POST")
329             {
330                 cout << "\t\t\trequestType : POST\n";
331
332                 OCRepresentation rep = request->getResourceRepresentation();
333
334                 // Do related operations related to POST request
335                 OCRepresentation rep_post = post(rep);
336                 pResponse->setResourceRepresentation(rep_post);
337                 pResponse->setErrorCode(200);
338                 if(rep_post.hasAttribute("createduri"))
339                 {
340                     pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
341                     pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
342                 }
343                 else
344                 {
345                     pResponse->setResponseResult(OC_EH_OK);
346                 }
347
348                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
349                 {
350                     ehResult = OC_EH_OK;
351                 }
352             }
353             else if(requestType == "DELETE")
354             {
355                 cout << "Delete request received" << endl;
356             }
357         }
358
359         if(requestFlag & RequestHandlerFlag::ObserverFlag)
360         {
361             ObservationInfo observationInfo = request->getObservationInfo();
362             if(ObserveAction::ObserveRegister == observationInfo.action)
363             {
364                 m_interestedObservers.push_back(observationInfo.obsId);
365             }
366             else if(ObserveAction::ObserveUnregister == observationInfo.action)
367             {
368                 m_interestedObservers.erase(std::remove(
369                                                             m_interestedObservers.begin(),
370                                                             m_interestedObservers.end(),
371                                                             observationInfo.obsId),
372                                                             m_interestedObservers.end());
373             }
374
375             pthread_t threadId;
376
377             cout << "\t\trequestFlag : Observer\n";
378             gObservation = 1;
379             static int startedThread = 0;
380
381             // Observation happens on a different thread in ChangeLightRepresentation function.
382             // If we have not created the thread already, we will create one here.
383             if(!startedThread)
384             {
385                 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)this);
386                 startedThread = 1;
387             }
388             ehResult = OC_EH_OK;
389         }
390     }
391     else
392     {
393         std::cout << "Request invalid" << std::endl;
394     }
395
396     return ehResult;
397 }
398
399 };
400
401 // ChangeLightRepresentaion is an observation function,
402 // which notifies any changes to the resource to stack
403 // via notifyObservers
404 void * ChangeLightRepresentation (void *param)
405 {
406     LightResource* lightPtr = (LightResource*) param;
407
408     // This function continuously monitors for the changes
409     while (1)
410     {
411         sleep (3);
412
413         if (gObservation)
414         {
415             // If under observation if there are any changes to the light resource
416             // we call notifyObservors
417             //
418             // For demostration we are changing the power value and notifying.
419             lightPtr->m_power += 10;
420
421             cout << "\nPower updated to : " << lightPtr->m_power << endl;
422             cout << "Notifying observers with resource handle: " << lightPtr->getHandle() << endl;
423
424             OCStackResult result = OC_STACK_OK;
425
426             if(isListOfObservers)
427             {
428                 std::shared_ptr<OCResourceResponse> resourceResponse =
429                             {std::make_shared<OCResourceResponse>()};
430
431                 resourceResponse->setErrorCode(200);
432                 resourceResponse->setResourceRepresentation(lightPtr->get(), DEFAULT_INTERFACE);
433
434                 result = OCPlatform::notifyListOfObservers(  lightPtr->getHandle(),
435                                                              lightPtr->m_interestedObservers,
436                                                              resourceResponse);
437             }
438             else
439             {
440                 result = OCPlatform::notifyAllObservers(lightPtr->getHandle());
441             }
442
443             if(OC_STACK_NO_OBSERVERS == result)
444             {
445                 cout << "No More observers, stopping notifications" << endl;
446                 gObservation = 0;
447             }
448         }
449     }
450
451     return NULL;
452 }
453
454 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
455 {
456     // This function handles slow response case
457     LightResource* lightPtr = (LightResource*) param;
458     // Induce a case for slow response by using sleep
459     std::cout << "SLOW response" << std::endl;
460     sleep (10);
461
462     auto pResponse = std::make_shared<OC::OCResourceResponse>();
463     pResponse->setRequestHandle(pRequest->getRequestHandle());
464     pResponse->setResourceHandle(pRequest->getResourceHandle());
465     pResponse->setResourceRepresentation(lightPtr->get());
466     pResponse->setErrorCode(200);
467     pResponse->setResponseResult(OC_EH_OK);
468
469     // Set the slow response flag back to false
470     isSlowResponse = false;
471     OCPlatform::sendResponse(pResponse);
472     return NULL;
473 }
474
475 void PrintUsage()
476 {
477     std::cout << std::endl;
478     std::cout << "Usage : simpleserver <value>\n";
479     std::cout << "    Default - Non-secure resource and notify all observers\n";
480     std::cout << "    1 - Non-secure resource and notify list of observers\n\n";
481     std::cout << "    2 - Secure resource and notify all observers\n";
482     std::cout << "    3 - Secure resource and notify list of observers\n\n";
483     std::cout << "    4 - Non-secure resource, GET slow response, notify all observers\n";
484 }
485
486 static FILE* client_open(const char* /*path*/, const char *mode)
487 {
488     return fopen(SVR_DB_FILE_NAME, mode);
489 }
490
491 int main(int argc, char* argv[])
492 {
493     PrintUsage();
494     OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
495
496     if (argc == 1)
497     {
498         isListOfObservers = false;
499         isSecure = false;
500     }
501     else if (argc == 2)
502     {
503         int value = atoi(argv[1]);
504         switch (value)
505         {
506             case 1:
507                 isListOfObservers = true;
508                 isSecure = false;
509                 break;
510             case 2:
511                 isListOfObservers = false;
512                 isSecure = true;
513                 break;
514             case 3:
515                 isListOfObservers = true;
516                 isSecure = true;
517                 break;
518             case 4:
519                 isSlowResponse = true;
520                 break;
521             default:
522                 break;
523        }
524      }
525     else
526     {
527         return -1;
528     }
529
530     // Create PlatformConfig object
531     PlatformConfig cfg {
532         OC::ServiceType::InProc,
533         OC::ModeType::Server,
534         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
535         0,         // Uses randomly available port
536         OC::QualityOfService::LowQos,
537         &ps
538     };
539
540     OCPlatform::Configure(cfg);
541     try
542     {
543         // Create the instance of the resource class
544         // (in this case instance of class 'LightResource').
545         LightResource myLight;
546
547         // Invoke createResource function of class light.
548         myLight.createResource();
549         std::cout << "Created resource." << std::endl;
550
551         myLight.addType(std::string("core.brightlight"));
552         myLight.addInterface(std::string(LINK_INTERFACE));
553         std::cout << "Added Interface and Type" << std::endl;
554
555
556         // A condition variable will free the mutex it is given, then do a non-
557         // intensive block until 'notify' is called on it.  In this case, since we
558         // don't ever call cv.notify, this should be a non-processor intensive version
559         // of while(true);
560         std::mutex blocker;
561         std::condition_variable cv;
562         std::unique_lock<std::mutex> lock(blocker);
563         std::cout <<"Waiting" << std::endl;
564         cv.wait(lock, []{return false;});
565     }
566     catch(OCException &e)
567     {
568         std::cout << "OCException in main : " << e.what() << endl;
569     }
570
571     // No explicit call to stop the platform.
572     // When OCPlatform::destructor is invoked, internally we do platform cleanup
573
574     return 0;
575 }