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