Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / resource / provisioning / examples / provisioningclient.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 <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <string>
25 #include <map>
26 #include <cstdlib>
27 #include <pthread.h>
28 #include <mutex>
29 #include <condition_variable>
30
31 #include "logger.h"
32 #include "oic_malloc.h"
33 #include "oic_string.h"
34 #include "OCPlatform.h"
35 #include "OCApi.h"
36 #include "OCProvisioningManager.h"
37 #include "oxmjustworks.h"
38 #include "oxmrandompin.h"
39
40 #define MAX_URI_LENGTH (64)
41 #define MAX_PERMISSION_LENGTH (5)
42 #define CREATE (1)
43 #define READ (2)
44 #define UPDATE (4)
45 #define DELETE (8)
46 #define NOTIFY (16)
47 #define DASH '-'
48 #define PREDEFINED_TIMEOUT (10)
49 #define MAX_OWNED_DEVICE (10)
50 #define TAG  "provisioningclient"
51
52 #define JSON_DB_PATH "./oic_svr_db_client.json"
53 #define DAT_DB_PATH "./oic_svr_db_client.dat"
54 #define DEV_STATUS_ON "DEV_STATUS_ON"
55 #define DEV_STATUS_OFF "DEV_STATUS_OFF"
56
57 #define DISCOVERY_TIMEOUT 5
58
59 using namespace OC;
60
61 DeviceList_t pUnownedDevList, pOwnedDevList;
62 static int transferDevIdx, ask = 1;
63
64 static FILE* client_open(const char *UNUSED_PARAM, const char *mode)
65 {
66     (void)UNUSED_PARAM;
67     return fopen(DAT_DB_PATH, mode);
68 }
69
70 void printMenu()
71 {
72     std::cout << "\nChoose an option:"<<std::endl;
73     std::cout << "   1. UnOwned Device discovery"<<std::endl;
74     std::cout << "   2. Owned Device discovery"<<std::endl;
75     std::cout << "   3. Ownership transfer"<<std::endl;
76     std::cout << "   4. Provision ACL"<<std::endl;
77     std::cout << "   5. Provision Credentials"<<std::endl;
78     std::cout << "   6. Credential & ACL provisioning b/w two devices"<<std::endl;
79     std::cout << "   7. Unlink Devices"<<std::endl;
80     std::cout << "   8. Remove Device"<<std::endl;
81     std::cout << "   9. Get Linked Devices"<<std::endl;
82     std::cout << "   10. Get Device Status"<<std::endl;
83     std::cout << "   11. Exit loop"<<std::endl;
84 }
85
86 void moveTransferredDevice()
87 {
88     pOwnedDevList.push_back(pUnownedDevList[transferDevIdx]);
89     pUnownedDevList.erase(pUnownedDevList.begin() + transferDevIdx);
90 }
91
92 void InputPinCB(char* pinBuf, size_t bufSize)
93 {
94     if(pinBuf)
95     {
96         std::cout <<"INPUT PIN : ";
97         std::string ptr;
98         std::cin >> ptr;
99         OICStrcpy(pinBuf, bufSize, ptr.c_str());
100         return;
101     }
102 }
103
104 void printUuid(OicUuid_t uuid)
105 {
106     for (int i = 0; i < UUID_LENGTH; i++)
107     {
108         std::cout <<std::hex << uuid.id[i] << " ";
109     }
110     std::cout<<std::endl;
111 }
112
113 void ownershipTransferCB(PMResultList_t *result, int hasError)
114 {
115     if (hasError)
116     {
117         std::cout << "Error!!! in OwnershipTransfer"<<std::endl;
118     }
119     else
120     {
121         std::cout<< "\nTransferred Ownership successfuly for device : ";
122         printUuid(result->at(0).deviceId);
123         delete result;
124
125         moveTransferredDevice();
126     }
127     ask = 1;
128 }
129
130 void printStatus(int status)
131 {
132     static std::map<int, std::string> devStatus = {{1<<0, DEV_STATUS_ON}, {1<<1, DEV_STATUS_OFF}};
133
134     std::cout <<devStatus[status] <<std::endl;
135 }
136
137 void printDevices(DeviceList_t &list)
138 {
139    for (unsigned int i = 0; i < list.size(); i++ )
140    {
141       std::cout << "Device "<< i+1 <<" ID: ";
142       std::cout << list[i]->getDeviceID() << " From IP: ";
143       std::cout << list[i]->getDevAddr() << std::endl;
144    }
145 }
146
147 /**
148  * Callback function for provisioning ACL, Credentials.
149  *
150  * @param[in]    result Result list
151  * @param[in] hasError indicates if the result has error
152  */
153 void provisionCB(PMResultList_t *result, int hasError)
154 {
155    if (hasError)
156    {
157        std::cout << "Error in provisioning operation!"<<std::endl;
158    }
159    else
160    {
161        std::cout<< "\nReceived provisioning results: ";
162        for (unsigned int i = 0; i < result->size(); i++)
163        {
164            std::cout << "Result is = " << result->at(i).res <<" for device ";
165            printUuid(result->at(i).deviceId);
166        }
167
168        delete result;
169    }
170    printMenu();
171    ask = 1;
172 }
173 /**
174  *
175  * Ask user with which devices it wants to make further actions.
176  * All possible error checks included.
177  * Default behavior in case if only one options leaves are included too.
178  * Expect that user count devices from 1, f.e. 1st, 2nd, 3rd, etc
179  * Use DeviceList_t instead of devicesCount because of print devices info
180  *
181  * @param[in] list owned devices list.
182  * @param[out] out device number array.
183  * @param[in] count how many device numbers need to read.
184  * @return 0 in case of success and other value otherwise.
185  */
186 int readDeviceNumber(DeviceList_t &list, int count, int *out)
187 {
188    if (out == NULL || count <= 0)
189    {
190       std::cout << "Error! Please put valid input parameters" << std::endl;
191       return -1;
192    }
193
194    int devicesCount = list.size();
195
196    //Print current list of owned devices
197    std::cout <<"Owned devices, count = " << devicesCount << std::endl;
198    printDevices(list);
199
200    if (devicesCount < count)
201    {
202       std::cout << "You can't proceed with selected action because Owned devices count ( ";
203       std::cout << devicesCount << " ) are less then required devices ( " << count << " ).";
204       std::cout << "You may need to discover devices again" << std::endl;
205       return -2;
206    }
207
208    std::cout << "Select " << count << " device(s) for provisioning" << std::endl;
209
210    for (int curr = 0; curr < count; curr++)
211    {
212       //select last device by default if only 1 option exist
213       //from user's point of view device counting starts from 1,
214       //so 1st, 2nd, 3rd, etc devices
215       if ((curr == count - 1) && (devicesCount == count))
216       {
217          int sum = 0;
218          for (int i = 0; i < curr; i++)
219          {
220              sum += out[i];
221          }
222
223          out[curr] = (count*(count+1))/2 - sum;
224
225          std::cout << "Device " << curr + 1 << " : " << out[curr];
226          std::cout << " - selected automatically (because no other options exist)" << std::endl;
227          break;
228       }
229
230       int choice;
231       std::cout << "Device " << curr + 1 << " : ";
232       std::cin >> choice;
233
234       if (choice < 1 || choice > devicesCount)
235       {
236          std::cout << "Error! You should enter valid device number!" << std::endl;
237          return -3;
238       }
239
240       //check that user doesn't select the same device twice
241       for (int i = 0; i < curr; i++)
242       {
243          if (out[i] == choice)
244          {
245             std::cout << "Error! You cannot select the same device twice!" << std::endl;
246             return -4;
247          }
248       }
249
250       out[curr] = choice;
251    }
252
253    //Users count devices from 1, so 1st, 2nd, 3rd, etc device
254    //But deviceList array start index is 0, so need to decrease all numbers to 1
255    for (int i = 0; i < count; i++) out[i] -= 1;
256
257    return 0;
258 }
259
260 /**
261  * Perform cleanup for ACL
262  * @param[in]    ACL
263  */
264 static void deleteACL(OicSecAcl_t *acl)
265 {
266     if (acl)
267     {
268         /* Clean Resources */
269         for (unsigned int i = 0; i < (acl)->resourcesLen; i++)
270         {
271             OICFree((acl)->resources[i]);
272         }
273         OICFree((acl)->resources);
274
275         /* Clean ACL node itself */
276         /* Required only if acl was created in heap */
277         OICFree((acl));
278     }
279 }
280
281 /**
282  * Calculate ACL permission from string to bit
283  *
284  * @param[in] temp_psm    Input data of ACL permission string
285  * @param[in,out] pms    The pointer of ACL permission value
286  * @return  0 on success otherwise -1.
287  */
288 static int CalculateAclPermission(const char *temp_pms, uint16_t *pms)
289 {
290     int i = 0;
291
292     if (NULL == temp_pms || NULL == pms)
293     {
294         return -1;
295     }
296     *pms = 0;
297     while (temp_pms[i] != '\0')
298     {
299         switch (temp_pms[i])
300         {
301             case 'C':
302                 {
303                     *pms += CREATE;
304                     i++;
305                     break;
306                 }
307             case 'R':
308                 {
309                     *pms += READ;
310                     i++;
311                     break;
312                 }
313             case 'U':
314                 {
315                     *pms += UPDATE;
316                     i++;
317                     break;
318                 }
319             case 'D':
320                 {
321                     *pms += DELETE;
322                     i++;
323                     break;
324                 }
325             case 'N':
326                 {
327                     *pms += NOTIFY;
328                     i++;
329                     break;
330                 }
331             case '_':
332                 {
333                     i++;
334                     break;
335                 }
336             default:
337                 {
338                     return -1;
339                 }
340         }
341     }
342     return 0;
343 }
344
345 /**
346  * Get the ACL property from user
347  *
348  * @param[in]    ACL Datastructure to save user inputs
349  * @return  0 on success otherwise -1.
350  */
351 static int InputACL(OicSecAcl_t *acl)
352 {
353     int ret;
354     char *temp_id, *temp_rsc, *temp_pms;
355
356     printf("******************************************************************************\n");
357     printf("-Set ACL policy for target device\n");
358     printf("******************************************************************************\n");
359     //Set Subject.
360     printf("-URN identifying the subject\n");
361     printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n");
362     printf("Subject : ");
363     ret = scanf("%19ms", &temp_id);
364
365     if (1 == ret)
366     {
367         for (int i = 0, j = 0; temp_id[i] != '\0'; i++)
368         {
369             if (DASH != temp_id[i])
370                 acl->subject.id[j++] = temp_id[i];
371         }
372         OICFree(temp_id);
373     }
374     else
375     {
376         printf("Error while input\n");
377         return -1;
378     }
379
380     //Set Resource.
381     printf("Num. of Resource : ");
382     ret = scanf("%zu", &acl->resourcesLen);
383     if ((1 != ret) || (acl->resourcesLen <= 0 || acl->resourcesLen > 50))
384     {
385         printf("Error while input\n");
386         return -1;
387     }
388     printf("-URI of resource\n");
389     printf("ex)/oic/sh/temp/0 (Max_URI_Length: 64 Byte )\n");
390     acl->resources = (char **)OICCalloc(acl->resourcesLen, sizeof(char *));
391     if (NULL == acl->resources)
392     {
393         OIC_LOG(ERROR, TAG, "Error while memory allocation");
394         return -1;
395     }
396     for (size_t i = 0; i < acl->resourcesLen; i++)
397     {
398         printf("[%zu]Resource : ", i + 1);
399         ret = scanf("%64ms", &temp_rsc);
400         if (1 != ret)
401         {
402             printf("Error while input\n");
403             return -1;
404         }
405
406         acl->resources[i] = OICStrdup(temp_rsc);
407         OICFree(temp_rsc);
408         if (NULL == acl->resources[i])
409         {
410             OIC_LOG(ERROR, TAG, "Error while memory allocation");
411             return -1;
412         }
413     }
414     // Set Permission
415     do
416     {
417         printf("-Set the permission(C,R,U,D,N)\n");
418         printf("ex) CRUDN, CRU_N,..(5 Charaters)\n");
419         printf("Permission : ");
420         ret = scanf("%5ms", &temp_pms);
421         if (1 != ret)
422         {
423             printf("Error while input\n");
424             return -1;
425         }
426         ret = CalculateAclPermission(temp_pms, &(acl->permission));
427         OICFree(temp_pms);
428     } while (0 != ret );
429
430     // Set Rowner
431     printf("-URN identifying the rowner\n");
432     printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n");
433
434     printf("Rowner : ");
435     ret = scanf("%19ms", &temp_id);
436     if (1 != ret)
437     {
438         printf("Error while input\n");
439         return -1;
440     }
441
442     for (int k = 0, j = 0; temp_id[k] != '\0'; k++)
443     {
444         if (DASH != temp_id[k])
445         {
446             acl->rownerID.id[j++] = temp_id[k];
447         }
448     }
449     OICFree(temp_id);
450
451     return 0;
452 }
453
454 static int InputCredentials(Credential &cred)
455 {
456    int choice;
457
458    do
459    {
460        std::cout << "Select credential type from following values:" << std::endl;
461        std::cout << "1:  symmetric pair-wise key" << std::endl;
462        std::cout << "2:  symmetric group key" << std::endl;
463        std::cout << "4:  asymmetric key" << std::endl;
464        std::cout << "8:  signed asymmetric key (aka certificate)" << std::endl;
465        std::cout << "16: PIN /password" << std::endl;
466        std::cout << "Your choice: ";
467
468        std::cin >> choice;
469
470        switch (choice){
471            case 1:
472                cred.setCredentialType(static_cast<OicSecCredType_t>(choice));
473                choice = 0; //validation of the accepted choice.
474                break;
475            case 2:
476            case 4:
477            case 8:
478            case 16:
479                std::cout << "selected type is not supported yet" << std::endl;
480                break;
481            default:
482                std::cout << "Error! Please select valid credential type" << std::endl;
483                break;
484        }
485    } while(0 != choice);
486
487    std::cout << "Please enter key size (valid size is 128 or 256) :";
488    std::cin >> choice;
489
490    if(128 == choice)
491    {
492        cred.setCredentialKeySize(OWNER_PSK_LENGTH_128);
493    }
494    else if(256 == choice)
495    {
496         cred.setCredentialKeySize(OWNER_PSK_LENGTH_256);
497    }
498    else
499    {
500       std::cout << "Error! Please enter valid key size!" << std::endl;
501       return -2;
502    }
503
504    return 0;
505 }
506
507 int main(void)
508 {
509     OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
510
511     // Create PlatformConfig object
512     PlatformConfig cfg {
513         OC::ServiceType::InProc,
514             OC::ModeType::Both,
515             "0.0.0.0",
516             0,
517             OC::QualityOfService::LowQos,
518             &ps
519     };
520
521     OCPlatform::Configure(cfg);
522
523     try
524     {
525         int choice;
526         OicSecAcl_t *acl1 = nullptr, *acl2 = nullptr;
527         if (OCSecure::provisionInit("") != OC_STACK_OK)
528         {
529             std::cout <<"PM Init failed"<< std::endl;
530             return 1;
531         }
532
533         for (int out = 0; !out;)
534         {
535             while (!ask)
536             {
537                 sleep(1);
538             }
539
540             if (acl1)
541             {
542                 deleteACL(acl1);
543                 acl1 = nullptr;
544             }
545
546             if (acl2)
547             {
548                 deleteACL(acl2);
549                 acl2 = nullptr;
550             }
551
552             printMenu();
553             std::cin >> choice;
554             switch(choice) {
555                 case 1:
556                     {
557                         //Secure resource discovery.
558
559                         pUnownedDevList.clear();
560                         std::cout << "Started discovery..." <<std::endl;
561                         OCStackResult result = OCSecure::discoverUnownedDevices(DISCOVERY_TIMEOUT,
562                                 pUnownedDevList);
563                         if (result != OC_STACK_OK)
564                         {
565                             std::cout<< "!!Error - UnOwned Discovery failed."<<std::endl;
566                         }
567                         else if (pUnownedDevList.size())
568                         {
569                             std::cout <<"Found secure devices, count = " <<
570                                 pUnownedDevList.size() << std::endl;
571                             printDevices(pUnownedDevList);
572                         }
573                         else
574                         {
575                             std::cout <<"No Secure devices found"<<std::endl;
576                         }
577                         break;
578                     }
579                 case 2:
580                     {
581                         pOwnedDevList.clear();
582                         std::cout << "Started discovery..." <<std::endl;
583                         OCStackResult result = OCSecure::discoverOwnedDevices(DISCOVERY_TIMEOUT,
584                                 pOwnedDevList);
585                         if (result != OC_STACK_OK)
586                         {
587                             std::cout<< "!!Error - Owned Discovery failed."<<std::endl;
588                         }
589                         else if (pOwnedDevList.size())
590                         {
591                             std::cout <<"Found owned devices, count = " <<
592                                 pOwnedDevList.size() << std::endl;
593                             printDevices(pOwnedDevList);
594                         }
595                         else
596                         {
597                             std::cout <<"No Secure devices found"<<std::endl;
598                         }
599                         break;
600                     }
601                 case 3:
602                     {
603                         unsigned int devNum;
604
605                         if (!pUnownedDevList.size())
606                         {
607                             std::cout <<"There are no more Unowned devices"<<std::endl;
608                             break;
609                         }
610
611                         for (unsigned int i = 0; i < pUnownedDevList.size(); i++ )
612                         {
613                             std::cout << i+1 << ": "<< pUnownedDevList[i]->getDeviceID();
614                             std::cout << " From IP:" << pUnownedDevList[i]->getDevAddr() <<std::endl;
615                         }
616
617                         std::cout <<"Select device number: "<<std::endl;
618                         std::cin >> devNum;
619                         if (devNum > pUnownedDevList.size())
620                         {
621                             std::cout <<"Invalid device number"<<std::endl;
622                             break;
623                         }
624                         transferDevIdx = devNum - 1;
625
626                         //register callbacks for JUST WORKS and PIN methods
627                         std::cout <<"Registering OTM Methods: 1. JUST WORKS and 2. PIN"<<std::endl;
628
629                         {
630                             OTMCallbackData_t justWorksCBData;
631                             justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
632                             justWorksCBData.createSecureSessionCB =
633                                 CreateSecureSessionJustWorksCallback;
634                             justWorksCBData.createSelectOxmPayloadCB =
635                                 CreateJustWorksSelectOxmPayload;
636                             justWorksCBData.createOwnerTransferPayloadCB =
637                                 CreateJustWorksOwnerTransferPayload;
638                             OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS,
639                                     &justWorksCBData, NULL);
640                         }
641
642                         {
643                             OTMCallbackData_t pinBasedCBData;
644                             pinBasedCBData.loadSecretCB = InputPinCodeCallback;
645                             pinBasedCBData.createSecureSessionCB =
646                                 CreateSecureSessionRandomPinCallback;
647                             pinBasedCBData.createSelectOxmPayloadCB =
648                                 CreatePinBasedSelectOxmPayload;
649                             pinBasedCBData.createOwnerTransferPayloadCB =
650                                 CreatePinBasedOwnerTransferPayload;
651                             OCSecure::setOwnerTransferCallbackData(OIC_RANDOM_DEVICE_PIN,
652                                     &pinBasedCBData, InputPinCB);
653                         }
654
655                         ask = 0;
656                         std::cout << "Transfering ownership for : "<<
657                             pUnownedDevList[devNum-1]->getDeviceID()<<std::endl;
658                         if (pUnownedDevList[devNum-1]->doOwnershipTransfer(ownershipTransferCB)
659                                 != OC_STACK_OK)
660                         {
661                             std::cout<<"OwnershipTransferCallback is failed"<<std::endl;
662                             ask = 1;
663                         }
664                         break;
665                     }
666                 case 4: //Provision ACL
667                     {
668                         int index;
669
670                         if (0 != readDeviceNumber(pOwnedDevList, 1, &index)) break;
671
672                         std::cout << "Provision ACL for : "<<
673                             pOwnedDevList[index]->getDeviceID()<< std::endl;
674
675                         acl1 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t));
676                         if (NULL == acl1)
677                         {
678                             OIC_LOG(ERROR, TAG, "Error while memory allocation");
679                             break;
680                         }
681
682                         std::cout << "Please input ACL for selected device: " << std::endl;
683                         if (0 != InputACL(acl1))
684                         {
685                             break;
686                         }
687
688                         ask = 0;
689
690                         if (pOwnedDevList[index]->provisionACL(acl1, provisionCB) != OC_STACK_OK)
691                         {
692                             ask = 1;
693                             std::cout <<"provisionACL is failed"<< std::endl;
694                         }
695                     }
696                     break;
697                 case 5: //Provision Credentials
698                     {
699                         int devices[2];
700
701                         if (0 != readDeviceNumber(pOwnedDevList, 2, devices)) break;
702
703                         int first  = devices[0];
704                         int second = devices[1];
705
706                         std::cout << "Provision Credentials to devices: "<<
707                             pOwnedDevList[first]->getDeviceID();
708                         std::cout << " and "<< pOwnedDevList[second]->getDeviceID() << std::endl;
709
710                         Credential cred( NO_SECURITY_MODE ,0);
711                         std::cout << "Please input credentials for selected devices: " << std::endl;
712                         if (0 != InputCredentials(cred))
713                             break;
714
715                         ask = 0;
716
717                         if (pOwnedDevList[first]->provisionCredentials(cred,
718                                     *pOwnedDevList[second].get(), provisionCB) != OC_STACK_OK)
719                         {
720                             ask = 1;
721                             std::cout <<"provisionCredentials is failed"<< std::endl;
722                         }
723                     }
724                     break;
725                 case 6: //Provision ACL & Creds b/w two devices.
726                     {
727                         int devices[2];
728
729                         if (0 != readDeviceNumber(pOwnedDevList, 2, devices)) break;
730
731                         int first  = devices[0];
732                         int second = devices[1];
733
734                         std::cout << "Provision pairwise devices: "<<
735                             pOwnedDevList[first]->getDeviceID();
736                         std::cout << " and "<< pOwnedDevList[second]->getDeviceID() << std::endl;
737
738                         Credential cred( NO_SECURITY_MODE, 0);
739                         std::cout << "Please input credentials for selected devices: " << std::endl;
740                         if (0 != InputCredentials(cred))
741                             break;
742
743                         acl1 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t));
744                         if (NULL == acl1)
745                         {
746                             OIC_LOG(ERROR, TAG, "Error while memory allocation");
747                             break;
748                         }
749
750                         std::cout << "Please input ACL for selected device: " << std::endl;
751                         if (0 != InputACL(acl1))
752                         {
753                             break;
754                         }
755
756                         acl2 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t));
757                         if (NULL == acl2)
758                         {
759                             OIC_LOG(ERROR, TAG, "Error while memory allocation");
760                             break;
761                         }
762
763                         std::cout << "Please input ACL for selected device: " << std::endl;
764                         if (0 != InputACL(acl2))
765                         {
766                             break;
767                         }
768
769                         ask = 0;
770
771                         if (pOwnedDevList[first]->provisionPairwiseDevices(cred, acl1,
772                                     *pOwnedDevList[second].get(), acl2, provisionCB) != OC_STACK_OK)
773                         {
774                             ask = 1;
775                             std::cout <<"provisionPairwiseDevices is failed"<< std::endl;
776                         }
777                     }
778                     break;
779                 case 7: //Unlink Devices
780                     {
781                         int devices[2];
782
783                         if (0 != readDeviceNumber(pOwnedDevList, 2, devices)) break;
784
785                         int first  = devices[0];
786                         int second = devices[1];
787
788                         std::cout << "Unlink devices: "<< pOwnedDevList[first]->getDeviceID();
789                         std::cout << " and "<< pOwnedDevList[second]->getDeviceID() << std::endl;
790
791                         ask = 0;
792
793                         if (pOwnedDevList[first]->unlinkDevices(*pOwnedDevList[second].get(),
794                                     provisionCB) != OC_STACK_OK)
795                         {
796                             ask = 1;
797                             std::cout <<"unlinkDevice is failed"<< std::endl;
798                         }
799                         break;
800                     }
801                 case 8: //Remove Device
802                     {
803                         int index;
804
805                         if (0 != readDeviceNumber(pOwnedDevList, 1, &index)) break;
806
807                         std::cout << "Remove Device: "<< pOwnedDevList[index]->getDeviceID()<< std::endl;
808
809                         ask = 0;
810
811                         if (pOwnedDevList[index]->removeDevice(DISCOVERY_TIMEOUT, provisionCB)
812                                 != OC_STACK_OK)
813                         {
814                             ask = 1;
815                             std::cout <<"removeDevice is failed"<< std::endl;
816                         }
817                         break;
818                     }
819                 case 9: //Get Linked devices
820                     {
821                         UuidList_t linkedUuid;
822                         unsigned int devNum;
823
824                         if (!pOwnedDevList.size())
825                         {
826                             std::cout <<"There are no Owned devices yet,"
827                                 " may need to discover"<<std::endl;
828                             break;
829                         }
830
831                         for (unsigned int i = 0; i < pOwnedDevList.size(); i++ )
832                         {
833                             std::cout << i+1 << ": "<< pOwnedDevList[i]->getDeviceID() <<" From IP:";
834                             std::cout << pOwnedDevList[i]->getDevAddr() <<std::endl;
835                         }
836
837                         std::cout <<"Select device number: "<<std::endl;
838                         std::cin >> devNum;
839                         if (devNum > pOwnedDevList.size())
840                         {
841                             std::cout <<"Invalid device number"<<std::endl;
842                             break;
843                         }
844
845                         if(pOwnedDevList[devNum  -1]->getLinkedDevices(linkedUuid) == OC_STACK_OK)
846                         {
847                             if (!linkedUuid.size())
848                             {
849                                 std::cout <<"No devices are linked to "<<
850                                     pOwnedDevList[devNum  -1]->getDeviceID() << std::endl;
851                             }
852                             //display the Linked devices (UUIDs)
853                             for(unsigned int i = 0; i < linkedUuid.size(); i++)
854                             {
855                                 printUuid(linkedUuid[i]);
856                             }
857                         }
858                         else
859                         {
860                             std::cout <<"Error! in getLinkedDevices"<<std::endl;
861                         }
862                         break;
863                     }
864                 case 10: //Get device' status
865                     {
866                         DeviceList_t unownedList, ownedList;
867
868                         if (OCSecure::getDevInfoFromNetwork(DISCOVERY_TIMEOUT, ownedList,
869                                     unownedList) == OC_STACK_OK)
870                         {
871                             std::cout <<"Owned Device' status for" <<std::endl;
872                             for (unsigned int i = 0; i < ownedList.size(); i++ )
873                             {
874                                 std::cout << "Device "<<i+1 <<" ID: '";
875                                 std::cout << ownedList[i]->getDeviceID() << "' From IP: ";
876                                 std::cout << ownedList[i]->getDevAddr() << " Status: ";
877                                 printStatus(ownedList[i]->getDeviceStatus());
878                             }
879                             std::cout <<"\nUnOwned Device' status for" <<std::endl;
880                             for (unsigned int i = 0; i < unownedList.size(); i++ )
881                             {
882                                 std::cout << "Device "<<i+1 <<" ID: '";
883                                 std::cout << unownedList[i]->getDeviceID() << "' From IP: ";
884                                 std::cout << unownedList[i]->getDevAddr() << " Status: ";
885                                 printStatus(unownedList[i]->getDeviceStatus());
886                             }
887
888                         }
889                         break;
890                     }
891
892                 case 11:
893                 default:
894                     out = 1;
895                     break;
896             }
897         }
898     }
899     catch(OCException& e)
900     {
901         oclog() << "Exception in main: "<<e.what();
902     }
903
904     return 0;
905 }