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