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