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