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