Deprecate OCSetDeviceInfo and registerDeviceInfo
[platform/upstream/iotivity.git] / resource / examples / fridgeserver.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 /// The purpose of this server is to simulate a refrigerator that contains a device resource for
22 /// its description, a light resource for the internal light, and 2 door resources for the purpose
23 /// of representing the doors attached to this fridge.  This is used by the fridgeclient to
24 /// demonstrate using std::bind to attach to instances of a class as well as using
25 /// constructResourceObject
26
27 #include <chrono>
28 #include <iostream>
29 #include <thread>
30 #include <stdexcept>
31
32 #include "OCPlatform.h"
33 #include "OCApi.h"
34 #include "ocpayload.h"
35
36 using namespace OC;
37 namespace PH = std::placeholders;
38
39 // Option ID for API version and client token
40 const uint16_t API_VERSION = 2048;
41 const uint16_t TOKEN = 3000;
42
43 // Setting API version and token (shared out of band with client)
44 // This assumes the fact that this server responds
45 // only with a server with below version and token
46 const std::string FRIDGE_CLIENT_API_VERSION = "v.1.0";
47 const std::string FRIDGE_CLIENT_TOKEN = "21ae43gf";
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 Fridge Server";
64 std::string  specVersion = "core.1.1.0";
65 std::vector<std::string> dataModelVersions = {"res.1.1.0"};
66
67 // OCPlatformInfo Contains all the platform info to be stored
68 OCPlatformInfo platformInfo;
69
70 class Resource
71 {
72     protected:
73     OCResourceHandle m_resourceHandle;
74     OCRepresentation m_rep;
75     virtual OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)=0;
76 };
77
78 class DeviceResource : public Resource
79 {
80     public:
81
82     DeviceResource():m_modelName{}
83     {
84         std::string resourceURI = "/device";
85         std::string resourceTypeName = "intel.fridge";
86         std::string resourceInterface = DEFAULT_INTERFACE;
87         EntityHandler cb = std::bind(&DeviceResource::entityHandler, this,PH::_1);
88
89         EntityHandler defaultEH = std::bind(&DeviceResource::defaultEntityHandler
90                                             ,this, PH::_1);
91
92         std::cout << "Setting device default entity handler\n";
93         OCPlatform::setDefaultDeviceEntityHandler(defaultEH);
94
95         uint8_t resourceProperty = OC_DISCOVERABLE;
96         OCStackResult result = OCPlatform::registerResource(m_resourceHandle,
97             resourceURI,
98             resourceTypeName,
99             resourceInterface,
100             cb,
101             resourceProperty);
102
103         if(OC_STACK_OK != result)
104         {
105             throw std::runtime_error(
106                 std::string("Device Resource failed to start")+std::to_string(result));
107         }
108     }
109     private:
110     OCRepresentation get()
111     {
112         m_rep.setValue("device_name", std::string("Intel Powered 2 door, 1 light refrigerator"));
113         return m_rep;
114     }
115
116     OCStackResult deleteDeviceResource()
117     {
118         OCStackResult result = OCPlatform::unregisterResource(m_resourceHandle);
119         if(OC_STACK_OK != result)
120         {
121             throw std::runtime_error(
122                std::string("Device Resource failed to unregister/delete") + std::to_string(result));
123         }
124         return result;
125     }
126
127     std::string m_modelName;
128     protected:
129     virtual OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
130     {
131         OCEntityHandlerResult ehResult = OC_EH_ERROR;
132         if(request)
133         {
134             // Get the header options from the request
135             HeaderOptions headerOptions = request->getHeaderOptions();
136             std::string clientAPIVersion;
137             std::string clientToken;
138
139             // Get the message ID from the request
140             std::cout << " MessageID: " << request->getMessageID() << std::endl;
141
142             // Search the header options map and look for API version and Client token
143             for (auto it = headerOptions.begin(); it != headerOptions.end(); ++it)
144             {
145                 uint16_t optionID = it->getOptionID();
146                 if(optionID == API_VERSION)
147                 {
148                     clientAPIVersion = it->getOptionData();
149                     std::cout << " Client API version: " << clientAPIVersion << std::endl;
150                 }
151                 else if(optionID == TOKEN)
152                 {
153                     clientToken = it->getOptionData();
154                     std::cout << " Client token: " << clientToken << std::endl;
155                 }
156                 else
157                 {
158                     std::cout << " Invalid header option " << std::endl;
159                 }
160             }
161
162             // In this case Server entity handler verifies API version
163             // and client token. If they are valid, client requests are handled.
164             if(clientAPIVersion == FRIDGE_CLIENT_API_VERSION && clientToken == FRIDGE_CLIENT_TOKEN)
165             {
166                 HeaderOptions serverHeaderOptions;
167                 try
168                 {
169                     // Set API version from server side
170                     HeaderOption::OCHeaderOption apiVersion(API_VERSION, FRIDGE_CLIENT_API_VERSION);
171                     serverHeaderOptions.push_back(apiVersion);
172                 }
173                 catch(OCException& e)
174                 {
175                     std::cout << "Error creating HeaderOption in server: " << e.what() << std::endl;
176                 }
177
178                 if(request->getRequestHandlerFlag() == RequestHandlerFlag::RequestFlag)
179                 {
180                     auto pResponse = std::make_shared<OC::OCResourceResponse>();
181                     pResponse->setRequestHandle(request->getRequestHandle());
182                     pResponse->setResourceHandle(request->getResourceHandle());
183                     pResponse->setHeaderOptions(serverHeaderOptions);
184
185                     if(request->getRequestType() == "GET")
186                     {
187                         std::cout<<"DeviceResource Get Request"<<std::endl;
188
189                         pResponse->setResponseResult(OC_EH_OK);
190                         pResponse->setResourceRepresentation(get(), "");
191                         if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
192                         {
193                             ehResult = OC_EH_OK;
194                         }
195                     }
196                     else if(request->getRequestType() == "DELETE")
197                     {
198                         std::cout<<"DeviceResource Delete Request"<<std::endl;
199                         if(deleteDeviceResource() == OC_STACK_OK)
200                         {
201
202                             pResponse->setResponseResult(OC_EH_RESOURCE_DELETED);
203                             ehResult = OC_EH_OK;
204                         }
205                         else
206                         {
207                             pResponse->setResponseResult(OC_EH_ERROR);
208                             ehResult = OC_EH_ERROR;
209                         }
210                         OCPlatform::sendResponse(pResponse);
211                     }
212                     else
213                     {
214                         std::cout <<"DeviceResource unsupported request type "
215                         << request->getRequestType() << std::endl;
216                         pResponse->setResponseResult(OC_EH_ERROR);
217                         OCPlatform::sendResponse(pResponse);
218                         ehResult = OC_EH_ERROR;
219                     }
220                 }
221                 else
222                 {
223                     std::cout << "DeviceResource unsupported request flag" <<std::endl;
224                 }
225             }
226             else
227             {
228                 std::cout << "Unsupported/invalid header options/values" << std::endl;
229             }
230         }
231
232         return ehResult;
233     }
234
235     virtual OCEntityHandlerResult defaultEntityHandler(std::shared_ptr<OCResourceRequest> request)
236     {
237         OCEntityHandlerResult ehResult = OC_EH_ERROR;
238         if(request)
239         {
240             std::cout << "In Default Entity Handler, uri received: "
241                         << request->getResourceUri() << std::endl;
242
243             if(request->getRequestHandlerFlag() == RequestHandlerFlag::RequestFlag)
244             {
245                 auto pResponse = std::make_shared<OC::OCResourceResponse>();
246                 pResponse->setRequestHandle(request->getRequestHandle());
247                 pResponse->setResourceHandle(request->getResourceHandle());
248
249                 if(request->getRequestType() == "GET")
250                 {
251                     std::cout<<"Default Entity Handler: Get Request"<<std::endl;
252
253                     pResponse->setResourceRepresentation(get(), "");
254                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
255                     {
256                         ehResult = OC_EH_OK;
257                     }
258                 }
259                 else
260                 {
261                     std::cout <<"Default Entity Handler: unsupported request type "
262                     << request->getRequestType() << std::endl;
263                     pResponse->setResponseResult(OC_EH_ERROR);
264                     OCPlatform::sendResponse(pResponse);
265                     ehResult = OC_EH_ERROR;
266                 }
267             }
268             else
269             {
270                 std::cout << "Default Entity Handler: unsupported request flag" <<std::endl;
271             }
272         }
273
274         return ehResult;
275    }
276
277 };
278
279 class LightResource : public Resource
280 {
281     public:
282     LightResource() : m_isOn(false)
283     {
284         std::string resourceURI = "/light";
285         std::string resourceTypeName = "intel.fridge.light";
286         std::string resourceInterface = DEFAULT_INTERFACE;
287         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
288         uint8_t resourceProperty = 0;
289         OCStackResult result = OCPlatform::registerResource(m_resourceHandle,
290             resourceURI,
291             resourceTypeName,
292             resourceInterface,
293             cb,
294             resourceProperty);
295
296         if(OC_STACK_OK != result)
297         {
298             throw std::runtime_error(
299                 std::string("Light Resource failed to start")+std::to_string(result));
300         }
301     }
302     private:
303     OCRepresentation get()
304     {
305         m_rep.setValue("on", m_isOn);
306         return m_rep;
307     }
308
309     void put(const OCRepresentation& rep)
310     {
311         rep.getValue("on", m_isOn);
312     }
313
314     bool m_isOn;
315     protected:
316     virtual OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
317     {
318         OCEntityHandlerResult ehResult = OC_EH_ERROR;
319         if(request)
320         {
321             std::cout << "In entity handler for Light, URI is : "
322                       << request->getResourceUri() << std::endl;
323
324             if(request->getRequestHandlerFlag() == RequestHandlerFlag::RequestFlag)
325             {
326                 auto pResponse = std::make_shared<OC::OCResourceResponse>();
327                 pResponse->setRequestHandle(request->getRequestHandle());
328                 pResponse->setResourceHandle(request->getResourceHandle());
329
330                 if(request->getRequestType() == "GET")
331                 {
332                     std::cout<<"Light Get Request"<<std::endl;
333
334                     pResponse->setResourceRepresentation(get(), "");
335                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
336                     {
337                         ehResult = OC_EH_OK;
338                     }
339                 }
340                 else if(request->getRequestType() == "PUT")
341                 {
342                     std::cout <<"Light Put Request"<<std::endl;
343                     put(request->getResourceRepresentation());
344
345                     pResponse->setResourceRepresentation(get(), "");
346                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
347                     {
348                         ehResult = OC_EH_OK;
349                     }
350                 }
351                 else
352                 {
353                     std::cout << "Light unsupported request type"
354                     << request->getRequestType() << std::endl;
355                     pResponse->setResponseResult(OC_EH_ERROR);
356                     OCPlatform::sendResponse(pResponse);
357                     ehResult = OC_EH_ERROR;
358                 }
359             }
360             else
361             {
362                 std::cout << "Light unsupported request flag" <<std::endl;
363             }
364         }
365
366         return ehResult;
367     }
368 };
369
370 class DoorResource : public Resource
371 {
372     public:
373     DoorResource(const std::string& side):m_isOpen{false}, m_side(side)
374     {
375
376         std::string resourceURI = "/door/"+ side;
377         std::string resourceTypeName = "intel.fridge.door";
378         std::string resourceInterface = DEFAULT_INTERFACE;
379         EntityHandler cb = std::bind(&DoorResource::entityHandler, this,PH::_1);
380
381         uint8_t resourceProperty = 0;
382         OCStackResult result = OCPlatform::registerResource(m_resourceHandle,
383             resourceURI,
384             resourceTypeName,
385             resourceInterface,
386             cb,
387             resourceProperty);
388
389         if(OC_STACK_OK != result)
390         {
391             throw std::runtime_error(
392                 std::string("Door Resource failed to start")+std::to_string(result));
393         }
394     }
395
396     private:
397     OCRepresentation get()
398     {
399         m_rep.setValue("open", m_isOpen);
400         m_rep.setValue("side", m_side);
401         return m_rep;
402     }
403
404     void put(const OCRepresentation& rep)
405     {
406         rep.getValue("open", m_isOpen);
407         // Note, we won't let the user change the door side!
408     }
409     bool m_isOpen;
410     std::string m_side;
411     protected:
412     virtual OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
413     {
414         std::cout << "EH of door invoked " << std::endl;
415         OCEntityHandlerResult ehResult = OC_EH_ERROR;
416
417         if(request)
418         {
419             std::cout << "In entity handler for Door, URI is : "
420                       << request->getResourceUri() << std::endl;
421
422             if(request->getRequestHandlerFlag() == RequestHandlerFlag::RequestFlag)
423             {
424                 auto pResponse = std::make_shared<OC::OCResourceResponse>();
425                 pResponse->setRequestHandle(request->getRequestHandle());
426                 pResponse->setResourceHandle(request->getResourceHandle());
427
428                 if(request->getRequestType() == "GET")
429                 {
430                     // note that we know the side because std::bind gives us the
431                     // appropriate object
432                     std::cout<< m_side << " Door Get Request"<<std::endl;
433
434                     pResponse->setResourceRepresentation(get(), "");
435                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
436                     {
437                         ehResult = OC_EH_OK;
438                     }
439                 }
440                 else if(request->getRequestType() == "PUT")
441                 {
442                     std::cout << m_side <<" Door Put Request"<<std::endl;
443                     put(request->getResourceRepresentation());
444
445                     pResponse->setResourceRepresentation(get(),"");
446                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
447                     {
448                         ehResult = OC_EH_OK;
449                     }
450                 }
451                 else
452                 {
453                     std::cout <<m_side<<" Door unsupported request type "
454                     << request->getRequestType() << std::endl;
455                     pResponse->setResponseResult(OC_EH_ERROR);
456                     OCPlatform::sendResponse(pResponse);
457                     ehResult = OC_EH_ERROR;
458                 }
459             }
460             else
461             {
462                 std::cout << "Door unsupported request flag" <<std::endl;
463             }
464         }
465
466         return ehResult;
467     }
468
469 };
470
471 class Refrigerator
472 {
473     public:
474     Refrigerator()
475         :
476         m_light(),
477         m_device(),
478         m_leftdoor("left"),
479         m_rightdoor("right")
480     {
481     }
482     private:
483     LightResource m_light;
484     DeviceResource m_device;
485     DoorResource m_leftdoor;
486     DoorResource m_rightdoor;
487 };
488
489 void DeletePlatformInfo()
490 {
491     delete[] platformInfo.platformID;
492     delete[] platformInfo.manufacturerName;
493     delete[] platformInfo.manufacturerUrl;
494     delete[] platformInfo.modelNumber;
495     delete[] platformInfo.dateOfManufacture;
496     delete[] platformInfo.platformVersion;
497     delete[] platformInfo.operatingSystemVersion;
498     delete[] platformInfo.hardwareVersion;
499     delete[] platformInfo.firmwareVersion;
500     delete[] platformInfo.supportUrl;
501     delete[] platformInfo.systemTime;
502 }
503
504 void DuplicateString(char ** targetString, std::string sourceString)
505 {
506     *targetString = new char[sourceString.length() + 1];
507     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
508 }
509
510 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
511     std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
512     std::string platformVersion, std::string operatingSystemVersion, std::string hardwareVersion,
513     std::string firmwareVersion, std::string supportUrl, std::string systemTime)
514 {
515     DuplicateString(&platformInfo.platformID, platformID);
516     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
517     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
518     DuplicateString(&platformInfo.modelNumber, modelNumber);
519     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
520     DuplicateString(&platformInfo.platformVersion, platformVersion);
521     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
522     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
523     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
524     DuplicateString(&platformInfo.supportUrl, supportUrl);
525     DuplicateString(&platformInfo.systemTime, systemTime);
526
527     return OC_STACK_OK;
528 }
529
530 OCStackResult SetDeviceInfo()
531 {
532     OCStackResult result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME,
533                                                         deviceName);
534     if (result != OC_STACK_OK)
535     {
536         std::cout << "Failed to set device name" << std::endl;
537         return result;
538     }
539
540     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION,
541                                           dataModelVersions);
542     if (result != OC_STACK_OK)
543     {
544         std::cout << "Failed to set data model versions" << std::endl;
545         return result;
546     }
547
548     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, specVersion);
549     if (result != OC_STACK_OK)
550     {
551         std::cout << "Failed to set spec version" << std::endl;
552         return result;
553     }
554
555     return OC_STACK_OK;
556 }
557
558 int main ()
559 {
560     PlatformConfig cfg
561     {
562         ServiceType::InProc,
563         ModeType::Server,
564         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
565         0,         // Uses randomly available port
566         QualityOfService::LowQos
567     };
568
569     OCPlatform::Configure(cfg);
570     Refrigerator rf;
571
572     std::cout << "Starting server & setting platform info\n";
573
574     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
575             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
576             hardwareVersion, firmwareVersion, supportLink, systemTime);
577
578     result = OCPlatform::registerPlatformInfo(platformInfo);
579
580     if (result != OC_STACK_OK)
581     {
582         std::cout << "Platform Registration failed\n";
583         return -1;
584     }
585
586     result = SetDeviceInfo();
587
588     if (result != OC_STACK_OK)
589     {
590         std::cout << "Device Registration failed\n";
591         return -1;
592     }
593
594     DeletePlatformInfo();
595     // we will keep the server alive for at most 30 minutes
596     std::this_thread::sleep_for(std::chrono::minutes(30));
597     return 0;
598 }
599