replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / examples / lightserver.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 // Copyright 2014 Samsung Electronics All Rights Reserved.
5 //
6 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 //      http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // Unless required by applicable law or agreed to in writing, software
15 // distributed under the License is distributed on an "AS IS" BASIS,
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 // See the License for the specific language governing permissions and
18 // limitations under the License.
19 //
20 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21
22 ///
23 /// This sample provides steps to define an interface for a resource
24 /// (properties and methods) and host this resource on the server.
25 ///
26 #include "iotivity_config.h"
27
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <functional>
32
33 #include <pthread.h>
34 #include <mutex>
35 #include <condition_variable>
36
37 #include "OCPlatform.h"
38 #include "OCApi.h"
39 #include "ocpayload.h"
40
41 using namespace OC;
42 using namespace std;
43 namespace PH = std::placeholders;
44
45 int gObservation = 0;
46 void * ChangeLightRepresentation (void *param);
47 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest);
48
49 // Set of strings for each of platform Info fields
50 std::string  platformId = "0A3E0D6F-DBF5-404E-8719-D6880042463A";
51 std::string  manufacturerName = "OCF";
52 std::string  manufacturerLink = "https://www.iotivity.org";
53 std::string  modelNumber = "myModelNumber";
54 std::string  dateOfManufacture = "2016-01-15";
55 std::string  platformVersion = "myPlatformVersion";
56 std::string  operatingSystemVersion = "myOS";
57 std::string  hardwareVersion = "myHardwareVersion";
58 std::string  firmwareVersion = "1.0";
59 std::string  supportLink = "https://www.iotivity.org";
60 std::string  systemTime = "2016-01-15T11.01";
61
62 // Set of strings for each of device info fields
63 std::string  deviceName = "IoTivity Light Server";
64 std::string  specVersion = "core.1.1.0";
65 std::string  dataModelVersions = "res.1.1.0";
66
67 // OCPlatformInfo Contains all the platform info to be stored
68 OCPlatformInfo platformInfo;
69
70 // OCDeviceInfo Contains all the device info to be stored
71 OCDeviceInfo deviceInfo;
72
73 // Specifies secure or non-secure
74 // false: non-secure resource
75 // true: secure resource
76 bool isSecure = false;
77
78 /// Specifies whether Entity handler is going to do slow response or not
79 bool isSlowResponse = false;
80
81 // Forward declaring the entityHandler
82
83 /// This class represents a single resource named 'lightResource'. This resource has
84 /// one simple attribute, power
85
86 class LightResource
87 {
88
89 public:
90     /// Access this property from a TB client
91     std::string m_power;
92     std::string m_lightUri;
93     OCResourceHandle m_resourceHandle;
94     OCRepresentation m_lightRep;
95
96 public:
97     /// Constructor
98     LightResource()
99         :m_power(""), m_lightUri("/a/light") {
100         // Initialize representation
101         m_lightRep.setUri(m_lightUri);
102
103         m_lightRep.setValue("power", m_power);
104     }
105
106     /* Note that this does not need to be a member function: for classes you do not have
107     access to, you can accomplish this with a free function: */
108
109     /// This function internally calls registerResource API.
110     void createResource()
111     {
112         std::string resourceURI = m_lightUri; //URI of the resource
113         std::string resourceTypeName = "core.light"; //resource type name. In this case, it is light
114         std::string resourceInterface = DEFAULT_INTERFACE; // resource interface.
115
116         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
117
118         // This will internally create and register the resource.
119         OCStackResult result = OCPlatform::registerResource(
120                                     m_resourceHandle, resourceURI, resourceTypeName,
121                                     resourceInterface, cb, OC_DISCOVERABLE | OC_OBSERVABLE);
122
123         if (OC_STACK_OK != result)
124         {
125             cout << "Resource creation was unsuccessful\n";
126         }
127     }
128
129     OCResourceHandle getHandle()
130     {
131         return m_resourceHandle;
132     }
133
134     // Puts representation.
135     // Gets values from the representation and
136     // updates the internal state
137     void put(OCRepresentation& rep)
138     {
139         try {
140             if (rep.getValue("power", m_power))
141             {
142                 cout << "\t\t\t\t" << "power: " << m_power << endl;
143             }
144             else
145             {
146                 cout << "\t\t\t\t" << "power not found in the representation" << endl;
147             }
148         }
149         catch (exception& e)
150         {
151             cout << e.what() << endl;
152         }
153
154     }
155
156     // Post representation.
157     // Post can create new resource or simply act like put.
158     // Gets values from the representation and
159     // updates the internal state
160     OCRepresentation post(OCRepresentation& rep)
161     {
162         put(rep);
163         return get();
164     }
165
166
167     // gets the updated representation.
168     // Updates the representation with latest internal state before
169     // sending out.
170     OCRepresentation get()
171     {
172         m_lightRep.setValue("power", m_power);
173
174         return m_lightRep;
175     }
176
177     void addType(const std::string& type) const
178     {
179         OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
180         if (OC_STACK_OK != result)
181         {
182             cout << "Binding TypeName to Resource was unsuccessful\n";
183         }
184     }
185
186     void addInterface(const std::string& interface) const
187     {
188         OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, interface);
189         if (OC_STACK_OK != result)
190         {
191             cout << "Binding TypeName to Resource was unsuccessful\n";
192         }
193     }
194
195 private:
196 // This is just a sample implementation of entity handler.
197 // Entity handler can be implemented in several ways by the manufacturer
198 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
199 {
200     cout << "\tIn Server CPP entity handler:\n";
201     OCEntityHandlerResult ehResult = OC_EH_ERROR;
202     if(request)
203     {
204         // Get the request type and request flag
205         std::string requestType = request->getRequestType();
206         int requestFlag = request->getRequestHandlerFlag();
207
208         if(requestFlag & RequestHandlerFlag::RequestFlag)
209         {
210             cout << "\t\trequestFlag : Request\n";
211             auto pResponse = std::make_shared<OC::OCResourceResponse>();
212             pResponse->setRequestHandle(request->getRequestHandle());
213             pResponse->setResourceHandle(request->getResourceHandle());
214
215             // If the request type is GET
216             if(requestType == "GET")
217             {
218                 cout << "\t\t\trequestType : GET\n";
219                 if(isSlowResponse) // Slow response case
220                 {
221                     static int startedThread = 0;
222                     if(!startedThread)
223                     {
224                         std::thread t(handleSlowResponse, (void *)this, request);
225                         startedThread = 1;
226                         t.detach();
227                     }
228                     ehResult = OC_EH_SLOW;
229                 }
230                 else // normal response case.
231                 {
232                     pResponse->setErrorCode(200);
233                     pResponse->setResponseResult(OC_EH_OK);
234                     pResponse->setResourceRepresentation(get());
235                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
236                     {
237                         ehResult = OC_EH_OK;
238                     }
239                 }
240             }
241             else if(requestType == "PUT")
242             {
243                 cout << "\t\t\trequestType : PUT\n";
244                 OCRepresentation rep = request->getResourceRepresentation();
245
246                 // Do related operations related to PUT request
247                 // Update the lightResource
248                 put(rep);
249                 pResponse->setErrorCode(200);
250                 pResponse->setResponseResult(OC_EH_OK);
251                 pResponse->setResourceRepresentation(get());
252                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
253                 {
254                     ehResult = OC_EH_OK;
255                 }
256             }
257             else if(requestType == "POST")
258             {
259                 cout << "\t\t\trequestType : POST\n";
260
261                 OCRepresentation rep = request->getResourceRepresentation();
262
263                 // Do related operations related to POST request
264                 OCRepresentation rep_post = post(rep);
265                 pResponse->setResourceRepresentation(rep_post);
266                 pResponse->setErrorCode(200);
267                 if(rep_post.hasAttribute("createduri"))
268                 {
269                     pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
270                     pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
271                 }
272
273                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
274                 {
275                     ehResult = OC_EH_OK;
276                 }
277             }
278             else if(requestType == "DELETE")
279             {
280                 // DELETE request operations
281             }
282         }
283     }
284     else
285     {
286         std::cout << "Request invalid" << std::endl;
287     }
288
289     return ehResult;
290 }
291 };
292
293 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
294 {
295     // This function handles slow response case
296     LightResource* lightPtr = (LightResource*) param;
297     // Induce a case for slow response by using sleep
298     std::cout << "SLOW response" << std::endl;
299     sleep (10);
300
301     auto pResponse = std::make_shared<OC::OCResourceResponse>();
302     pResponse->setRequestHandle(pRequest->getRequestHandle());
303     pResponse->setResourceHandle(pRequest->getResourceHandle());
304     pResponse->setResourceRepresentation(lightPtr->get());
305     pResponse->setErrorCode(200);
306     pResponse->setResponseResult(OC_EH_OK);
307
308     // Set the slow response flag back to false
309     isSlowResponse = false;
310     OCPlatform::sendResponse(pResponse);
311     return NULL;
312 }
313
314 void DeletePlatformInfo()
315 {
316     delete[] platformInfo.platformID;
317     delete[] platformInfo.manufacturerName;
318     delete[] platformInfo.manufacturerUrl;
319     delete[] platformInfo.modelNumber;
320     delete[] platformInfo.dateOfManufacture;
321     delete[] platformInfo.platformVersion;
322     delete[] platformInfo.operatingSystemVersion;
323     delete[] platformInfo.hardwareVersion;
324     delete[] platformInfo.firmwareVersion;
325     delete[] platformInfo.supportUrl;
326     delete[] platformInfo.systemTime;
327 }
328
329 void DeleteDeviceInfo()
330 {
331     delete[] deviceInfo.deviceName;
332     delete[] deviceInfo.specVersion;
333     OCFreeOCStringLL(deviceInfo.dataModelVersions);
334 }
335
336 void DuplicateString(char ** targetString, std::string sourceString)
337 {
338     *targetString = new char[sourceString.length() + 1];
339     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
340 }
341
342 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
343         std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
344         std::string platformVersion, std::string operatingSystemVersion,
345         std::string hardwareVersion, std::string firmwareVersion, std::string supportUrl,
346         std::string systemTime)
347 {
348     DuplicateString(&platformInfo.platformID, platformID);
349     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
350     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
351     DuplicateString(&platformInfo.modelNumber, modelNumber);
352     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
353     DuplicateString(&platformInfo.platformVersion, platformVersion);
354     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
355     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
356     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
357     DuplicateString(&platformInfo.supportUrl, supportUrl);
358     DuplicateString(&platformInfo.systemTime, systemTime);
359
360     return OC_STACK_OK;
361 }
362
363 OCStackResult SetDeviceInfo(std::string deviceName, std::string specVersion, std::string dataModelVersions)
364 {
365     DuplicateString(&deviceInfo.deviceName, deviceName);
366
367     if (!specVersion.empty())
368     {
369         DuplicateString(&deviceInfo.specVersion, specVersion);
370     }
371
372     if (!dataModelVersions.empty())
373     {
374         OCResourcePayloadAddStringLL(&deviceInfo.dataModelVersions, dataModelVersions.c_str());
375     }
376
377     return OC_STACK_OK;
378 }
379
380 int main(int /*argc*/, char** /*argv[]*/)
381 {
382     // Create PlatformConfig object
383     PlatformConfig cfg {
384         OC::ServiceType::InProc,
385         OC::ModeType::Server,
386         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
387         0,         // Uses randomly available port
388         OC::QualityOfService::LowQos
389     };
390
391     OCPlatform::Configure(cfg);
392     std::cout << "Starting server & setting platform info\n";
393
394     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
395             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
396             hardwareVersion, firmwareVersion, supportLink, systemTime);
397
398     result = OCPlatform::registerPlatformInfo(platformInfo);
399
400     if (result != OC_STACK_OK)
401     {
402         std::cout << "Platform Registration failed\n";
403         return -1;
404     }
405
406     result = SetDeviceInfo(deviceName, specVersion, dataModelVersions);
407     OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.wk.d");
408
409     result = OCPlatform::registerDeviceInfo(deviceInfo);
410
411     if (result != OC_STACK_OK)
412     {
413         std::cout << "Device Registration failed\n";
414         return -1;
415     }
416
417     try
418     {
419         // Create the instance of the resource class
420         // (in this case instance of class 'LightResource').
421         LightResource myLight;
422
423         // Invoke createResource function of class light.
424         myLight.createResource();
425
426         myLight.addType(std::string("core.brightlight"));
427         myLight.addInterface(std::string(LINK_INTERFACE));
428
429         DeletePlatformInfo();
430         DeleteDeviceInfo();
431
432         // A condition variable will free the mutex it is given, then do a non-
433         // intensive block until 'notify' is called on it.  In this case, since we
434         // don't ever call cv.notify, this should be a non-processor intensive version
435         // of while(true);
436         std::mutex blocker;
437         std::condition_variable cv;
438         std::unique_lock<std::mutex> lock(blocker);
439         cv.wait(lock);
440     }
441     catch(OCException& e)
442     {
443        oclog() << "Exception in main: "<< e.what();
444     }
445
446     // No explicit call to stop the platform.
447     // When OCPlatform::destructor is invoked, internally we do platform cleanup
448
449     return 0;
450 }
451