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