Add pthread_join() in case of failure of ca_thread_pool_add_task()
[platform/upstream/iotivity.git] / resource / examples / roomserver.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 ///
22 /// This sample shows how one could create a resource (collection) with children.
23 ///
24
25 #include <functional>
26
27 #include <mutex>
28 #include <condition_variable>
29
30 #include "OCPlatform.h"
31 #include "OCApi.h"
32 #include "ocpayload.h"
33
34 using namespace OC;
35 using namespace std;
36
37
38 // Forward declaring the entityHandler (room)
39 OCEntityHandlerResult entityHandlerRoom(std::shared_ptr<OCResourceRequest> request);
40 OCEntityHandlerResult entityHandlerLight(std::shared_ptr<OCResourceRequest> request);
41 OCEntityHandlerResult entityHandlerFan(std::shared_ptr<OCResourceRequest> request);
42
43 /// Specifies whether default collection entity handler is used or not
44 bool useDefaultCollectionEH = false;
45
46 // Set of strings for each of platform Info fields
47 std::string  platformId = "0A3E0D6F-DBF5-404E-8719-D6880042463A";
48 std::string  manufacturerName = "OCF";
49 std::string  manufacturerLink = "https://www.iotivity.org";
50 std::string  modelNumber = "myModelNumber";
51 std::string  dateOfManufacture = "2016-01-15";
52 std::string  platformVersion = "myPlatformVersion";
53 std::string  operatingSystemVersion = "myOS";
54 std::string  hardwareVersion = "myHardwareVersion";
55 std::string  firmwareVersion = "1.0";
56 std::string  supportLink = "https://www.iotivity.org";
57 std::string  systemTime = "2016-01-15T11.01";
58
59 // Set of strings for each of device info fields
60 std::string  deviceName = "IoTivity Room Server";
61 std::string  specVersion = "core.1.1.0";
62 std::string  dataModelVersions = "res.1.1.0";
63
64 // OCPlatformInfo Contains all the platform info to be stored
65 OCPlatformInfo platformInfo;
66
67 // OCDeviceInfo Contains all the device info to be stored
68 OCDeviceInfo deviceInfo;
69
70 class RoomResource
71 {
72 public:
73
74     // Room members
75     std::string m_roomUri;
76     std::string m_roomName;
77     std::vector<std::string> m_roomTypes;
78     std::vector<std::string> m_roomInterfaces;
79     OCResourceHandle m_roomHandle;
80     OCRepresentation m_roomRep;
81
82     // light members
83     bool m_lightState;
84     int m_lightColor;
85     std::string m_lightUri;
86     std::vector<std::string> m_lightTypes;
87     std::vector<std::string> m_lightInterfaces;
88     OCResourceHandle m_lightHandle;
89     OCRepresentation m_lightRep;
90
91     // fan members
92     bool m_fanState;
93     int m_fanSpeed;
94     std::string m_fanUri;
95     std::vector<std::string> m_fanTypes;
96     std::vector<std::string> m_fanInterfaces;
97     OCResourceHandle m_fanHandle;
98     OCRepresentation m_fanRep;
99
100 public:
101     /// Constructor
102     RoomResource(): m_roomName("John's Room"), m_roomHandle(nullptr), m_lightState(false),
103                     m_lightColor(0),m_lightHandle(nullptr),  m_fanState(false), m_fanSpeed(0),
104                     m_fanHandle(nullptr)
105     {
106         m_lightUri = "/a/light"; // URI of the resource
107         m_lightTypes.push_back("core.light"); // resource type name. In this case, it is light
108         m_lightInterfaces.push_back(DEFAULT_INTERFACE); // resource interface.
109
110         m_lightRep.setUri(m_lightUri);
111         m_lightRep.setResourceTypes(m_lightTypes);
112         m_lightRep.setResourceInterfaces(m_lightInterfaces);
113         m_lightRep.setValue("state", m_lightState);
114         m_lightRep.setValue("color", m_lightColor);
115
116         m_fanUri = "/a/fan"; // URI of the resource
117         m_fanTypes.push_back("core.fan"); // resource type name. In this case, it is light
118         m_fanInterfaces.push_back(DEFAULT_INTERFACE); // resource interface.
119
120         m_fanRep.setUri(m_fanUri);
121         m_fanRep.setResourceTypes(m_fanTypes);
122         m_fanRep.setResourceInterfaces(m_fanInterfaces);
123         m_fanRep.setValue("state", m_fanState);
124         m_fanRep.setValue("speed", m_fanSpeed);
125
126         m_roomUri = "/a/room"; // URI of the resource
127         m_roomTypes.push_back("core.room"); // resource type name. In this case, it is light
128         m_roomInterfaces.push_back(DEFAULT_INTERFACE); // resource interface.
129         m_roomInterfaces.push_back(BATCH_INTERFACE); // resource interface.
130         m_roomInterfaces.push_back(LINK_INTERFACE); // resource interface.
131         m_roomRep.setValue("name", m_roomName);
132         m_roomRep.setUri(m_roomUri);
133         m_roomRep.setResourceTypes(m_roomTypes);
134         m_roomRep.setResourceInterfaces(m_roomInterfaces);
135     }
136
137     /// This function internally calls registerResource API.
138     void createResources()
139     {
140         // This function internally creates and registers the resource.
141         using namespace OC::OCPlatform;
142         OCStackResult result = OC_STACK_ERROR;
143
144         // Based on the case, we will use default collection EH (by passing NULL in entity handler
145         // parameter) or use application entity handler.
146         if(useDefaultCollectionEH)
147         {
148             result = registerResource(
149                                     m_roomHandle, m_roomUri, m_roomTypes[0],
150                                     m_roomInterfaces[0], NULL,
151                                     OC_DISCOVERABLE | OC_OBSERVABLE);
152         }
153         else
154         {
155             result = registerResource(
156                                     m_roomHandle, m_roomUri, m_roomTypes[0],
157                                     m_roomInterfaces[0], entityHandlerRoom,
158                                     OC_DISCOVERABLE | OC_OBSERVABLE);
159         }
160
161         if (OC_STACK_OK != result)
162         {
163             cout << "Resource creation (room) was unsuccessful\n";
164         }
165
166         result = bindInterfaceToResource(m_roomHandle, m_roomInterfaces[1]);
167         if (OC_STACK_OK != result)
168         {
169             cout << "Binding TypeName to Resource was unsuccessful\n";
170         }
171
172         result = bindInterfaceToResource(m_roomHandle, m_roomInterfaces[2]);
173         if (OC_STACK_OK != result)
174         {
175             cout << "Binding TypeName to Resource was unsuccessful\n";
176         }
177
178         result = registerResource(m_lightHandle, m_lightUri, m_lightTypes[0],
179                                   m_lightInterfaces[0], entityHandlerLight,
180                                   OC_DISCOVERABLE | OC_OBSERVABLE);
181
182         if (OC_STACK_OK != result)
183         {
184             cout << "Resource creation (light) was unsuccessful\n";
185         }
186
187         result = registerResource(m_fanHandle, m_fanUri, m_fanTypes[0],
188                                   m_fanInterfaces[0], entityHandlerFan,
189                                   OC_DISCOVERABLE | OC_OBSERVABLE);
190
191         if (OC_STACK_OK != result)
192         {
193             cout << "Resource creation (fan) was unsuccessful\n";
194         }
195
196         result = bindResource(m_roomHandle, m_lightHandle);
197         if (OC_STACK_OK != result)
198         {
199             cout << "Binding fan resource to room was unsuccessful\n";
200         }
201
202         result = bindResource(m_roomHandle, m_fanHandle);
203         if (OC_STACK_OK != result)
204         {
205             cout << "Binding light resource to room was unsuccessful\n";
206         }
207
208     }
209
210     void setLightRepresentation(OCRepresentation& rep)
211     {
212         bool tempState = false;
213         int tempColor = 0;
214
215         // If both entries exist
216         if(rep.getValue("state", tempState) && rep.getValue("color", tempColor))
217         {
218             m_lightState = tempState;
219             m_lightColor= tempColor;
220
221             cout << "\t\t\t\t" << "state: " << m_lightState << endl;
222             cout << "\t\t\t\t" << "color: " << m_lightColor << endl;
223         }
224     }
225
226     void setFanRepresentation(OCRepresentation& rep)
227     {
228         bool tempState = false;
229         int tempSpeed = 0;
230
231         // If both entries exist
232         if(rep.getValue("state", tempState) && rep.getValue("speed", tempSpeed))
233         {
234             m_fanState = tempState;
235             m_fanSpeed = tempSpeed;
236
237             cout << "\t\t\t\t" << "state: " << m_fanState << endl;
238             cout << "\t\t\t\t" << "speed: " << m_fanSpeed << endl;
239         }
240     }
241
242
243     OCRepresentation getLightRepresentation()
244     {
245         m_lightRep.setValue("state", m_lightState);
246         m_lightRep.setValue("color", m_lightColor);
247
248         return m_lightRep;
249     }
250
251     OCRepresentation getFanRepresentation()
252     {
253         m_fanRep.setValue("state", m_fanState);
254         m_fanRep.setValue("speed", m_fanSpeed);
255         return m_fanRep;
256     }
257
258     OCRepresentation getRoomRepresentation(void)
259     {
260         m_roomRep.clearChildren();
261
262         m_roomRep.addChild(getLightRepresentation());
263         m_roomRep.addChild(getFanRepresentation());
264         return m_roomRep;
265     }
266
267 };
268
269 // Create the instance of the resource class (in this case instance of class 'RoomResource').
270 RoomResource myRoomResource;
271
272 OCStackResult sendRoomResponse(std::shared_ptr<OCResourceRequest> pRequest)
273 {
274     auto pResponse = std::make_shared<OC::OCResourceResponse>();
275     pResponse->setRequestHandle(pRequest->getRequestHandle());
276     pResponse->setResourceHandle(pRequest->getResourceHandle());
277
278     // Check for query params (if any)
279     QueryParamsMap queryParamsMap = pRequest->getQueryParameters();
280
281     cout << "\t\t\tquery params: \n";
282     for(auto it = queryParamsMap.begin(); it != queryParamsMap.end(); it++)
283     {
284         cout << "\t\t\t\t" << it->first << ":" << it->second << endl;
285     }
286
287     OCRepresentation rep;
288     rep = myRoomResource.getRoomRepresentation();
289
290     auto findRes = queryParamsMap.find("if");
291
292     if(findRes != queryParamsMap.end())
293     {
294         pResponse->setResourceRepresentation(rep, findRes->second);
295     }
296     else
297     {
298         pResponse->setResourceRepresentation(rep, DEFAULT_INTERFACE);
299     }
300
301     pResponse->setErrorCode(200);
302     pResponse->setResponseResult(OC_EH_OK);
303
304     return OCPlatform::sendResponse(pResponse);
305 }
306
307 // This function prepares a response for any incoming request to Light resource.
308 bool prepareLightResponse(std::shared_ptr<OCResourceRequest> request)
309 {
310     cout << "\tIn Server CPP (Light) prepareLightResponse:\n";
311     bool result = false;
312     if(request)
313     {
314         // Get the request type and request flag
315         std::string requestType = request->getRequestType();
316         int requestFlag = request->getRequestHandlerFlag();
317
318         if(requestFlag == RequestHandlerFlag::RequestFlag)
319         {
320             cout << "\t\trequestFlag : Request\n";
321
322             // If the request type is GET
323             if(requestType == "GET")
324             {
325                 cout << "\t\t\trequestType : GET\n";
326                 // GET operations are directly handled while sending the response
327                 // in the sendLightResponse function
328                 result = true;
329             }
330             else if(requestType == "PUT")
331             {
332                 cout << "\t\t\trequestType : PUT\n";
333                 OCRepresentation rep = request->getResourceRepresentation();
334
335                 // Do related operations related to PUT request
336                 myRoomResource.setLightRepresentation(rep);
337                 result= true;
338             }
339             else if(requestType == "POST")
340             {
341                 // POST request operations
342             }
343             else if(requestType == "DELETE")
344             {
345                 // DELETE request operations
346             }
347         }
348         else if(requestFlag == RequestHandlerFlag::ObserverFlag)
349         {
350             cout << "\t\trequestFlag : Observer\n";
351         }
352     }
353     else
354     {
355         std::cout << "Request invalid" << std::endl;
356     }
357
358     return result;
359 }
360
361 // This function prepares a response for any incoming request to Fan resource.
362 bool prepareFanResponse(std::shared_ptr<OCResourceRequest> request)
363 {
364     cout << "\tIn Server CPP (Fan) prepareFanResponse:\n";
365     bool result = false;
366
367     if(request)
368     {
369         // Get the request type and request flag
370         std::string requestType = request->getRequestType();
371         int requestFlag = request->getRequestHandlerFlag();
372
373         if(requestFlag == RequestHandlerFlag::RequestFlag)
374         {
375             cout << "\t\trequestFlag : Request\n";
376
377             // If the request type is GET
378             if(requestType == "GET")
379             {
380                 cout << "\t\t\trequestType : GET\n";
381                 // GET operations are directly handled while sending the response
382                 // in the sendLightResponse function
383                 result = true;
384             }
385             else if(requestType == "PUT")
386             {
387                 cout << "\t\t\trequestType : PUT\n";
388
389                 OCRepresentation rep = request->getResourceRepresentation();
390
391                 // Do related operations related to PUT request
392                 myRoomResource.setFanRepresentation(rep);
393                 result = true;
394             }
395             else if(requestType == "POST")
396             {
397                 // POST request operations
398             }
399             else if(requestType == "DELETE")
400             {
401                 // DELETE request operations
402             }
403         }
404         else if(requestFlag == RequestHandlerFlag::ObserverFlag)
405         {
406             cout << "\t\trequestFlag : Observer\n";
407         }
408     }
409     else
410     {
411         std::cout << "Request invalid" << std::endl;
412     }
413
414     return result;
415 }
416
417 OCEntityHandlerResult entityHandlerRoom(std::shared_ptr<OCResourceRequest> request)
418 {
419     cout << "\tIn Server CPP entity handler:\n";
420     OCEntityHandlerResult ehResult = OC_EH_ERROR;
421
422     if(request)
423     {
424         // Get the request type and request flag
425         std::string requestType = request->getRequestType();
426         int requestFlag = request->getRequestHandlerFlag();
427
428         if(requestFlag == RequestHandlerFlag::RequestFlag)
429         {
430             cout << "\t\trequestFlag : Request\n";
431
432             // If the request type is GET
433             if(requestType == "GET")
434             {
435                 cout << "\t\t\trequestType : GET\n";
436                 if(OC_STACK_OK == sendRoomResponse(request))
437                 {
438                     ehResult = OC_EH_OK;
439                 }
440             }
441             else if(requestType == "PUT")
442             {
443                 cout << "\t\t\trequestType : PUT\n";
444                 // Call these functions to prepare the response for child resources and
445                 // then send the final response using sendRoomResponse function
446                 prepareLightResponse(request);
447                 prepareFanResponse(request);
448                 if(OC_STACK_OK == sendRoomResponse(request))
449                 {
450                     ehResult = OC_EH_OK;
451                 }
452             }
453             else if(requestType == "POST")
454             {
455                 // POST request operations
456             }
457             else if(requestType == "DELETE")
458             {
459                 // DELETE request operations
460             }
461         }
462         else if(requestFlag == RequestHandlerFlag::ObserverFlag)
463         {
464             cout << "\t\trequestFlag : Observer\n";
465         }
466     }
467     else
468     {
469         std::cout << "Request invalid" << std::endl;
470     }
471
472     return ehResult;
473 }
474
475 OCStackResult sendLightResponse(std::shared_ptr<OCResourceRequest> pRequest)
476 {
477     auto pResponse = std::make_shared<OC::OCResourceResponse>();
478     pResponse->setRequestHandle(pRequest->getRequestHandle());
479     pResponse->setResourceHandle(pRequest->getResourceHandle());
480     pResponse->setResourceRepresentation(myRoomResource.getLightRepresentation());
481     pResponse->setErrorCode(200);
482     pResponse->setResponseResult(OC_EH_OK);
483
484     return OCPlatform::sendResponse(pResponse);
485 }
486
487
488
489 OCEntityHandlerResult entityHandlerLight(std::shared_ptr<OCResourceRequest> request)
490 {
491     cout << "\tIn Server CPP (Light) entity handler:\n";
492     OCEntityHandlerResult ehResult = OC_EH_ERROR;
493
494     if(prepareLightResponse(request))
495     {
496         if(OC_STACK_OK == sendLightResponse(request))
497         {
498             ehResult = OC_EH_OK;
499         }
500         else
501         {
502             std::cout << "sendLightResponse failed." << std::endl;
503         }
504     }
505     else
506     {
507         std::cout << "PrepareLightResponse failed." << std::endl;
508     }
509     return ehResult;
510 }
511
512 OCStackResult sendFanResponse(std::shared_ptr<OCResourceRequest> pRequest)
513 {
514     auto pResponse = std::make_shared<OC::OCResourceResponse>();
515     pResponse->setRequestHandle(pRequest->getRequestHandle());
516     pResponse->setResourceHandle(pRequest->getResourceHandle());
517     pResponse->setResourceRepresentation(myRoomResource.getFanRepresentation());
518     pResponse->setErrorCode(200);
519     pResponse->setResponseResult(OC_EH_OK);
520
521     return OCPlatform::sendResponse(pResponse);
522 }
523
524
525 OCEntityHandlerResult entityHandlerFan(std::shared_ptr<OCResourceRequest> request)
526 {
527     cout << "\tIn Server CPP (Fan) entity handler:\n";
528     OCEntityHandlerResult ehResult = OC_EH_ERROR;
529     if(prepareFanResponse(request))
530     {
531         if(OC_STACK_OK == sendFanResponse(request))
532         {
533             ehResult = OC_EH_OK;
534         }
535         else
536         {
537             std::cout << "sendFanResponse failed." << std::endl;
538         }
539     }
540     else
541     {
542         std::cout << "PrepareFanResponse failed." << std::endl;
543     }
544
545     return ehResult;
546 }
547
548 void printUsage()
549 {
550     std::cout << std::endl;
551     std::cout << "Usage : roomserver <value>\n";
552     std::cout << "1 : Create room resource with default collection entity handler.\n";
553     std::cout << "2 : Create room resource with application collection entity handler.\n";
554 }
555
556 void DeletePlatformInfo()
557 {
558     delete[] platformInfo.platformID;
559     delete[] platformInfo.manufacturerName;
560     delete[] platformInfo.manufacturerUrl;
561     delete[] platformInfo.modelNumber;
562     delete[] platformInfo.dateOfManufacture;
563     delete[] platformInfo.platformVersion;
564     delete[] platformInfo.operatingSystemVersion;
565     delete[] platformInfo.hardwareVersion;
566     delete[] platformInfo.firmwareVersion;
567     delete[] platformInfo.supportUrl;
568     delete[] platformInfo.systemTime;
569 }
570
571 void DeleteDeviceInfo()
572 {
573     delete[] deviceInfo.deviceName;
574     delete[] deviceInfo.specVersion;
575     OCFreeOCStringLL(deviceInfo.dataModelVersions);
576 }
577
578 void DuplicateString(char ** targetString, std::string sourceString)
579 {
580     *targetString = new char[sourceString.length() + 1];
581     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
582 }
583
584 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
585         std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
586         std::string platformVersion, std::string operatingSystemVersion,
587         std::string hardwareVersion, std::string firmwareVersion, std::string supportUrl,
588         std::string systemTime)
589 {
590     DuplicateString(&platformInfo.platformID, platformID);
591     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
592     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
593     DuplicateString(&platformInfo.modelNumber, modelNumber);
594     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
595     DuplicateString(&platformInfo.platformVersion, platformVersion);
596     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
597     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
598     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
599     DuplicateString(&platformInfo.supportUrl, supportUrl);
600     DuplicateString(&platformInfo.systemTime, systemTime);
601
602     return OC_STACK_OK;
603 }
604
605 OCStackResult SetDeviceInfo(std::string deviceName, std::string specVersion, std::string dataModelVersions)
606 {
607     DuplicateString(&deviceInfo.deviceName, deviceName);
608
609     if (!specVersion.empty())
610     {
611         DuplicateString(&deviceInfo.specVersion, specVersion);
612     }
613
614     if (!dataModelVersions.empty())
615     {
616         OCResourcePayloadAddStringLL(&deviceInfo.dataModelVersions, dataModelVersions.c_str());
617     }
618
619     return OC_STACK_OK;
620 }
621
622 int main(int argc, char* argv[])
623 {
624     printUsage();
625
626     if(argc == 2)
627     {
628         int value = atoi(argv[1]);
629         switch (value)
630         {
631             case 1:
632                 useDefaultCollectionEH = true;
633                 break;
634             case 2:
635             default:
636                 break;
637        }
638     }
639     else
640     {
641         return -1;
642     }
643
644     // Create PlatformConfig object
645     PlatformConfig cfg {
646         OC::ServiceType::InProc,
647         OC::ModeType::Server,
648         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
649         0,         // Uses randomly available port
650         OC::QualityOfService::LowQos
651     };
652
653     OCPlatform::Configure(cfg);
654     std::cout << "Starting server & setting platform info\n";
655
656     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
657             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
658             hardwareVersion, firmwareVersion, supportLink, systemTime);
659
660     result = OCPlatform::registerPlatformInfo(platformInfo);
661
662     if (result != OC_STACK_OK)
663     {
664         std::cout << "Platform Registration failed\n";
665         return -1;
666     }
667
668     result = SetDeviceInfo(deviceName, specVersion, dataModelVersions);
669     OCResourcePayloadAddStringLL(&deviceInfo.types, "oic.wk.d");
670     
671     result = OCPlatform::registerDeviceInfo(deviceInfo);
672
673     if (result != OC_STACK_OK)
674     {
675         std::cout << "Device Registration failed\n";
676         return -1;
677     }
678
679     try
680     {
681
682         myRoomResource.createResources();
683
684         DeletePlatformInfo();
685         DeleteDeviceInfo();
686         // A condition variable will free the mutex it is given, then do a non-
687         // intensive block until 'notify' is called on it.  In this case, since we
688         // don't ever call cv.notify, this should be a non-processor intensive version
689         // of while(true);
690         std::mutex blocker;
691         std::condition_variable cv;
692         std::unique_lock<std::mutex> lock(blocker);
693         cv.wait(lock);
694
695     }
696     catch(OCException &e)
697     {
698         std::cout << "Exception in main: " << e.what();
699     }
700
701     // No explicit call to stop the platform.
702     // When OCPlatform destructor is invoked, internally we do platform cleanup
703
704     return 0;
705 }
706