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