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