Merge branch 'master' into windows-port
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / sample / provisioningclient.c
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 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26
27 #include "platform_features.h"
28 #include "logger.h"
29 #include "oic_malloc.h"
30 #include "oic_string.h"
31 #include "ocprovisioningmanager.h"
32 #include "oxmjustworks.h"
33 #include "oxmrandompin.h"
34 #include "securevirtualresourcetypes.h"
35 #include "srmutility.h"
36 #include "pmtypes.h"
37
38 #ifdef __cplusplus
39 extern "C"
40 {
41 #endif //__cplusplus
42
43 // declaration(s) for provisioning client using C-level provisioning API
44 // user input definition for main loop on provisioning client
45 #define _10_DISCOV_ALL_DEVS_    10
46 #define _11_DISCOV_UNOWN_DEVS_  11
47 #define _12_DISCOV_OWN_DEVS_    12
48 #define _20_REGIST_DEVS_        20
49 #define _30_PROVIS_PAIR_DEVS_   30
50 #define _31_PROVIS_CRED_        31
51 #define _32_PROVIS_ACL_         32
52 #define _33_PROVIS_DP_           33
53 #define _34_CHECK_LINK_STATUS_  34
54 #define _40_UNLINK_PAIR_DEVS_   40
55 #define _50_REMOVE_SELEC_DEV_   50
56 #define _99_EXIT_PRVN_CLT_      99
57
58 #define ACL_RESRC_MAX_NUM   16
59 #define ACL_RESRC_MAX_LEN   128
60 #define ACL_PEMISN_CNT      5
61 #define DISCOVERY_TIMEOUT   10  // 10 sec
62 #define CALLBACK_TIMEOUT    60  // 1 min
63 #define TAG "provisioningclient"
64
65 static const char* ACL_PEMISN[5] = {"CREATE", "READ", "WRITE", "DELETE", "NOTIFY"};
66 static const char* SVR_DB_FILE_NAME = "oic_svr_db_client.dat";
67         // '_' for separaing from the same constant variable in |srmresourcestrings.c|
68 static const char* PRVN_DB_FILE_NAME = "oic_prvn_mng.db";
69 static const OicSecPrm_t  SUPPORTED_PRMS[1] =
70 {
71     PRM_PRE_CONFIGURED,
72 };
73
74 // |g_ctx| means provision manager application context and
75 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
76 // for accessing all function(s) for these, they are declared on global domain
77 static const char* g_ctx = "Provision Manager Client Application Context";
78 static char* g_svr_fname;
79 static char* g_prvn_fname;
80 static OCProvisionDev_t* g_own_list;
81 static OCProvisionDev_t* g_unown_list;
82 static int g_own_cnt;
83 static int g_unown_cnt;
84 static bool g_doneCB;
85
86 // function declaration(s) for calling them before implementing
87 static OicSecAcl_t* createAcl(const int);
88 static OicSecPdAcl_t* createPdAcl(const int);
89 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
90 static int printDevList(const OCProvisionDev_t*);
91 static size_t printUuidList(const OCUuidList_t*);
92 static int printResultList(const OCProvisionResult_t*, const int);
93 static void printUuid(const OicUuid_t*);
94 static FILE* fopen_prvnMng(const char*, const char*);
95 static int waitCallbackRet(void);
96 static int selectTwoDiffNum(int*, int*, const int, const char*);
97
98 // callback function(s) for provisioning client using C-level provisioning API
99 static void ownershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
100 {
101     if(!hasError)
102     {
103         OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
104     }
105     else
106     {
107         OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
108         printResultList((const OCProvisionResult_t*) arr, nOfRes);
109     }
110     g_doneCB = true;
111 }
112
113 static void provisionPairwiseCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
114 {
115     if(!hasError)
116     {
117         OIC_LOG_V(INFO, TAG, "Provision Pairwise SUCCEEDED - ctx: %s", (char*) ctx);
118     }
119     else
120     {
121         OIC_LOG_V(ERROR, TAG, "Provision Pairwise FAILED - ctx: %s", (char*) ctx);
122         printResultList((const OCProvisionResult_t*) arr, nOfRes);
123     }
124     g_doneCB = true;
125 }
126
127 static void provisionCredCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
128 {
129     if(!hasError)
130     {
131         OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
132     }
133     else
134     {
135         OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
136         printResultList((const OCProvisionResult_t*) arr, nOfRes);
137     }
138     g_doneCB = true;
139 }
140
141 static void provisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
142 {
143     if(!hasError)
144     {
145         OIC_LOG_V(INFO, TAG, "Provision ACL SUCCEEDED - ctx: %s", (char*) ctx);
146     }
147     else
148     {
149         OIC_LOG_V(ERROR, TAG, "Provision ACL FAILED - ctx: %s", (char*) ctx);
150         printResultList((const OCProvisionResult_t*) arr, nOfRes);
151     }
152     g_doneCB = true;
153 }
154
155 static void provisionDPCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
156 {
157     if(!hasError)
158     {
159         OIC_LOG_V(INFO, TAG, "Provision Direct-Pairing SUCCEEDED - ctx: %s", (char*) ctx);
160     }
161     else
162     {
163         OIC_LOG_V(ERROR, TAG, "Provision Direct-Pairing FAILED - ctx: %s", (char*) ctx);
164         printResultList((const OCProvisionResult_t*) arr, nOfRes);
165     }
166     g_doneCB = true;
167 }
168
169 static void unlinkDevicesCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
170 {
171     if(!hasError)
172     {
173         OIC_LOG_V(INFO, TAG, "Unlink Devices SUCCEEDED - ctx: %s", (char*) ctx);
174     }
175     else
176     {
177         OIC_LOG_V(ERROR, TAG, "Unlink Devices FAILED - ctx: %s", (char*) ctx);
178         printResultList((const OCProvisionResult_t*) arr, nOfRes);
179     }
180     g_doneCB = true;
181 }
182
183 static void removeDeviceCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
184 {
185     if(!hasError)
186     {
187         OIC_LOG_V(INFO, TAG, "Remove Device SUCCEEDED - ctx: %s", (char*) ctx);
188     }
189     else
190     {
191         OIC_LOG_V(ERROR, TAG, "Remove Device FAILED - ctx: %s", (char*) ctx);
192         printResultList((const OCProvisionResult_t*) arr, nOfRes);
193     }
194     g_doneCB = true;
195 }
196
197 static void inputPinCB(char* pin, size_t len)
198 {
199     if(!pin || OXM_RANDOM_PIN_SIZE>=len)
200     {
201         OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
202         return;
203     }
204
205     printf("   > INPUT PIN: ");
206     for(int ret=0; 1!=ret; )
207     {
208         ret = scanf("%8s", pin);
209         for( ; 0x20<=getchar(); );  // for removing overflow garbages
210                                     // '0x20<=code' is character region
211     }
212 }
213
214 // function(s) for provisioning client using C-level provisioning API
215 static int initProvisionClient(void)
216 {
217     // initialize persistent storage for SVR DB
218     static OCPersistentStorage pstStr =
219     {
220         .open = fopen_prvnMng,
221         .read = fread,
222         .write = fwrite,
223         .close = fclose,
224         .unlink = unlink
225     };
226     if(OC_STACK_OK != OCRegisterPersistentStorageHandler(&pstStr))
227     {
228         OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
229         return -1;
230     }
231
232     // initialize OC stack and provisioning manager
233     if(OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
234     {
235         OIC_LOG(ERROR, TAG, "OCStack init error");
236         return -1;
237     }
238
239     if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
240     {
241         printf("************************************************************\n");
242         printf("************Provisioning DB file already exists.************\n");
243         printf("************************************************************\n");
244     }
245     else
246     {
247         printf("*************************************************************\n");
248         printf("************No provisioning DB file, creating new************\n");
249         printf("*************************************************************\n");
250     }
251
252     if(OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
253     {
254         OIC_LOG(ERROR, TAG, "OC_PM init error");
255         return -1;
256     }
257
258     // register callback function(s) to each OxM
259     OTMCallbackData_t otmcb =
260     {
261         .loadSecretCB = LoadSecretJustWorksCallback,
262         .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
263         .createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload,
264         .createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload
265     };
266     if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_JUST_WORKS, &otmcb))
267     {
268         OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_JUST_WORKS");
269         return -1;
270     }
271     otmcb.loadSecretCB = InputPinCodeCallback;
272     otmcb.createSecureSessionCB = CreateSecureSessionRandomPinCallback;
273     otmcb.createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload;
274     otmcb.createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload;
275     if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_RANDOM_DEVICE_PIN, &otmcb))
276     {
277         OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_RANDOM_DEVICE_PIN");
278         return -1;
279     }
280     SetInputPinCB(inputPinCB);
281
282     return 0;
283 }
284
285 static int discoverAllDevices(void)
286 {
287     // delete un/owned device lists before updating them
288     if(g_own_list)
289     {
290         OCDeleteDiscoveredDevices(g_own_list);
291         g_own_list = NULL;
292     }
293     if(g_unown_list)
294     {
295         OCDeleteDiscoveredDevices(g_unown_list);
296         g_unown_list = NULL;
297     }
298
299     // call |OCGetDevInfoFromNetwork| API actually
300     printf("   Discovering All Un/Owned Devices on Network..\n");
301     if(OC_STACK_OK != OCGetDevInfoFromNetwork(DISCOVERY_TIMEOUT, &g_own_list, &g_unown_list))
302     {
303         OIC_LOG(ERROR, TAG, "OCGetDevInfoFromNetwork API error");
304         return -1;
305     }
306
307     // display the discovered un/owned lists
308     printf("   > Discovered Owned Devices\n");
309     g_own_cnt = printDevList(g_own_list);
310     printf("   > Discovered Unowned Devices\n");
311     g_unown_cnt = printDevList(g_unown_list);
312
313     return 0;
314 }
315
316
317 static int discoverUnownedDevices(void)
318 {
319     // delete unowned device list before updating it
320     if(g_unown_list)
321     {
322         OCDeleteDiscoveredDevices(g_unown_list);
323         g_unown_list = NULL;
324     }
325
326     // call |OCDiscoverUnownedDevices| API actually
327     printf("   Discovering Only Unowned Devices on Network..\n");
328     if(OC_STACK_OK != OCDiscoverUnownedDevices(DISCOVERY_TIMEOUT, &g_unown_list))
329     {
330         OIC_LOG(ERROR, TAG, "OCDiscoverUnownedDevices API error");
331         return -1;
332     }
333
334     // display the discovered unowned list
335     printf("   > Discovered Unowned Devices\n");
336     g_unown_cnt = printDevList(g_unown_list);
337
338     return 0;
339 }
340
341 static int discoverOwnedDevices(void)
342 {
343     // delete owned device list before updating it
344     if(g_own_list)
345     {
346         OCDeleteDiscoveredDevices(g_own_list);
347         g_own_list = NULL;
348     }
349
350     // call |OCDiscoverOwnedDevices| API actually
351     printf("   Discovering Only Owned Devices on Network..\n");
352     if(OC_STACK_OK != OCDiscoverOwnedDevices(DISCOVERY_TIMEOUT, &g_own_list))
353     {
354         OIC_LOG(ERROR, TAG, "OCDiscoverOwnedDevices API error");
355         return -1;
356     }
357
358     // display the discovered owned list
359     printf("   > Discovered Owned Devices\n");
360     g_own_cnt = printDevList(g_own_list);
361
362     return 0;
363 }
364
365 static int registerDevices(void)
366 {
367     // check |unown_list| for registering devices
368     if(!g_unown_list || 0>=g_unown_cnt)
369     {
370         printf("   > Unowned Device List, to Register Devices, is Empty\n");
371         printf("   > Please Discover Unowned Devices first, with [10|11] Menu\n");
372         return 0;  // normal case
373     }
374
375     // call |OCDoOwnershipTransfer| API actually
376     // calling this API with callback actually acts like blocking
377     // for error checking, the return value saved and printed
378     g_doneCB = false;
379     printf("   Registering All Discovered Unowned Devices..\n");
380     OCStackResult rst = OCDoOwnershipTransfer((void*) g_ctx, g_unown_list, ownershipTransferCB);
381     if(OC_STACK_OK != rst)
382     {
383         OIC_LOG_V(ERROR, TAG, "OCDoOwnershipTransfer API error: %d", rst);
384         return -1;
385     }
386     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
387     {
388         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
389         return -1;
390     }
391
392     // display the registered result
393     printf("   > Registered Discovered Unowned Devices\n");
394     printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
395
396     return 0;
397 }
398
399 static int provisionPairwise(void)
400 {
401     // check |own_list| for provisioning pairwise devices
402     if(!g_own_list || 2>g_own_cnt)
403     {
404         printf("   > Owned Device List, to Provision the Pairwise, is Empty\n");
405         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
406         return 0;  // normal case
407     }
408
409     // select two devices for provisioning pairwise devices
410     int dev_num[2] = {0};
411     if(selectTwoDiffNum(&(dev_num[0]), &(dev_num[1]), g_own_cnt, "for Linking Devices"))
412     {
413         OIC_LOG(ERROR, TAG, "selectTwoDiffNum error return");
414         return -1;  // not need to 'goto' |ERROR| before allocating |acl|
415     }
416
417     // create ACL(s) for each selected device
418     OicSecAcl_t* acl[2] = {0};
419     for(int i=0; 2>i; ++i)
420     {
421         acl[i] = createAcl(dev_num[i]);
422         if(!acl[i])
423         {
424             OIC_LOG(ERROR, TAG, "createAcl error return");
425             goto PVPWS_ERROR;
426         }
427     }
428
429     // call |OCProvisionPairwiseDevices| API actually
430     // calling this API with callback actually acts like blocking
431     // for error checking, the return value saved and printed
432     g_doneCB = false;
433     printf("   Provisioning Selected Pairwise Devices..\n");
434     OCStackResult rst =
435             OCProvisionPairwiseDevices((void*) g_ctx,
436                     SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
437                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[0]), acl[0],
438                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[1]), acl[1],
439                     provisionPairwiseCB);
440     if(OC_STACK_OK != rst)
441     {
442         OIC_LOG_V(ERROR, TAG, "OCProvisionPairwiseDevices API error: %d", rst);
443         goto PVPWS_ERROR;
444     }
445     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
446     {
447         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
448         goto PVPWS_ERROR;
449     }
450     OCDeleteACLList(acl[0]);
451     OCDeleteACLList(acl[1]);
452
453     // display the pairwise-provisioned result
454     printf("   > Provisioned Selected Pairwise Devices\n");
455     printf("   > Please Check Device's Status for the Linked Result, with [33] Menu\n");
456
457     return 0;
458
459 PVPWS_ERROR:
460     OCDeleteACLList(acl[0]);
461     OCDeleteACLList(acl[1]);
462     return -1;
463 }
464
465 static int provisionCred(void)
466 {
467     // check |own_list| for provisioning pairwise credentials
468     if(!g_own_list || 2>g_own_cnt)
469     {
470         printf("   > Owned Device List, to Provision Credentials, is Empty\n");
471         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
472         return 0;  // normal case
473     }
474
475     // select two devices for provisioning pairwise credentials
476     int dev_num[2] = {0};
477     if(selectTwoDiffNum(&(dev_num[0]), &(dev_num[1]), g_own_cnt, "for Linking CRED(s)"))
478     {
479         OIC_LOG(ERROR, TAG, "selectTwoDiffNum error return");
480         return -1;
481     }
482
483     printf("   Select PSK length..\n");
484     printf("   1 - 128bit(Default)\n");
485     printf("   2 - 256bit\n");
486     int sizeOption = 0;
487
488     for(int ret=0; 1!=ret; )
489     {
490          ret = scanf("%d",&sizeOption);
491          for( ; 0x20<=getchar(); );  // for removing overflow garbages
492                                     // '0x20<=code' is character region
493     }
494     size_t size = 0;
495
496     switch(sizeOption)
497     {
498         case 1:
499         {
500             size = OWNER_PSK_LENGTH_128;
501             break;
502         }
503         case 2:
504         {
505             size = OWNER_PSK_LENGTH_256;
506             break;
507         }
508         default:
509         {
510             size = OWNER_PSK_LENGTH_128;
511             break;
512         }
513     }
514
515
516     // call |OCProvisionCredentials| API actually
517     // calling this API with callback actually acts like blocking
518     // for error checking, the return value saved and printed
519     g_doneCB = false;
520     printf("   Provisioning Selected Pairwise Credentials..\n");
521     OCStackResult rst =
522             OCProvisionCredentials((void*) g_ctx,
523                     SYMMETRIC_PAIR_WISE_KEY, size,
524                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[0]),
525                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[1]),
526                     provisionCredCB);
527     if(OC_STACK_OK != rst)
528     {
529         OIC_LOG_V(ERROR, TAG, "OCProvisionCredentials API error: %d", rst);
530         return -1;
531     }
532     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
533     {
534         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
535         return -1;
536     }
537
538     // display the CRED-provisioned result
539     printf("   > Provisioned Selected Pairwise Crendentials\n");
540     printf("   > Please Check Device's Status for the Linked Result, with [33] Menu\n");
541
542     return 0;
543 }
544
545 static int provisionAcl(void)
546 {
547     // check |own_list| for provisioning access control list
548     if(!g_own_list || 1>g_own_cnt)
549     {
550         printf("   > Owned Device List, to Provision ACL, is Empty\n");
551         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
552         return 0;  // normal case
553     }
554
555     // select device for provisioning access control list
556     int dev_num = 0;
557     for( ; ; )
558     {
559         printf("   > Enter Device Number, for Provisioning ACL: ");
560         for(int ret=0; 1!=ret; )
561         {
562             ret = scanf("%d", &dev_num);
563             for( ; 0x20<=getchar(); );  // for removing overflow garbages
564                                         // '0x20<=code' is character region
565         }
566         if(0<dev_num && g_own_cnt>=dev_num)
567         {
568             break;
569         }
570         printf("     Entered Wrong Number. Please Enter Again\n");
571     }
572
573     // create ACL for selected device
574     OicSecAcl_t* acl = NULL;
575     acl = createAcl(dev_num);
576     if(!acl)
577     {
578         OIC_LOG(ERROR, TAG, "createAcl error return");
579         goto PVACL_ERROR;
580     }
581
582     // call |OCProvisionACL| API actually
583     // calling this API with callback actually acts like blocking
584     // for error checking, the return value saved and printed
585     g_doneCB = false;
586     printf("   Provisioning Selected ACL..\n");
587     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
588     if(!dev)
589     {
590         OIC_LOG(ERROR, TAG, "provisionAcl: device instance empty");
591         goto PVACL_ERROR;
592     }
593     OCStackResult rst = OCProvisionACL((void*) g_ctx, dev, acl, provisionAclCB);
594     if(OC_STACK_OK != rst)
595     {
596         OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", rst);
597         goto PVACL_ERROR;
598     }
599     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
600     {
601         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
602         goto PVACL_ERROR;
603     }
604     OCDeleteACLList(acl);  // after here |acl| points nothing
605
606     // display the ACL-provisioned result
607     printf("   > Provisioned Selected ACL\n");
608
609     return 0;
610
611 PVACL_ERROR:
612     OCDeleteACLList(acl);  // after here |acl| points nothing
613     return -1;
614 }
615
616 static int provisionDirectPairing(void)
617 {
618     // check |own_list| for provisioning direct-pairing
619     if(!g_own_list || 1>g_own_cnt)
620     {
621         printf("   > Owned Device List, to Provision ACL, is Empty\n");
622         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
623         return 0;  // normal case
624     }
625
626     // select device for provisioning direct-pairing
627     int dev_num = 0;
628     for( ; ; )
629     {
630         printf("   > Enter Device Number, for Provisioning Direct-Pairing: ");
631         for(int ret=0; 1!=ret; )
632         {
633             ret = scanf("%d", &dev_num);
634             for( ; 0x20<=getchar(); );  // for removing overflow garbages
635                                         // '0x20<=code' is character region
636         }
637         if(0<dev_num && g_own_cnt>=dev_num)
638         {
639             break;
640         }
641         printf("     Entered Wrong Number. Please Enter Again\n");
642     }
643
644     // create Direct-Pairing Configuration(PIN, PDACL) for selected device
645     // TODO: default acl -> input from user !
646     OicSecPconf_t pconf;
647     memset(&pconf, 0, sizeof(OicSecPconf_t));
648
649     // set enable dp
650     pconf.edp = true;
651
652     // set default supported PRM types
653     pconf.prmLen = sizeof(SUPPORTED_PRMS)/sizeof(OicSecPrm_t);
654     pconf.prm = (OicSecPrm_t *)OICCalloc(pconf.prmLen, sizeof(OicSecPrm_t));
655     if(pconf.prm)
656     {
657         for (size_t i=0; i<pconf.prmLen; i++)
658         {
659             pconf.prm[i] = SUPPORTED_PRMS[i];
660         }
661     }
662     else
663     {
664         OIC_LOG(ERROR, TAG, "create prm error return");
665         goto PVDP_ERROR;
666     }
667
668     // set default pin
669     const char DP_DEFAULT_PIN[] = "00000000";
670     memcpy(pconf.pin.val, DP_DEFAULT_PIN, DP_PIN_LENGTH);
671
672     // set default pdacl
673     pconf.pdacls = createPdAcl(dev_num);
674     if(!pconf.pdacls)
675     {
676         OIC_LOG(ERROR, TAG, "createPdAcl error return");
677         goto PVDP_ERROR;
678     }
679
680     // call |OCProvisionDirectPairing| API actually
681     // calling this API with callback actually acts like blocking
682     // for error checking, the return value saved and printed
683     g_doneCB = false;
684     printf("   Atempt Direct-Pairing Provisioning (PIN : [%s])..\n", (char*)pconf.pin.val);
685     OCStackResult rst = OCProvisionDirectPairing((void*) g_ctx,
686                                        getDevInst((const OCProvisionDev_t*) g_own_list, dev_num),
687                                        &pconf, provisionDPCB);
688     if(OC_STACK_OK != rst)
689     {
690         OIC_LOG_V(ERROR, TAG, "OCProvisionDirectPairing API error: %d", rst);
691         if (OC_STACK_UNAUTHORIZED_REQ == rst)
692         {
693             OIC_LOG(ERROR, TAG, "Target Server NOT Support Direct-Pairing !!! (DPC == false)");
694         }
695         goto PVDP_ERROR;
696     }
697     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
698     {
699         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
700         goto PVDP_ERROR;
701     }
702     OCDeletePdAclList(pconf.pdacls);
703
704     // display the PCONF-provisioned result
705     printf("   > SUCCESS to provision Direct-Pairing !!\n");
706
707     return 0;
708
709 PVDP_ERROR:
710     OCDeletePdAclList(pconf.pdacls);  // after here |acl| points nothing
711     return -1;
712 }
713
714 static int checkLinkedStatus(void)
715 {
716     // check |own_list| for checking selected link status on PRVN DB
717     if(!g_own_list || 1>g_own_cnt)
718     {
719         printf("   > Owned Device List, to Check Linked Status on PRVN DB, is Empty\n");
720         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
721         return 0;  // normal case
722     }
723
724     // select device for checking selected link status on PRVN DB
725     int dev_num = 0;
726     for( ; ; )
727     {
728         printf("   > Enter Device Number, for Checking Linked Status on PRVN DB: ");
729         for(int ret=0; 1!=ret; )
730         {
731             ret = scanf("%d", &dev_num);
732             for( ; 0x20<=getchar(); );  // for removing overflow garbages
733                                         // '0x20<=code' is character region
734         }
735         if(0<dev_num && g_own_cnt>=dev_num)
736         {
737             break;
738         }
739         printf("     Entered Wrong Number. Please Enter Again\n");
740     }
741
742     // call |OCGetLinkedStatus| API actually
743     printf("   Checking Selected Link Status on PRVN DB..\n");
744     OCUuidList_t* dvid_lst = NULL;
745     size_t dvid_cnt = 0;
746     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
747     if(!dev || !dev->doxm)
748     {
749         OIC_LOG(ERROR, TAG, "checkLinkedStatus: device instance empty");
750         goto CKLST_ERROR;
751     }
752
753     if(OC_STACK_OK !=
754             OCGetLinkedStatus(
755                     &dev->doxm->deviceID,
756                     &dvid_lst, &dvid_cnt))  // allow empty list
757     {
758         OIC_LOG(ERROR, TAG, "OCGetLinkedStatus API error");
759         goto CKLST_ERROR;
760     }
761
762     // display the linked status result
763     printf("   > Checked Selected Link Status on PRVN DB\n");
764     if(!dvid_lst || !dvid_cnt)  // |size_t| is unsigned
765     {
766         printf("     Linked Device List is Empty..\n");
767         return 0;  // normal case
768     }
769     if(dvid_cnt != printUuidList((const OCUuidList_t*) dvid_lst))
770     {
771         OIC_LOG(ERROR, TAG, "printUuidList error return");
772         goto CKLST_ERROR;
773     }
774     OCDeleteUuidList(dvid_lst);
775
776     return 0;
777
778 CKLST_ERROR:
779     OCDeleteUuidList(dvid_lst);
780     return -1;
781 }
782
783 static int unlinkPairwise(void)
784 {
785     // check |own_list| for unlinking pairwise devices
786     if(!g_own_list || 2>g_own_cnt)
787     {
788         printf("   > Owned Device List, to Unlink the Pairwise, is Empty\n");
789         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
790         return 0;  // normal case
791     }
792
793     // select two devices for unlinking pairwise devices
794     int dev_num[2] = {0};
795     if(selectTwoDiffNum(&(dev_num[0]), &(dev_num[1]), g_own_cnt, "for Unlinking Devices"))
796     {
797         OIC_LOG(ERROR, TAG, "selectTwoDiffNum error return");
798         return -1;
799     }
800
801     // call |OCUnlinkDevices| API actually
802     // calling this API with callback actually acts like blocking
803     // for error checking, the return value saved and printed
804     g_doneCB = false;
805     printf("   Unlinking Selected Pairwise Devices..\n");
806     OCStackResult rst =
807             OCUnlinkDevices((void*) g_ctx,
808                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[0]),
809                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[1]),
810                     unlinkDevicesCB);
811     if(OC_STACK_OK != rst)
812     {
813         OIC_LOG_V(ERROR, TAG, "OCUnlinkDevices API error: %d", rst);
814         return -1;
815     }
816     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
817     {
818         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
819         return -1;
820     }
821
822     // display the pairwise-unlinked result
823     printf("   > Unlinked Selected Pairwise Devices\n");
824     printf("   > Please Check Device's Status for the Unlinked Result, with [33] Menu\n");
825
826     return 0;
827 }
828
829 static int removeDevice(void)
830 {
831     // check |own_list| for removing device
832     if(!g_own_list || 1>g_own_cnt)
833     {
834         printf("   > Owned Device List, to Remove Device, is Empty\n");
835         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
836         return 0;  // normal case
837     }
838
839     // select device for removing it
840     int dev_num = 0;
841     for( ; ; )
842     {
843         printf("   > Enter Device Number, for Removing Device: ");
844         for(int ret=0; 1!=ret; )
845         {
846             ret = scanf("%d", &dev_num);
847             for( ; 0x20<=getchar(); );  // for removing overflow garbages
848                                         // '0x20<=code' is character region
849         }
850         if(0<dev_num && g_own_cnt>=dev_num)
851         {
852             break;
853         }
854         printf("     Entered Wrong Number. Please Enter Again\n");
855     }
856
857     // call |OCRemoveDevice| API actually
858     // calling this API with callback actually acts like blocking
859     // for error checking, the return value saved and printed
860     g_doneCB = false;
861     printf("   Removing Selected Owned Device..\n");
862     OCStackResult rst =
863             OCRemoveDevice((void*) g_ctx, DISCOVERY_TIMEOUT,
864                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num), removeDeviceCB);
865     if(OC_STACK_OK != rst)
866     {
867         OIC_LOG_V(ERROR, TAG, "OCRemoveDevice API error: %d", rst);
868         return -1;
869     }
870     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
871     {
872         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
873         return -1;
874     }
875
876     // display the removed result
877     printf("   > Removed Selected Owned Device\n");
878     printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
879
880     return 0;
881 }
882
883 static OicSecAcl_t* createAcl(const int dev_num)
884 {
885     if(0>=dev_num || g_own_cnt<dev_num)
886     {
887         OIC_LOG(ERROR, TAG, "createAcl invalid parameters");
888         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
889     }
890
891     // allocate memory for |acl| struct
892     printf("   **** Create ACL for the Selected Device[%d]\n", dev_num);
893     OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
894     if(!acl)
895     {
896         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
897         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
898     }
899
900     // enter |subject| device number
901     int num = 0;
902     for( ; ; )
903     {
904         printf("   > [A] Enter Subject Device Number: ");
905         for(int ret=0; 1!=ret; )
906         {
907             ret = scanf("%d", &num);
908             for( ; 0x20<=getchar(); );  // for removing overflow garbages
909                                         // '0x20<=code' is character region
910         }
911         if(0<num && g_own_cnt>=num && dev_num!=num)
912         {
913             break;
914         }
915         printf("     Entered Wrong Number. Please Enter Again\n");
916     }
917
918     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, num);
919     if(!dev || !dev->doxm)
920     {
921         OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
922         goto CRACL_ERROR;
923     }
924     memcpy(&acl->subject, &dev->doxm->deviceID, UUID_LENGTH);
925
926     // enter number of |resources| in 'accessed' device
927     for( ; ; )
928     {
929         printf("   > [B] Enter Number of Accessed Resources (under 16): ");
930                 // '16' is |ACL_RESRC_MAX_NUM|
931         for(int ret=0; 1!=ret; )
932         {
933             ret = scanf("%d", &num);
934             for( ; 0x20<=getchar(); );  // for removing overflow garbages
935                                         // '0x20<=code' is character region
936         }
937         if(0<num && ACL_RESRC_MAX_NUM>=num)
938         {
939             break;
940         }
941         printf("     Entered Wrong Number. Please Enter under 16 Again\n");
942                 // '16' is |ACL_RESRC_MAX_NUM|
943     }
944
945     // enter actually each 'accessed' |resources| name
946     printf("         Enter Each Accessed Resource Name (each under 128 char)\n");
947             // '128' is ACL_RESRC_MAX_LEN
948     acl->resourcesLen = (unsigned) num;
949     acl->resources = (char**) OICCalloc(acl->resourcesLen, sizeof(char*));
950     if(!acl->resources)
951     {
952         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
953         goto CRACL_ERROR;
954     }
955     char rsrc_in[ACL_RESRC_MAX_LEN+1] = {0};  // '1' for null termination
956     for(int i=0; acl->resourcesLen>(unsigned)i; ++i)
957     {
958         printf("         Enter Accessed Resource[%d] Name: ", i+1);
959         for(int ret=0; 1!=ret; )
960         {
961             ret = scanf("%128s", rsrc_in);  // '128' is ACL_RESRC_MAX_LEN
962             for( ; 0x20<=getchar(); );  // for removing overflow garbages
963                                         // '0x20<=code' is character region
964         }
965         size_t len = strlen(rsrc_in)+1;  // '1' for null termination
966         char* rsrc = (char*) OICCalloc(len, sizeof(char));
967         if(!rsrc)
968         {
969             OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
970             goto CRACL_ERROR;
971         }
972         OICStrcpy(rsrc, len, rsrc_in);
973         acl->resources[i] = rsrc;  // after here, |rsrc| points nothing
974     }
975
976     // enter |permission| for this access
977     printf("   > [C] Enter Permission for This Access\n");
978     uint16_t pmsn = PERMISSION_FULL_CONTROL;  // default full permission
979     uint16_t pmsn_msk = PERMISSION_CREATE;  // default permission mask
980     for(int i=0; ACL_PEMISN_CNT>i; ++i)
981     {
982         char ans = 0;
983         for( ; ; )
984         {
985             printf("         Enter %s Permission (y/n): ", ACL_PEMISN[i]);
986             for(int ret=0; 1!=ret; )
987             {
988                 ret = scanf("%c", &ans);
989                 for( ; 0x20<=getchar(); );  // for removing overflow garbages
990                                             // '0x20<=code' is character region
991             }
992             if('y'==ans || 'Y'==ans || 'n'==ans|| 'N'==ans)
993             {
994                 ans &= ~0x20;  // for masking lower case, 'y/n'
995                 break;
996             }
997             printf("         Entered Wrong Answer. Please Enter 'y/n' Again\n");
998         }
999         if('N' == ans)  // masked lower case, 'n'
1000         {
1001             pmsn -= pmsn_msk;
1002         }
1003         pmsn_msk <<= 1;
1004     }
1005     acl->permission = pmsn;
1006
1007     // enter |owner| device number
1008     int own_num = 0;
1009     for( ; ; )
1010     {
1011         printf("   > [D] Enter Owner Device Number: ");
1012         for(int ret=0; 1!=ret; )
1013         {
1014             ret = scanf("%d", &own_num);
1015             for( ; 0x20<=getchar(); );  // for removing overflow garbages
1016                                         // '0x20<=code' is character region
1017         }
1018         if(0<own_num && g_own_cnt>=own_num)
1019         {
1020             break;
1021         }
1022         printf("         Entered Wrong Number. Please Enter Again\n");
1023     }
1024
1025     dev = getDevInst((const OCProvisionDev_t*)g_own_list, own_num);
1026     if(!dev || !dev->doxm)
1027     {
1028         OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
1029         goto CRACL_ERROR;
1030     }
1031     memcpy(&acl->rownerID, &dev->doxm->deviceID, sizeof(OicUuid_t));
1032     printf("\n");
1033
1034     return acl;
1035
1036 CRACL_ERROR:
1037     OCDeleteACLList(acl);  // after here |acl| points nothing
1038     return NULL;
1039 }
1040
1041 static OicSecPdAcl_t* createPdAcl(const int dev_num)
1042 {
1043     if(0>=dev_num || g_own_cnt<dev_num)
1044     {
1045         OIC_LOG(ERROR, TAG, "createAcl invalid parameters");
1046         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
1047     }
1048
1049     // allocate memory for |pdacl| struct
1050     printf("   **** Create PDACL for the Selected Device[%d]\n", dev_num);
1051     OicSecPdAcl_t* pdAcl = (OicSecPdAcl_t*) OICCalloc(1, sizeof(OicSecPdAcl_t));
1052     if(!pdAcl)
1053     {
1054         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
1055         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
1056     }
1057
1058
1059     // number of resources
1060     char rsrc_in[][ACL_RESRC_MAX_LEN+1] = {"*", "/rsrc/*"};
1061     pdAcl->resourcesLen = 1;
1062
1063     // resource
1064     int num = pdAcl->resourcesLen;
1065     pdAcl->resources = (char**) OICCalloc(num, sizeof(char*));
1066     if(!pdAcl->resources)
1067     {
1068         OIC_LOG(ERROR, TAG, "createPdAcl: OICCalloc error return");
1069         goto CRPDACL_ERROR;
1070     }
1071     for(int i=0; num>i; ++i)
1072     {
1073         size_t len = strlen(rsrc_in[i])+1;  // '1' for null termination
1074         char* rsrc = (char*) OICCalloc(len, sizeof(char));
1075         if(!rsrc)
1076         {
1077             OIC_LOG(ERROR, TAG, "createPdAcl: OICCalloc error return");
1078             goto CRPDACL_ERROR;
1079         }
1080         OICStrcpy(rsrc, len, rsrc_in[i]);
1081         pdAcl->resources[i] = rsrc;  // after here, |rsrc| points nothing
1082     }
1083
1084     // permission
1085     pdAcl->permission = PERMISSION_FULL_CONTROL;
1086
1087     return pdAcl;
1088
1089 CRPDACL_ERROR:
1090     OCDeletePdAclList(pdAcl);
1091     return NULL;
1092 }
1093
1094 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
1095 {
1096     if(!dev_lst || 0>=dev_num)
1097     {
1098         printf("     Device List is Empty..\n");
1099         return NULL;
1100     }
1101
1102     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
1103     for(int i=0; lst; )
1104     {
1105         if(dev_num == ++i)
1106         {
1107             return lst;
1108         }
1109         lst = lst->next;
1110     }
1111
1112     return NULL;  // in here |lst| is always |NULL|
1113 }
1114
1115 static int printDevList(const OCProvisionDev_t* dev_lst)
1116 {
1117     if(!dev_lst)
1118     {
1119         printf("     Device List is Empty..\n\n");
1120         return 0;
1121     }
1122
1123     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
1124     int lst_cnt = 0;
1125     for( ; lst; )
1126     {
1127         printf("     [%d] ", ++lst_cnt);
1128         printUuid((const OicUuid_t*) &lst->doxm->deviceID);
1129         printf("\n");
1130         lst = lst->next;
1131     }
1132     printf("\n");
1133
1134     return lst_cnt;
1135 }
1136
1137 static size_t printUuidList(const OCUuidList_t* uid_lst)
1138 {
1139     if(!uid_lst)
1140     {
1141         printf("     Device List is Empty..\n\n");
1142         return 0;
1143     }
1144
1145     OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
1146     size_t lst_cnt = 0;
1147     for( ; lst; )
1148     {
1149         printf("     [%zu] ", ++lst_cnt);
1150         printUuid((const OicUuid_t*) &lst->dev);
1151         printf("\n");
1152         lst = lst->next;
1153     }
1154     printf("\n");
1155
1156     return lst_cnt;
1157 }
1158
1159 static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
1160 {
1161     if(!rslt_lst || 0>=rslt_cnt)
1162     {
1163         printf("     Device List is Empty..\n\n");
1164         return 0;
1165     }
1166
1167     int lst_cnt = 0;
1168     for( ; rslt_cnt>lst_cnt; ++lst_cnt)
1169     {
1170         printf("     [%d] ", lst_cnt+1);
1171         printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
1172         printf(" - result: %d\n", rslt_lst[lst_cnt].res);
1173     }
1174     printf("\n");
1175
1176     return lst_cnt;
1177 }
1178
1179 static void printUuid(const OicUuid_t* uid)
1180 {
1181     for(int i=0; i<UUID_LENGTH; )
1182     {
1183         printf("%02X", (*uid).id[i++]);
1184         if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
1185         {
1186             printf("-");
1187         }
1188     }
1189 }
1190
1191 static FILE* fopen_prvnMng(const char* path, const char* mode)
1192 {
1193     (void)path;  // unused |path| parameter
1194
1195     // input |g_svr_db_fname| internally by force, not using |path| parameter
1196     // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
1197     // with its own |SVR_DB_FILE_NAME|
1198     return fopen(SVR_DB_FILE_NAME, mode);
1199 }
1200
1201 static int waitCallbackRet(void)
1202 {
1203     for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
1204     {
1205         sleep(1);
1206         if(OC_STACK_OK != OCProcess())
1207         {
1208             OIC_LOG(ERROR, TAG, "OCStack process error");
1209             return -1;
1210         }
1211     }
1212
1213     return 0;
1214 }
1215
1216 static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
1217 {
1218     if(!a || !b || 2>=max || !str)
1219     {
1220         return -1;
1221     }
1222
1223     for( ; ; )
1224     {
1225         for(int i=0; 2>i; ++i)
1226         {
1227             int* num = 0==i?a:b;
1228             for( ; ; )
1229             {
1230                 printf("   > Enter Device[%d] Number, %s: ", i+1, str);
1231                 for(int ret=0; 1!=ret; )
1232                 {
1233                     ret = scanf("%d", num);
1234                     for( ; 0x20<=getchar(); );  // for removing overflow garbages
1235                                                 // '0x20<=code' is character region
1236                 }
1237                 if(0<*num && max>=*num)
1238                 {
1239                     break;
1240                 }
1241                 printf("     Entered Wrong Number. Please Enter Again\n");
1242             }
1243         }
1244         if(*a != *b)
1245         {
1246             printf("\n");
1247             return 0;
1248         }
1249     }
1250
1251     return -1;
1252 }
1253
1254 static void printMenu(void)
1255 {
1256     printf("************************************************************\n");
1257     printf("****** OIC Provisioning Client with using C-level API ******\n");
1258     printf("************************************************************\n\n");
1259
1260     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
1261     printf("** 10. Discover All Un/Owned Devices on Network\n");
1262     printf("** 11. Discover Only Unowned Devices on Network\n");
1263     printf("** 12. Discover Only Owned Devices on Network\n\n");
1264
1265     printf("** [B] REGISTER/OWN ALL DISCOVERED UNOWNED DEVICES\n");
1266     printf("** 20. Register/Own All Discovered Unowned Devices\n\n");
1267
1268     printf("** [C] PROVISION/LINK PAIRWISE THINGS\n");
1269     printf("** 30. Provision/Link Pairwise Things\n");
1270     printf("** 31. Provision Credentials for Pairwise Things\n");
1271     printf("** 32. Provision the Selected Access Control List(ACL)\n");
1272     printf("** 33. Provision Direct-Pairing Configuration\n");
1273     printf("** 34. Check Linked Status of the Selected Device on PRVN DB\n\n");
1274
1275     printf("** [D] UNLINK PAIRWISE THINGS\n");
1276     printf("** 40. Unlink Pairwise Things\n\n");
1277
1278     printf("** [E] REMOVE THE SELECTED DEVICE\n");
1279     printf("** 50. Remove the Selected Device\n\n");
1280
1281     printf("** [F] EXIT PROVISIONING CLIENT\n");
1282     printf("** 99. Exit Provisionong Client\n\n");
1283
1284     printf("************************************************************\n\n");
1285 }
1286
1287 #if 0 // Code for enabling path configuration for PDB and SVR DBf
1288 static void printUsage(void)
1289 {
1290     printf("\n");
1291     printf("OIC Provisioning Client with using C-level API\n");
1292     printf("Usage: provisioningclient [option]...\n");
1293     printf("\n");
1294     printf("  -h                           print help for this provisioning client\n");
1295     printf("  -p=[prvn_db_file_path/name]  input PRVN DB file path and name\n");
1296     printf("                               if not exists, will load default DB file\n");
1297     printf("                               (default: |oic_prvn_mng.db| on working dir)\n");
1298     printf("                               (ex. -p=oic_prvn_mng.db)\n");
1299     printf("  -s=[svr_db_file_path/name]   input SVR DB file path and name\n");
1300     printf("                               if not exists, will load default DB file\n");
1301     printf("                               (default: |oic_svr_db_client.json| on working dir)\n");
1302     printf("                               (ex. -s=oic_svr_db_client.json)\n");
1303     printf("\n");
1304 }
1305 #endif
1306
1307 // main function for provisioning client using C-level provisioning API
1308 int main()
1309 {
1310     // initialize provisioning client
1311     if(initProvisionClient())
1312     {
1313         OIC_LOG(ERROR, TAG, "ProvisionClient init error");
1314         goto PMCLT_ERROR;
1315     }
1316
1317     // main loop for provisioning manager
1318     int mn_num = 0;
1319     for( ; ; )
1320     {
1321         printf("\n");
1322         printMenu();
1323         printf(">> Enter Menu Number: ");
1324         for(int ret=0; 1!=ret; )
1325         {
1326             ret = scanf("%d", &mn_num);
1327             for( ; 0x20<=getchar(); );  // for removing overflow garbages
1328                                         // '0x20<=code' is character region
1329         }
1330         printf("\n");
1331         switch(mn_num)
1332         {
1333         case _10_DISCOV_ALL_DEVS_:
1334             if(discoverAllDevices())
1335             {
1336                 OIC_LOG(ERROR, TAG, "_10_DISCOV_ALL_DEVS_: error");
1337             }
1338             break;
1339         case _11_DISCOV_UNOWN_DEVS_:
1340             if(discoverUnownedDevices())
1341             {
1342                 OIC_LOG(ERROR, TAG, "_11_DISCOV_UNOWN_DEVS_: error");
1343             }
1344             break;
1345         case _12_DISCOV_OWN_DEVS_:
1346             if(discoverOwnedDevices())
1347             {
1348                 OIC_LOG(ERROR, TAG, "_12_DISCOV_OWN_DEVS_: error");
1349             }
1350             break;
1351         case _20_REGIST_DEVS_:
1352             if(registerDevices())
1353             {
1354                 OIC_LOG(ERROR, TAG, "_20_REGIST_DEVS_: error");
1355             }
1356             break;
1357         case _30_PROVIS_PAIR_DEVS_:
1358             if(provisionPairwise())
1359             {
1360                 OIC_LOG(ERROR, TAG, "_30_PROVIS_PAIR_DEVS_: error");
1361             }
1362             break;
1363         case _31_PROVIS_CRED_:
1364             if(provisionCred())
1365             {
1366                 OIC_LOG(ERROR, TAG, "_31_PROVIS_CRED_: error");
1367             }
1368             break;
1369         case _32_PROVIS_ACL_:
1370             if(provisionAcl())
1371             {
1372                 OIC_LOG(ERROR, TAG, "_32_PROVIS_ACL_: error");
1373             }
1374             break;
1375         case _33_PROVIS_DP_:
1376             if(provisionDirectPairing())
1377             {
1378                 OIC_LOG(ERROR, TAG, "_33_PROVIS_DP_: error");
1379             }
1380             break;
1381         case _34_CHECK_LINK_STATUS_:
1382             if(checkLinkedStatus())
1383             {
1384                 OIC_LOG(ERROR, TAG, "_34_CHECK_LINK_STATUS_: error");
1385             }
1386             break;
1387         case _40_UNLINK_PAIR_DEVS_:
1388             if(unlinkPairwise())
1389             {
1390                 OIC_LOG(ERROR, TAG, "_40_UNLINK_PAIR_DEVS_: error");
1391             }
1392             break;
1393         case _50_REMOVE_SELEC_DEV_:
1394             if(removeDevice())
1395             {
1396                 OIC_LOG(ERROR, TAG, "_50_REMOVE_SELEC_DEV_: error");
1397             }
1398             break;
1399         case _99_EXIT_PRVN_CLT_:
1400             goto PMCLT_ERROR;
1401         default:
1402             printf(">> Entered Wrong Number. Please Enter Again\n\n");
1403             break;
1404         }
1405     }
1406
1407 PMCLT_ERROR:
1408     if(OC_STACK_OK != OCStop())
1409     {
1410         OIC_LOG(ERROR, TAG, "OCStack stop error");
1411     }
1412     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
1413     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
1414
1415     if(g_svr_fname)
1416     {
1417         OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
1418     }
1419     if(g_prvn_fname)
1420     {
1421         OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
1422     }
1423     return 0;  // always return normal case
1424 }
1425
1426 #ifdef __cplusplus
1427 }
1428 #endif //__cplusplus