[IOT-1538] Add support for Protocol-Independent ID
[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::vector<std::string> dataModelVersions = {"res.1.1.0"};
66 std::string  protocolIndependentID = "b0ed9259-ec95-4ac6-8f62-241d0da02683";
67
68 // OCPlatformInfo Contains all the platform info to be stored
69 OCPlatformInfo platformInfo;
70
71 // Specifies secure or non-secure
72 // false: non-secure resource
73 // true: secure resource
74 bool isSecure = false;
75
76 /// Specifies whether Entity handler is going to do slow response or not
77 bool isSlowResponse = false;
78
79 // Forward declaring the entityHandler
80
81 /// This class represents a single resource named 'lightResource'. This resource has
82 /// one simple attribute, power
83
84 class LightResource
85 {
86
87 public:
88     /// Access this property from a TB client
89     std::string m_power;
90     std::string m_lightUri;
91     OCResourceHandle m_resourceHandle;
92     OCRepresentation m_lightRep;
93
94 public:
95     /// Constructor
96     LightResource()
97         :m_power(""), m_lightUri("/a/light") {
98         // Initialize representation
99         m_lightRep.setUri(m_lightUri);
100
101         m_lightRep.setValue("power", m_power);
102     }
103
104     /* Note that this does not need to be a member function: for classes you do not have
105     access to, you can accomplish this with a free function: */
106
107     /// This function internally calls registerResource API.
108     void createResource()
109     {
110         std::string resourceURI = m_lightUri; //URI of the resource
111         std::string resourceTypeName = "core.light"; //resource type name. In this case, it is light
112         std::string resourceInterface = DEFAULT_INTERFACE; // resource interface.
113
114         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
115
116         // This will internally create and register the resource.
117         OCStackResult result = OCPlatform::registerResource(
118                                     m_resourceHandle, resourceURI, resourceTypeName,
119                                     resourceInterface, cb, OC_DISCOVERABLE | OC_OBSERVABLE);
120
121         if (OC_STACK_OK != result)
122         {
123             cout << "Resource creation was unsuccessful\n";
124         }
125     }
126
127     OCResourceHandle getHandle()
128     {
129         return m_resourceHandle;
130     }
131
132     // Puts representation.
133     // Gets values from the representation and
134     // updates the internal state
135     void put(OCRepresentation& rep)
136     {
137         try {
138             if (rep.getValue("power", m_power))
139             {
140                 cout << "\t\t\t\t" << "power: " << m_power << endl;
141             }
142             else
143             {
144                 cout << "\t\t\t\t" << "power not found in the representation" << endl;
145             }
146         }
147         catch (exception& e)
148         {
149             cout << e.what() << endl;
150         }
151
152     }
153
154     // Post representation.
155     // Post can create new resource or simply act like put.
156     // Gets values from the representation and
157     // updates the internal state
158     OCRepresentation post(OCRepresentation& rep)
159     {
160         put(rep);
161         return get();
162     }
163
164
165     // gets the updated representation.
166     // Updates the representation with latest internal state before
167     // sending out.
168     OCRepresentation get()
169     {
170         m_lightRep.setValue("power", m_power);
171
172         return m_lightRep;
173     }
174
175     void addType(const std::string& type) const
176     {
177         OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
178         if (OC_STACK_OK != result)
179         {
180             cout << "Binding TypeName to Resource was unsuccessful\n";
181         }
182     }
183
184     void addInterface(const std::string& interface) const
185     {
186         OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, interface);
187         if (OC_STACK_OK != result)
188         {
189             cout << "Binding TypeName to Resource was unsuccessful\n";
190         }
191     }
192
193 private:
194 // This is just a sample implementation of entity handler.
195 // Entity handler can be implemented in several ways by the manufacturer
196 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
197 {
198     cout << "\tIn Server CPP entity handler:\n";
199     OCEntityHandlerResult ehResult = OC_EH_ERROR;
200     if(request)
201     {
202         // Get the request type and request flag
203         std::string requestType = request->getRequestType();
204         int requestFlag = request->getRequestHandlerFlag();
205
206         if(requestFlag & RequestHandlerFlag::RequestFlag)
207         {
208             cout << "\t\trequestFlag : Request\n";
209             auto pResponse = std::make_shared<OC::OCResourceResponse>();
210             pResponse->setRequestHandle(request->getRequestHandle());
211             pResponse->setResourceHandle(request->getResourceHandle());
212
213             // If the request type is GET
214             if(requestType == "GET")
215             {
216                 cout << "\t\t\trequestType : GET\n";
217                 if(isSlowResponse) // Slow response case
218                 {
219                     static int startedThread = 0;
220                     if(!startedThread)
221                     {
222                         std::thread t(handleSlowResponse, (void *)this, request);
223                         startedThread = 1;
224                         t.detach();
225                     }
226                     ehResult = OC_EH_SLOW;
227                 }
228                 else // normal response case.
229                 {
230
231                     pResponse->setResponseResult(OC_EH_OK);
232                     pResponse->setResourceRepresentation(get());
233                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
234                     {
235                         ehResult = OC_EH_OK;
236                     }
237                 }
238             }
239             else if(requestType == "PUT")
240             {
241                 cout << "\t\t\trequestType : PUT\n";
242                 OCRepresentation rep = request->getResourceRepresentation();
243
244                 // Do related operations related to PUT request
245                 // Update the lightResource
246                 put(rep);
247
248                 pResponse->setResponseResult(OC_EH_OK);
249                 pResponse->setResourceRepresentation(get());
250                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
251                 {
252                     ehResult = OC_EH_OK;
253                 }
254             }
255             else if(requestType == "POST")
256             {
257                 cout << "\t\t\trequestType : POST\n";
258
259                 OCRepresentation rep = request->getResourceRepresentation();
260
261                 // Do related operations related to POST request
262                 OCRepresentation rep_post = post(rep);
263                 pResponse->setResourceRepresentation(rep_post);
264
265                 if(rep_post.hasAttribute("createduri"))
266                 {
267                     pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
268                     pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
269                 }
270
271                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
272                 {
273                     ehResult = OC_EH_OK;
274                 }
275             }
276             else if(requestType == "DELETE")
277             {
278                 // DELETE request operations
279             }
280         }
281     }
282     else
283     {
284         std::cout << "Request invalid" << std::endl;
285     }
286
287     return ehResult;
288 }
289 };
290
291 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
292 {
293     // This function handles slow response case
294     LightResource* lightPtr = (LightResource*) param;
295     // Induce a case for slow response by using sleep
296     std::cout << "SLOW response" << std::endl;
297     sleep (10);
298
299     auto pResponse = std::make_shared<OC::OCResourceResponse>();
300     pResponse->setRequestHandle(pRequest->getRequestHandle());
301     pResponse->setResourceHandle(pRequest->getResourceHandle());
302     pResponse->setResourceRepresentation(lightPtr->get());
303
304     pResponse->setResponseResult(OC_EH_OK);
305
306     // Set the slow response flag back to false
307     isSlowResponse = false;
308     OCPlatform::sendResponse(pResponse);
309     return NULL;
310 }
311
312 void DeletePlatformInfo()
313 {
314     delete[] platformInfo.platformID;
315     delete[] platformInfo.manufacturerName;
316     delete[] platformInfo.manufacturerUrl;
317     delete[] platformInfo.modelNumber;
318     delete[] platformInfo.dateOfManufacture;
319     delete[] platformInfo.platformVersion;
320     delete[] platformInfo.operatingSystemVersion;
321     delete[] platformInfo.hardwareVersion;
322     delete[] platformInfo.firmwareVersion;
323     delete[] platformInfo.supportUrl;
324     delete[] platformInfo.systemTime;
325 }
326
327 void DuplicateString(char ** targetString, std::string sourceString)
328 {
329     *targetString = new char[sourceString.length() + 1];
330     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
331 }
332
333 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
334         std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
335         std::string platformVersion, std::string operatingSystemVersion,
336         std::string hardwareVersion, std::string firmwareVersion, std::string supportUrl,
337         std::string systemTime)
338 {
339     DuplicateString(&platformInfo.platformID, platformID);
340     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
341     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
342     DuplicateString(&platformInfo.modelNumber, modelNumber);
343     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
344     DuplicateString(&platformInfo.platformVersion, platformVersion);
345     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
346     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
347     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
348     DuplicateString(&platformInfo.supportUrl, supportUrl);
349     DuplicateString(&platformInfo.systemTime, systemTime);
350
351     return OC_STACK_OK;
352 }
353
354 OCStackResult SetDeviceInfo()
355 {
356     OCStackResult result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME,
357                                                         deviceName);
358     if (result != OC_STACK_OK)
359     {
360         cout << "Failed to set device name" << endl;
361         return result;
362     }
363
364     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION,
365                                           dataModelVersions);
366     if (result != OC_STACK_OK)
367     {
368         cout << "Failed to set data model versions" << endl;
369         return result;
370     }
371
372     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, specVersion);
373     if (result != OC_STACK_OK)
374     {
375         cout << "Failed to set spec version" << endl;
376         return result;
377     }
378
379     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID,
380                                           protocolIndependentID);
381     if (result != OC_STACK_OK)
382     {
383         cout << "Failed to set piid" << endl;
384         return result;
385     }
386
387     return OC_STACK_OK;
388 }
389
390 int main(int /*argc*/, char** /*argv[]*/)
391 {
392     // Create PlatformConfig object
393     PlatformConfig cfg {
394         OC::ServiceType::InProc,
395         OC::ModeType::Server,
396         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
397         0,         // Uses randomly available port
398         OC::QualityOfService::LowQos
399     };
400
401     OCPlatform::Configure(cfg);
402     std::cout << "Starting server & setting platform info\n";
403
404     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
405             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
406             hardwareVersion, firmwareVersion, supportLink, systemTime);
407
408     result = OCPlatform::registerPlatformInfo(platformInfo);
409
410     if (result != OC_STACK_OK)
411     {
412         std::cout << "Platform Registration failed\n";
413         return -1;
414     }
415
416     result = SetDeviceInfo();
417
418     if (result != OC_STACK_OK)
419     {
420         std::cout << "Device Registration failed\n";
421         return -1;
422     }
423
424     try
425     {
426         // Create the instance of the resource class
427         // (in this case instance of class 'LightResource').
428         LightResource myLight;
429
430         // Invoke createResource function of class light.
431         myLight.createResource();
432
433         myLight.addType(std::string("core.brightlight"));
434         myLight.addInterface(std::string(LINK_INTERFACE));
435
436         DeletePlatformInfo();
437
438         // A condition variable will free the mutex it is given, then do a non-
439         // intensive block until 'notify' is called on it.  In this case, since we
440         // don't ever call cv.notify, this should be a non-processor intensive version
441         // of while(true);
442         std::mutex blocker;
443         std::condition_variable cv;
444         std::unique_lock<std::mutex> lock(blocker);
445         cv.wait(lock);
446     }
447     catch(OCException& e)
448     {
449        oclog() << "Exception in main: "<< e.what();
450     }
451
452     // No explicit call to stop the platform.
453     // When OCPlatform::destructor is invoked, internally we do platform cleanup
454
455     return 0;
456 }
457