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