b01688fc452c14f61274aab7d90e82a167f39af2
[iotivity.git] / service / easy-setup / sampleapp / mediator / linux / richsdk_sample / submediator.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics 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 #include <iostream>
22 #include <condition_variable>
23
24 #include "OCPlatform.h"
25 #include "OCApi.h"
26 #include "OCProvisioningManager.hpp"
27 #include "securevirtualresourcetypes.h"
28
29 #include "EasySetup.hpp"
30 #include "ESRichCommon.h"
31
32 #define ES_SAMPLE_APP_TAG "ES_SAMPLE_APP_TAG"
33 #define DECLARE_MENU(FUNC, ...) { #FUNC, FUNC }
34
35 #define JSON_DB_PATH "./oic_svr_db_subclient.dat"
36
37 using namespace OC;
38 using namespace OIC::Service;
39
40 static std::shared_ptr<RemoteEnrollee> remoteEnrollee = nullptr;
41 static std::shared_ptr<OC::OCResource> curResource = nullptr;
42
43 static std::mutex g_discoverymtx;
44 static std::condition_variable g_cond;
45
46 typedef void (*Runner)();
47
48 Runner g_currentRun;
49
50 int processUserInput(int min = std::numeric_limits<int>::min(),
51                      int max = std::numeric_limits<int>::max())
52 {
53     assert(min <= max);
54
55     int input = 0;
56
57     std::cin >> input;
58     std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
59
60     if (!std::cin.fail() && min <= input && input <= max)
61     {
62         return input;
63     }
64
65     std::cin.clear();
66     std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
67
68     throw std::runtime_error("Invalid Input, please try again");
69 }
70
71 void printConfiguration(const EnrolleeConf &conf)
72 {
73     cout << "===========================================" << endl;
74     cout << "\tProvStatus : " << conf.getProvStatus() << endl;
75     cout << "\tLastErrCode : " << conf.getLastErrCode() << endl;
76     cout << "\tDevice Name : " << conf.getDeviceName() << endl;
77
78     for (auto it : conf.getWiFiModes())
79     {
80         cout << "\tSupported WiFi modes : " << it << endl;
81     }
82
83     cout << "\tSupported WiFi freq : " << static_cast<int>(conf.getWiFiFreq()) << endl;
84     cout << "\tCloud accessibility: " << conf.isCloudAccessible() << endl;
85     cout << "===========================================" << endl;
86 }
87
88 void printStatus(const EnrolleeStatus &status)
89 {
90     cout << "===========================================" << endl;
91     cout << "\tProvStatus : " << status.getProvStatus() << endl;
92     cout << "\tLastErrCode : " << status.getLastErrCode() << endl;
93     cout << "===========================================" << endl;
94 }
95
96 ESOwnershipTransferData provisionSecurityStatusCallback(std::shared_ptr<SecProvisioningStatus>
97         secProvisioningStatus)
98 {
99     cout << "provisionSecurityStatusCallback IN" << endl;
100     cout << "ESResult : " << secProvisioningStatus->getESResult() << std::endl;
101     cout << "Device ID : " << secProvisioningStatus->getDeviceUUID() << std::endl;
102
103     if (secProvisioningStatus->getESResult() == ES_SECURE_RESOURCE_IS_DISCOVERED)
104     {
105 #ifdef __WITH_DTLS__
106         cout << "Owned Status : " << secProvisioningStatus->isOwnedDevice() << std::endl;
107         if (secProvisioningStatus->isOwnedDevice())
108         {
109             cout << "Owner ID : " << secProvisioningStatus->getOwnerID() << std::endl;
110         }
111         cout << "OT Method : " << secProvisioningStatus->getSelectedOTMethod() << std::endl;
112 #ifdef MULTIPLE_OWNER
113         cout << "MOT Enabled : " << secProvisioningStatus->isMOTEnabled() << std::endl;
114
115         // TEST
116         ESOwnershipTransferData OTData;
117         OTData.setMOTMethod(OIC_PRECONFIG_PIN, "12345678");
118
119         cout << "Enter!" << std::endl;
120         getchar();
121
122         return OTData;
123 #endif
124 #endif
125     }
126     else if (secProvisioningStatus->getESResult() == ES_OK)
127     {
128         cout << "provisionSecurity is success." << std::endl;
129         curResource = nullptr;
130     }
131     else
132     {
133         cout << "provisionSecurity is failed." << endl;
134     }
135
136     return {};
137 }
138
139 void provisionSecurity()
140 {
141     if (!remoteEnrollee)
142     {
143         std::cout << "RemoteEnrollee is null, retry Discovery EnrolleeResource." << endl;
144         return;
145     }
146
147     try
148     {
149         remoteEnrollee->provisionSecurity((SecurityProvStatusCbWithOption)provisionSecurityStatusCallback);
150     }
151     catch (OCException &e)
152     {
153         std::cout << "Exception during provisionSecurity call" << e.reason();
154         return;
155     }
156 }
157
158 void getStatusCallback(std::shared_ptr< GetEnrolleeStatus > getEnrolleeStatus)
159 {
160     if (getEnrolleeStatus->getESResult() != ES_OK)
161     {
162         cout << "getStatus is failed." << endl;
163         return;
164     }
165     else
166     {
167         cout << "getStatus is success." << endl;
168         printStatus(getEnrolleeStatus->getEnrolleeStatus());
169     }
170 }
171
172
173 void getStatus()
174 {
175     if (!remoteEnrollee)
176     {
177         std::cout << "RemoteEnrollee is null, retry Discovery EnrolleeResource." << endl;
178         return;
179     }
180
181     try
182     {
183         remoteEnrollee->getStatus(getStatusCallback);
184     }
185     catch (OCException &e)
186     {
187         std::cout << "Exception during getConfiguration call" << e.reason();
188         return;
189     }
190 }
191
192 void getConfigurationCallback(std::shared_ptr< GetConfigurationStatus > getConfigurationStatus)
193 {
194     if (getConfigurationStatus->getESResult() != ES_OK)
195     {
196         cout << "GetConfigurationStatus is failed." << endl;
197         return;
198     }
199     else
200     {
201         cout << "GetConfigurationStatus is success." << endl;
202         printConfiguration(getConfigurationStatus->getEnrolleeConf());
203     }
204 }
205
206 void getConfiguration()
207 {
208     if (!remoteEnrollee)
209     {
210         std::cout << "RemoteEnrollee is null, retry Discovery EnrolleeResource." << endl;
211         return;
212     }
213
214     try
215     {
216         remoteEnrollee->getConfiguration(getConfigurationCallback);
217     }
218     catch (OCException &e)
219     {
220         std::cout << "Exception during getConfiguration call" << e.reason();
221         return;
222     }
223 }
224
225 void deviceProvisioningStatusCallback(std::shared_ptr< DevicePropProvisioningStatus > provStatus)
226 {
227     if (provStatus->getESResult() != ES_OK)
228     {
229         cout << "Device Provisioning is failed." << endl;
230         return;
231     }
232     else
233     {
234         cout << "Device Provisioning is success." << endl;
235     }
236 }
237
238 void provisionDeviceProperty()
239 {
240     if (!remoteEnrollee)
241     {
242         std::cout << "RemoteEnrollee is null, retry Discovery EnrolleeResource." << endl;
243         return;
244     }
245
246     DeviceProp devProp;
247     devProp.setWiFiProp("Iotivity_SSID", "Iotivity_PWD", WPA2_PSK, TKIP_AES);
248
249     try
250     {
251         remoteEnrollee->provisionDeviceProperties(devProp, deviceProvisioningStatusCallback);
252     }
253     catch (OCException &e)
254     {
255         std::cout << "Exception during provisionDeviceProperties call" << e.reason();
256         return;
257     }
258 }
259
260 void connectRequestStatusCallback(std::shared_ptr< ConnectRequestStatus > requestStatus)
261 {
262     if (requestStatus->getESResult() != ES_OK)
263     {
264         cout << "Request to connection is failed." << endl;
265         return;
266     }
267     else
268     {
269         cout << "Request to connection is success." << endl;
270     }
271 }
272
273 void requestToConnect()
274 {
275     if (!remoteEnrollee)
276     {
277         std::cout << "RemoteEnrollee is null, retry Discovery EnrolleeResource." << endl;
278         return;
279     }
280
281     try
282     {
283         std::vector<ES_CONNECT_TYPE> types;
284         types.push_back(ES_CONNECT_WIFI);
285         types.push_back(ES_CONNECT_COAPCLOUD);
286         remoteEnrollee->requestToConnect(types, connectRequestStatusCallback);
287     }
288     catch (OCException &e)
289     {
290         std::cout << "Exception during provisionDeviceProperties call" << e.reason();
291         return;
292     }
293 }
294
295 void cloudProvisioningStatusCallback(std::shared_ptr< CloudPropProvisioningStatus > provStatus)
296 {
297     switch (provStatus->getESResult())
298     {
299         case ES_OK:
300             cout << "Cloud Provisioning is success." << endl;
301             break;
302         case ES_SECURE_RESOURCE_DISCOVERY_FAILURE:
303             cout << "Enrollee is not found in a given network." << endl;
304             break;
305         case ES_ACL_PROVISIONING_FAILURE:
306             cout << "ACL provisioning is failed." << endl;
307             break;
308         case ES_CERT_PROVISIONING_FAILURE:
309             cout << "CERT provisioning is failed." << endl;
310             break;
311         default:
312             cout << "Cloud Provisioning is failed." << endl;
313             break;
314     }
315 }
316
317 void provisionCloudProperty()
318 {
319     if (!remoteEnrollee)
320     {
321         std::cout << "RemoteEnrollee is null, retry Discovery EnrolleeResource." << endl;
322         return;
323     }
324
325     CloudProp cloudProp;
326     cloudProp.setCloudPropWithAccessToken("accessToken", OAUTH_TOKENTYPE_BEARER, "authProvider",
327                                           "ciServer");
328
329     try
330     {
331         remoteEnrollee->provisionCloudProperties(cloudProp, cloudProvisioningStatusCallback);
332     }
333     catch (OCException &e)
334     {
335         std::cout << "Exception during provisionCloudProperties call" << e.reason();
336         return;
337     }
338 }
339
340 // Callback to found resources
341 void foundUnsecuredResource(std::shared_ptr<OC::OCResource> resource)
342 {
343     std::string resourceURI;
344     std::string hostAddress;
345     try
346     {
347         // Do some operations with resource object.
348         if (resource && !curResource  &&
349             resource->getResourceTypes().at(0) == OC_RSRVD_ES_RES_TYPE_EASYSETUP)
350         {
351             std::cout << "DISCOVERED Resource:" << std::endl;
352             // Get the resource URI
353             resourceURI = resource->uri();
354             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
355
356             // Get the resource host address
357             hostAddress = resource->host();
358             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
359
360             // Get the resource types
361             std::cout << "\tList of resource types: " << std::endl;
362             for (auto &resourceTypes : resource->getResourceTypes())
363             {
364                 std::cout << "\t\t" << resourceTypes << std::endl;
365             }
366
367             // Get the resource interfaces
368             std::cout << "\tList of resource interfaces: " << std::endl;
369             for (auto &resourceInterfaces : resource->getResourceInterfaces())
370             {
371                 std::cout << "\t\t" << resourceInterfaces << std::endl;
372             }
373
374             if (curResource == nullptr)
375             {
376                 remoteEnrollee = EasySetup::getInstance()->createRemoteEnrollee(resource);
377                 if (!remoteEnrollee)
378                 {
379                     std::cout << "RemoteEnrollee object is failed for some reasons!" << std::endl;
380                 }
381                 else
382                 {
383                     curResource = resource;
384                     std::cout << "RemoteEnrollee object is successfully created!" << std::endl;
385                     g_cond.notify_all();
386                 }
387             }
388         }
389     }
390     catch (std::exception &e)
391     {
392         std::cerr << "Exception in foundResource: " << e.what() << std::endl;
393     }
394 }
395
396 // Callback to found resources
397 void foundSecuredResource(std::shared_ptr<OC::OCResource> resource)
398 {
399     std::string resourceURI;
400     std::string hostAddress;
401
402     try
403     {
404         // Do some operations with resource object.
405         if (resource && !curResource  &&
406             resource->getResourceTypes().at(0) == OC_RSRVD_ES_RES_TYPE_EASYSETUP)
407         {
408             std::cout << "DISCOVERED Resource:" << std::endl;
409             // Get the resource URI
410             resourceURI = resource->uri();
411             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
412
413             // Get the resource host address
414             hostAddress = resource->host();
415             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
416
417             // Get Resource Endpoint Infomation
418             std::cout << "\tList of resource endpoints: " << std::endl;
419             for (auto &resourceEndpoints : resource->getAllHosts())
420             {
421                 std::cout << "\t\t" << resourceEndpoints << std::endl;
422             }
423
424             // Get the resource types
425             std::cout << "\tList of resource types: " << std::endl;
426             for (auto &resourceTypes : resource->getResourceTypes())
427             {
428                 std::cout << "\t\t" << resourceTypes << std::endl;
429             }
430
431             // Get the resource interfaces
432             std::cout << "\tList of resource interfaces: " << std::endl;
433             for (auto &resourceInterfaces : resource->getResourceInterfaces())
434             {
435                 std::cout << "\t\t" << resourceInterfaces << std::endl;
436             }
437
438             if (curResource == nullptr)
439             {
440                 remoteEnrollee = nullptr;
441
442                 for (auto &resourceEndpoints : resource->getAllHosts())
443                 {
444                     if (std::string::npos != resourceEndpoints.find("coaps"))
445                     {
446                         std::string newHost = resourceEndpoints;
447                         // Change Resource host if another host exists
448                         std::cout << "\tChange host of resource endpoints" << std::endl;
449                         std::cout << "\t\t" << "Current host is "
450                                   << resource->setHost(newHost) << std::endl;
451                         remoteEnrollee = EasySetup::getInstance()->createRemoteEnrollee(resource);
452                         break;
453                     }
454                 }
455
456                 if (!remoteEnrollee)
457                 {
458                     std::cout << "RemoteEnrollee object is failed for some reasons!" << std::endl;
459                 }
460                 else
461                 {
462                     curResource = resource;
463                     std::cout << "RemoteEnrollee object is successfully created!" << std::endl;
464                     g_cond.notify_all();
465                 }
466             }
467         }
468     }
469     catch (std::exception &e)
470     {
471         std::cerr << "Exception in foundResource: " << e.what() << std::endl;
472     }
473 }
474
475 void discoveryEnrolleeResource(void (*f)(std::shared_ptr<OC::OCResource> resource))
476 {
477     try
478     {
479         std::ostringstream requestURI;
480         requestURI << OC_RSRVD_WELL_KNOWN_URI << "?rt=" << OC_RSRVD_ES_RES_TYPE_EASYSETUP;
481         OCPlatform::findResource("", requestURI.str(), CT_DEFAULT, f);
482         std::cout << "Finding Resource... " << std::endl;
483
484         std::unique_lock<std::mutex> lck(g_discoverymtx);
485         g_cond.wait_for(lck, std::chrono::seconds(5));
486     }
487     catch (OCException &e)
488     {
489         std::cout << "Exception in discoveryEnrolleeResource: " << e.what();
490     }
491 }
492
493 void DisplayMenu()
494 {
495     constexpr int DISCOVER_UNSECURED_ENROLLEE = 1;
496     constexpr int DISCOVER_SECURED_ENROLLEE = 2;
497     constexpr int PROVISION_SECURITY = 3;
498     constexpr int GET_STATUS = 4;
499     constexpr int GET_CONFIGURATION = 5;
500     constexpr int PROVISION_DEVICE_PROPERTY = 6;
501     constexpr int REQUEST_TO_CONNECT = 7;
502     constexpr int PROVISION_CLOUD_PROPERTY = 8;
503
504     std::cout << "========================================================\n";
505     std::cout << DISCOVER_UNSECURED_ENROLLEE << ". Discover Enrollee Resource \n";
506     std::cout << DISCOVER_SECURED_ENROLLEE << ". Discover Secured Enrollee Resource \n";
507     std::cout << PROVISION_SECURITY << ". Provision Security to Enrollee  \n";
508     std::cout << GET_STATUS << ". Get Status from Enrollee  \n";
509     std::cout << GET_CONFIGURATION << ". Get Configuration from Enrollee  \n";
510     std::cout << PROVISION_DEVICE_PROPERTY << ". Provision Device Property\n";
511     std::cout << REQUEST_TO_CONNECT << ". Request to Connect  \n";
512     std::cout << PROVISION_CLOUD_PROPERTY << ". Provision Cloud Property  \n";
513     std::cout << "========================================================\n";
514
515     int selection = processUserInput(DISCOVER_UNSECURED_ENROLLEE, PROVISION_CLOUD_PROPERTY);
516
517     switch (selection)
518     {
519         case DISCOVER_UNSECURED_ENROLLEE:
520             discoveryEnrolleeResource(&foundUnsecuredResource);
521             break;
522         case DISCOVER_SECURED_ENROLLEE:
523             discoveryEnrolleeResource(&foundSecuredResource);
524             break;
525         case PROVISION_SECURITY:
526             provisionSecurity();
527             break;
528         case GET_STATUS:
529             getStatus();
530             break;
531         case GET_CONFIGURATION:
532             getConfiguration();
533             break;
534         case PROVISION_DEVICE_PROPERTY:
535             provisionDeviceProperty();
536             break;
537         case REQUEST_TO_CONNECT:
538             requestToConnect();
539             break;
540         case PROVISION_CLOUD_PROPERTY:
541             provisionCloudProperty();
542             break;
543         default:
544             break;
545     };
546 }
547
548 static FILE *client_open(const char *path, const char *mode)
549 {
550     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
551     {
552         return fopen(JSON_DB_PATH, mode);
553     }
554     else
555     {
556         return fopen(path, mode);
557     }
558 }
559
560 int main()
561 {
562     OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
563
564     PlatformConfig config
565     {
566         OC::ServiceType::InProc, ModeType::Both, "0.0.0.0", 0, OC::QualityOfService::HighQos, &ps
567     };
568
569     OCPlatform::Configure(config);
570
571     try
572     {
573 #ifdef __WITH_DTLS__
574         //Initializing the provisioning client stack using the db path provided by the application.
575         OCStackResult result = OCSecure::provisionInit("");
576
577         if (result != OC_STACK_OK)
578         {
579             return -1;
580         }
581 #endif
582     }
583     catch (...)
584     {
585         std::cout << "Exception in main: " << std::endl;
586     }
587
588     while (true)
589     {
590         try
591         {
592             DisplayMenu();
593         }
594         catch (...)
595         {
596             std::cout << "Exception caught in main " << std::endl;
597         }
598     }
599
600     std::cout << "Stopping the client" << std::endl;
601
602     return 0;
603 }
604