8fd6020b1a304fc06db35138ef373dbdaf6fe7ec
[iotivity.git] / resource / csdk / security / provisioning / sample / subownerclient.c
1 /******************************************************************
2  *
3  * Copyright 2016 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 #include "iotivity_config.h"
21
22 #include <stdio.h>
23 #include <string.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #include "platform_features.h"
29 #include "utlist.h"
30 #include "logger.h"
31 #include "oic_malloc.h"
32 #include "oic_string.h"
33 #include "ocprovisioningmanager.h"
34 #include "oxmjustworks.h"
35 #include "oxmrandompin.h"
36 #include "securevirtualresourcetypes.h"
37 #include "srmutility.h"
38 #include "pmtypes.h"
39 #include "pmutility.h"
40
41 #ifdef __cplusplus
42 extern "C"
43 {
44 #endif //__cplusplus
45
46 // declaration(s) for provisioning client using C-level provisioning API
47 // user input definition for main loop on provisioning client
48 #define _10_DISCOV_MOT_ENABLED_DEV_         10
49 #define _11_DISCOV_MULTIPLE_OWNED_DEV_         11
50 #define _20_PERFORM_MOT_        20
51 #define _30_GET_LED_RESOURCE_  30
52 #define _31_PUT_LED_RESOURCE_  31
53 #define _40_PROVISION_ACL_  40
54 #define _41_PROVISION_CRED_  41
55 #define _99_EXIT_PRVN_CLT_          99
56
57 #define ACL_RESRC_MAX_NUM   16
58 #define ACL_RESRC_ARRAY_SIZE   3 //This value is used only for sample (not OCF spec)
59 #define ACL_RESRC_MAX_LEN   128
60 #define ACL_PEMISN_CNT      5
61 #define DISCOVERY_TIMEOUT   5  // 5 sec
62 #define CALLBACK_TIMEOUT    60  // 1 min
63 #define TAG "subownerclient"
64
65 static const char* SVR_DB_FILE_NAME = "oic_svr_db_subowner_client.dat";
66         // '_' for separaing from the same constant variable in |srmresourcestrings.c|
67 static const char* PRVN_DB_FILE_NAME = "oic_pdm_subowner.db";
68 static const OicSecPrm_t  SUPPORTED_PRMS[1] =
69 {
70     PRM_PRE_CONFIGURED,
71 };
72
73 // |g_ctx| means provision manager application context and
74 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
75 // for accessing all function(s) for these, they are declared on global domain
76 static const char* g_ctx = "SubOwner Client Application Context";
77 static char* g_svr_fname;
78 static char* g_prvn_fname;
79 static OCProvisionDev_t* g_own_list;
80 static OCProvisionDev_t* g_unown_list;
81 static OCProvisionDev_t* g_motdev_list;
82 static OCProvisionDev_t* g_mowned_list;
83 static int g_own_cnt;
84 static int g_unown_cnt;
85 static int g_motdev_cnt;
86 static int g_mowned_cnt;
87 static bool g_doneCB;
88
89 // function declaration(s) for calling them before implementing
90 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
91 static int printDevList(const OCProvisionDev_t*);
92 static size_t printUuidList(const OCUuidList_t*);
93 static int printResultList(const OCProvisionResult_t*, const int);
94 static void printUuid(const OicUuid_t*);
95 static FILE* fopen_prvnMng(const char*, const char*);
96 static int waitCallbackRet(void);
97 static int selectTwoDiffNum(int*, int*, const int, const char*);
98
99 // callback function(s) for provisioning client using C-level provisioning API
100 static void multipleOwnershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
101 {
102     if(!hasError)
103     {
104         OIC_LOG_V(INFO, TAG, "Multiple Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
105     }
106     else
107     {
108         OIC_LOG_V(ERROR, TAG, "Multiple Ownership Transfer FAILED - ctx: %s", (char*) ctx);
109         printResultList((const OCProvisionResult_t*) arr, nOfRes);
110     }
111     g_doneCB = true;
112 }
113
114 // callback function(s) for provisioning client using C-level provisioning API
115 static void ownershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
116 {
117     if(!hasError)
118     {
119         OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
120     }
121     else
122     {
123         OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
124         printResultList((const OCProvisionResult_t*) arr, nOfRes);
125     }
126     g_doneCB = true;
127 }
128
129 static void updateDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
130 {
131     if(!hasError)
132     {
133         OIC_LOG_V(INFO, TAG, "POST 'doxm' SUCCEEDED - ctx: %s", (char*) ctx);
134     }
135     else
136     {
137         OIC_LOG_V(ERROR, TAG, "POST 'doxm'  FAILED - ctx: %s", (char*) ctx);
138         printResultList((const OCProvisionResult_t*) arr, nOfRes);
139     }
140     g_doneCB = true;
141 }
142
143 static void provisionCredCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
144 {
145     if(!hasError)
146     {
147         OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
148     }
149     else
150     {
151         OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
152         printResultList((const OCProvisionResult_t*) arr, nOfRes);
153     }
154     g_doneCB = true;
155 }
156
157 static void provisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
158 {
159     if(!hasError)
160     {
161         OIC_LOG_V(INFO, TAG, "Provision ACL SUCCEEDED - ctx: %s", (char*) ctx);
162     }
163     else
164     {
165         OIC_LOG_V(ERROR, TAG, "Provision ACL FAILED - ctx: %s", (char*) ctx);
166         printResultList((const OCProvisionResult_t*) arr, nOfRes);
167     }
168     g_doneCB = true;
169 }
170
171 // response handler for LED requests.
172 static OCStackApplicationResult LedCB(void *ctx, OCDoHandle UNUSED, OCClientResponse *clientResponse)
173 {
174     if(clientResponse)
175     {
176         if(OC_STACK_OK == clientResponse->result)
177         {
178             printf("Received OC_STACK_OK from server\n");
179             if(clientResponse->payload)
180             {
181                 printf("Response ===================> %s\n", clientResponse->payload);
182             }
183         }
184         else if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
185         {
186             printf("Received OC_STACK_RESOURCE_CHANGED from server\n");
187         }
188         else
189         {
190             printf("Error in response : %d\n", clientResponse->result);
191         }
192     }
193     else
194     {
195         printf("Hit the response callback but can not find response data\n");
196     }
197
198     g_doneCB = true;
199     return OC_STACK_OK;
200 }
201
202 static void inputPinCB(char* pin, size_t len)
203 {
204     if(!pin || OXM_RANDOM_PIN_MAX_SIZE>=len)
205     {
206         OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
207         return;
208     }
209
210     printf("   > INPUT PIN: ");
211     for(int ret=0; 1!=ret; )
212     {
213         ret = scanf("%32s", pin);
214         for( ; 0x20<=getchar(); );  // for removing overflow garbages
215                                     // '0x20<=code' is character region
216     }
217 }
218
219 // function(s) for provisioning client using C-level provisioning API
220 static int initProvisionClient(void)
221 {
222     // initialize persistent storage for SVR DB
223     static OCPersistentStorage ps = {fopen_prvnMng, fread, fwrite, fclose, unlink};
224     if(OC_STACK_OK != OCRegisterPersistentStorageHandler(&ps))
225     {
226         OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
227         return -1;
228     }
229
230     // initialize OC stack and provisioning manager
231     if(OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
232     {
233         OIC_LOG(ERROR, TAG, "OCStack init error");
234         return -1;
235     }
236
237     if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
238     {
239         printf("************************************************************\n");
240         printf("************Provisioning DB file already exists.************\n");
241         printf("************************************************************\n");
242     }
243     else
244     {
245         printf("*************************************************************\n");
246         printf("************No provisioning DB file, creating new************\n");
247         printf("*************************************************************\n");
248     }
249
250     if(OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
251     {
252         OIC_LOG(ERROR, TAG, "OC_PM init error");
253         return -1;
254     }
255
256     SetInputPinCB(inputPinCB);
257
258     return 0;
259 }
260
261 static int discoverMotSupportedDevices(void)
262 {
263     // delete un/owned device lists before updating them
264     if(g_motdev_list)
265     {
266         OCDeleteDiscoveredDevices(g_motdev_list);
267         g_motdev_list = NULL;
268     }
269
270     // call |OCDiscoverMultipleOwnerEnabledDevices| API actually
271     printf("   Discovering Multiple Ownership Transfer enabled Devices on Network..\n");
272     if(OC_STACK_OK != OCDiscoverMultipleOwnerEnabledDevices(DISCOVERY_TIMEOUT, &g_motdev_list))
273     {
274         OIC_LOG(ERROR, TAG, "OCDiscoverMultipleOwnerEnalbedDevices API error");
275         return -1;
276     }
277
278     // display the discovered device lists
279     printf("   > Discovered Multiple Ownership Transfer Enabled Devices\n");
280     g_motdev_cnt = printDevList(g_motdev_list);
281
282     return 0;
283 }
284
285 static int discoverSubOwnerDevices()
286 {
287     // delete un/owned device lists before updating them
288     if(g_mowned_list)
289     {
290         OCDeleteDiscoveredDevices(g_mowned_list);
291         g_mowned_list = NULL;
292     }
293
294     // call |OCDiscoverMultipleOwnedDevices| API actually
295     printf("   Discovering Multiple Owned Devices on Network..\n");
296     if(OC_STACK_OK != OCDiscoverMultipleOwnedDevices(DISCOVERY_TIMEOUT, &g_mowned_list))
297     {
298         OIC_LOG(ERROR, TAG, "OCDiscoverMultipleOwnerEnabledDevices API error");
299         return -1;
300     }
301
302     // display the discovered device lists
303     printf("   > Discovered Multiple Owned Devices\n");
304     g_mowned_cnt = printDevList(g_mowned_list);
305
306     return 0;
307 }
308
309 static int multipleOwnershipTransfer(void)
310 {
311     // check |unown_list| for registering devices
312     if(!g_motdev_list || 0 >=g_motdev_cnt)
313     {
314         printf("   > MultipleOwnershipTransfer Enabled Device List is Empty\n");
315         printf("   > Please Discover Devices first, with [10] Menu\n");
316         return 0;  // normal case
317     }
318
319     // call |getDevInst| API actually
320     // calling this API with callback actually acts like blocking
321     // for error checking, the return value saved and printed
322     g_doneCB = false;
323
324 #ifdef MULTIPLE_OWNER
325     OCProvisionDev_t* dev = NULL;
326     LL_FOREACH(g_motdev_list, dev)
327     {
328         if(OIC_PRECONFIG_PIN == dev->doxm->oxmSel)
329         {
330             //Pre-Configured PIN initialization
331             const char* testPreconfigPin = "12341234";
332             if(OC_STACK_OK != OCAddPreconfigPin(dev, testPreconfigPin, strlen(testPreconfigPin)))
333             {
334                 printf("\n\n\n*** %60s ***\n", "WARNNING : Failed to save the pre-configured PIN");
335                 printf("*** %60s ***\n\n\n", "WARNNING : You can't use the pre-configured PIN OxM for MOT");
336                 return -1;
337             }
338         }
339     }
340 #endif //MULTIPLE_OWNER
341
342     if(OC_STACK_OK != OCDoMultipleOwnershipTransfer(g_ctx, g_motdev_list, multipleOwnershipTransferCB))
343     {
344         OIC_LOG(ERROR, TAG, "_20_PERFORM_MOT_: error");
345         return -1;
346     }
347
348     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
349     {
350         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
351         return -1;
352     }
353
354     // display the registered result
355     printf("   > Registered Discovered Devices\n");
356
357     return 0;
358 }
359
360 static int sendGetLed()
361 {
362     int selDevNum;
363     char query[256] = {0};
364     OCCallbackData cbData;
365     cbData.cb = &LedCB;
366     cbData.context = NULL;
367     cbData.cd = NULL;
368
369     printDevList(g_mowned_list);
370
371     // select device for provisioning access control list
372     for( ; ; )
373     {
374         printf("   > Enter Device Number, for sending GET LED request: ");
375         for(int ret=0; 1!=ret; )
376         {
377             ret = scanf("%d", &selDevNum);
378             for( ; 0x20<=getchar(); );  // for removing overflow garbages
379                                         // '0x20<=code' is character region
380         }
381         if(0<selDevNum && g_mowned_cnt>=selDevNum)
382         {
383             break;
384         }
385         printf("     Entered Wrong Number. Please Enter Again\n");
386     }
387
388     OCProvisionDev_t* selDev = getDevInst(g_mowned_list, selDevNum);
389     if(NULL == selDev)
390     {
391         printf("Failed to getDevInst()\n");
392         return -1;
393     }
394
395     if(PMGenerateQuery(true, selDev->endpoint.addr, selDev->securePort, selDev->connType, query, sizeof(query), "/a/led"))
396     {
397         g_doneCB = false;
398         printf("query=%s\n", query);
399         if(OC_STACK_OK != OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, selDev->connType, OC_HIGH_QOS, &cbData, NULL, 0))
400         {
401             printf("********************************\n");
402             printf("Failed to send GET request to %s\n", query);
403             printf("********************************\n");
404             g_doneCB = true;
405             return -1;
406         }
407
408         waitCallbackRet();
409     }
410     else
411     {
412         printf("Failed to generate GET request for /a/led\n");
413         return -1;
414     }
415
416     return 0;
417 }
418
419 static int sendPutLed()
420 {
421     int selDevNum;
422     char query[256] = {0};
423     OCCallbackData cbData;
424     cbData.cb = &LedCB;
425     cbData.context = NULL;
426     cbData.cd = NULL;
427
428     printDevList(g_mowned_list);
429     // select device for provisioning access control list
430     for( ; ; )
431     {
432         printf("   > Enter Device Number, for sending PUT LED request: ");
433         for(int ret=0; 1!=ret; )
434         {
435             ret = scanf("%d", &selDevNum);
436             for( ; 0x20<=getchar(); );  // for removing overflow garbages
437                                         // '0x20<=code' is character region
438         }
439         if(0<selDevNum && g_mowned_cnt>=selDevNum)
440         {
441             break;
442         }
443         printf("     Entered Wrong Number. Please Enter Again\n");
444     }
445
446     OCProvisionDev_t* selDev = getDevInst(g_mowned_list, selDevNum);
447     if(NULL == selDev)
448     {
449         printf("Failed to getDevInst()\n");
450         return -1;
451     }
452
453     if(PMGenerateQuery(true, selDev->endpoint.addr, selDev->securePort, selDev->connType, query, sizeof(query), "/a/led"))
454     {
455         g_doneCB = false;
456         printf("query=%s\n", query);
457         if(OC_STACK_OK != OCDoResource(NULL, OC_REST_PUT, query, NULL, NULL, selDev->connType, OC_LOW_QOS, &cbData, NULL, 0))
458         {
459             printf("********************************\n");
460             printf("Failed to send PUT request to %s\n", query);
461             printf("********************************\n");
462             g_doneCB = true;
463             return -1;
464         }
465
466         waitCallbackRet();
467     }
468     else
469     {
470         printf("Failed to generate PUT request for /a/led\n");
471         return -1;
472     }
473
474     return 0;
475 }
476
477
478 static OicSecAcl_t* createAclForLEDAccess(const OicUuid_t* subject)
479 {
480     if(NULL == subject)
481     {
482         OIC_LOG(ERROR, TAG, "createAcl: Invalid paramters");
483         return NULL;
484     }
485     // allocate memory for |acl| struct
486     OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
487     if(!acl)
488     {
489         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
490         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
491     }
492     OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
493     if(!ace)
494     {
495         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
496         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
497     }
498     LL_APPEND(acl->aces, ace);
499     memcpy(ace->subjectuuid.id, subject->id, sizeof(subject->id));
500
501     // fill the href
502     char* rsrc_in = "/a/led";  // '1' for null termination
503     OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
504     if(!rsrc)
505     {
506         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
507         goto CRACL_ERROR;
508     }
509
510     size_t len = strlen(rsrc_in)+1;  // '1' for null termination
511     rsrc->href = (char*) OICCalloc(len, sizeof(char));
512     if(!rsrc->href)
513     {
514         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
515         goto CRACL_ERROR;
516     }
517     OICStrcpy(rsrc->href, len, rsrc_in);
518
519     //fill the resource type (rt)
520     rsrc->typeLen = 1;
521     rsrc->types = (char**)OICCalloc(1, sizeof(char*));
522     if(!rsrc->types)
523     {
524         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
525         goto CRACL_ERROR;
526     }
527     rsrc->types[0] = OICStrdup("oic.r.core");
528     if(!rsrc->types[0])
529     {
530         OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
531         goto CRACL_ERROR;
532     }
533
534     //fill the interface (if)
535     rsrc->interfaceLen = 1;
536     rsrc->interfaces = (char**)OICCalloc(1, sizeof(char*));
537     if(!rsrc->interfaces)
538     {
539         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
540         goto CRACL_ERROR;
541     }
542     rsrc->interfaces[0] = OICStrdup("oic.if.baseline");
543     if(!rsrc->interfaces[0])
544     {
545         OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
546         goto CRACL_ERROR;
547     }
548
549     LL_APPEND(ace->resources, rsrc);
550
551     // full permission for /a/led
552     ace->permission = PERMISSION_FULL_CONTROL;
553
554     ace->eownerID = (OicUuid_t*)OICCalloc(1, sizeof(OicUuid_t));
555     if(NULL == ace->eownerID)
556     {
557         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
558         goto CRACL_ERROR;
559     }
560
561     memcpy(ace->eownerID->id, subject->id, sizeof(subject->id));
562
563     return acl;
564
565 CRACL_ERROR:
566     OCDeleteACLList(acl);  // after here |acl| points nothing
567     return NULL;
568 }
569
570 static int provisionAclForLed()
571 {
572     OicSecAcl_t* acl = NULL;
573
574     // check |own_list| for provisioning access control list
575     if(!g_mowned_list || 1> g_mowned_cnt)
576     {
577         printf("   > MOT Device List is Empty\n");
578         printf("   > Please Perform MOT first, with [12|21] Menu\n");
579         return 0;  // normal case
580     }
581
582     // display the MOT dev list
583     printf("   > MOT Devices\n");
584     g_mowned_cnt = printDevList(g_mowned_list);
585
586     // select device for provisioning access control list
587     int dev_num = 0;
588     for( ; ; )
589     {
590         printf("   > Enter Device Number, for Provisioning LED's ACL: ");
591         for(int ret=0; 1!=ret; )
592         {
593             ret = scanf("%d", &dev_num);
594             for( ; 0x20<=getchar(); );  // for removing overflow garbages
595                                         // '0x20<=code' is character region
596         }
597         if(0<dev_num && g_mowned_list>=dev_num)
598         {
599             break;
600         }
601         printf("     Entered Wrong Number. Please Enter Again\n");
602     }
603
604     g_doneCB = false;
605     printf("   Provisioning Selected ACL..\n");
606     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_mowned_list, dev_num);
607     if(!dev)
608     {
609         OIC_LOG(ERROR, TAG, "provisionAcl: device instance empty");
610         goto PVACL_ERROR;
611     }
612
613     acl = createAclForLEDAccess(&dev->doxm->subOwners->uuid);
614     if(NULL == acl)
615     {
616         OIC_LOG(ERROR, TAG, "provisionAcl: Failed to create ACL for LED");
617         return -1;
618     }
619
620     OCStackResult rst = OCProvisionACL((void*) g_ctx, dev, acl, provisionAclCB);
621     if(OC_STACK_OK != rst)
622     {
623         OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", rst);
624         goto PVACL_ERROR;
625     }
626     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
627     {
628         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
629         goto PVACL_ERROR;
630     }
631     // display the ACL-provisioned result
632     printf("   > Provisioned Selected ACL\n");
633
634     OCDeleteACLList(acl);  // after here |acl| points nothing
635     return 0;
636
637 PVACL_ERROR:
638     OCDeleteACLList(acl);
639     return -1;
640 }
641
642 static int provisionCred()
643 {
644     // check |unown_list| for registering devices
645     if(!g_mowned_list|| 0 >=g_mowned_cnt)
646     {
647         printf("   > Multiple Owned Device List is Empty\n");
648         printf("   > Please Discover Devices first, with [13] Menu\n");
649         return 0;  // normal case
650     }
651
652     // display the MOT dev list
653     printf("   > Multiple Owned Devices\n");
654     g_mowned_cnt = printDevList(g_mowned_list);
655
656     int dev_num = 0;
657     for( ; ; )
658     {
659         printf("   > Enter Multiple Owned Device Number to link : ");
660         for(int ret=0; 1!=ret; )
661         {
662             ret = scanf("%d", &dev_num);
663             for( ; 0x20<=getchar(); );  // for removing overflow garbages
664                                         // '0x20<=code' is character region
665         }
666         if(0<dev_num && g_mowned_cnt>=dev_num)
667         {
668             break;
669         }
670         printf("     Entered Wrong Number. Please Enter Again\n");
671     }
672
673     OCProvisionDev_t* motDev = getDevInst(g_mowned_list, dev_num);
674     if(NULL == motDev)
675     {
676         OIC_LOG(ERROR, TAG, "Failed to getDevInst()");
677         return -1;
678     }
679
680     // display the MOT dev list
681     printf("   > Owned Devices\n");
682     g_own_cnt = printDevList(g_own_list);
683
684     for( ; ; )
685     {
686         printf("   > Enter Owned Device Number to link : ");
687         for(int ret=0; 1!=ret; )
688         {
689             ret = scanf("%d", &dev_num);
690             for( ; 0x20<=getchar(); );  // for removing overflow garbages
691                                         // '0x20<=code' is character region
692         }
693         if(0<dev_num && g_own_cnt>=dev_num)
694         {
695             break;
696         }
697         printf("     Entered Wrong Number. Please Enter Again\n");
698     }
699
700     OCProvisionDev_t* ownDev = getDevInst(g_own_list, dev_num);
701     if(NULL == ownDev)
702     {
703         OIC_LOG(ERROR, TAG, "Failed to getDevInst()");
704         return -1;
705     }
706
707     // call |OCProvisionCredentials| API actually
708     // calling this API with callback actually acts like blocking
709     // for error checking, the return value saved and printed
710     g_doneCB = false;
711     printf("   Provisioning Selected Pairwise Devices..\n");
712     OCStackResult rst = OCProvisionCredentials((void*) g_ctx,
713                     SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
714                     ownDev, motDev, provisionCredCB);
715     if(OC_STACK_OK != rst)
716     {
717         OIC_LOG_V(ERROR, TAG, "OCProvisionPairwiseDevices API error: %d", rst);
718         goto PVPWS_ERROR;
719     }
720     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
721     {
722         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
723         goto PVPWS_ERROR;
724     }
725
726     // display the pairwise-provisioned result
727     printf("   > Provisioned Selected Pairwise Devices\n");
728
729     return 0;
730
731 PVPWS_ERROR:
732     return -1;
733 }
734
735 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
736 {
737     if(!dev_lst || 0>=dev_num)
738     {
739         printf("     Device List is Empty..\n");
740         return NULL;
741     }
742
743     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
744     for(int i=0; lst; )
745     {
746         if(dev_num == ++i)
747         {
748             return lst;
749         }
750         lst = lst->next;
751     }
752
753     return NULL;  // in here |lst| is always |NULL|
754 }
755
756 static int printDevList(const OCProvisionDev_t* dev_lst)
757 {
758     if(!dev_lst)
759     {
760         printf("     Device List is Empty..\n\n");
761         return 0;
762     }
763
764     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
765     int lst_cnt = 0;
766     for( ; lst; )
767     {
768         printf("     [%d] ", ++lst_cnt);
769         printUuid((const OicUuid_t*) &lst->doxm->deviceID);
770         printf("\n");
771         lst = lst->next;
772     }
773     printf("\n");
774
775     return lst_cnt;
776 }
777
778 static size_t printUuidList(const OCUuidList_t* uid_lst)
779 {
780     if(!uid_lst)
781     {
782         printf("     Device List is Empty..\n\n");
783         return 0;
784     }
785
786     OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
787     size_t lst_cnt = 0;
788     for( ; lst; )
789     {
790         printf("     [%zu] ", ++lst_cnt);
791         printUuid((const OicUuid_t*) &lst->dev);
792         printf("\n");
793         lst = lst->next;
794     }
795     printf("\n");
796
797     return lst_cnt;
798 }
799
800 static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
801 {
802     if(!rslt_lst || 0>=rslt_cnt)
803     {
804         printf("     Device List is Empty..\n\n");
805         return 0;
806     }
807
808     int lst_cnt = 0;
809     for( ; rslt_cnt>lst_cnt; ++lst_cnt)
810     {
811         printf("     [%d] ", lst_cnt+1);
812         printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
813         printf(" - result: %d\n", rslt_lst[lst_cnt].res);
814     }
815     printf("\n");
816
817     return lst_cnt;
818 }
819
820 static void printUuid(const OicUuid_t* uid)
821 {
822     for(int i=0; i<UUID_LENGTH; )
823     {
824         printf("%02X", (*uid).id[i++]);
825         if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
826         {
827             printf("-");
828         }
829     }
830 }
831
832 static FILE* fopen_prvnMng(const char* path, const char* mode)
833 {
834     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
835     {
836         // input |g_svr_db_fname| internally by force, not using |path| parameter
837         // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
838         // with its own |SVR_DB_FILE_NAME|
839         return fopen(SVR_DB_FILE_NAME, mode);
840     }
841     else
842     {
843         return fopen(path, mode);
844     }
845 }
846
847 static int waitCallbackRet(void)
848 {
849     for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
850     {
851         sleep(1);
852         if(OC_STACK_OK != OCProcess())
853         {
854             OIC_LOG(ERROR, TAG, "OCStack process error");
855             return -1;
856         }
857     }
858
859     return 0;
860 }
861
862 static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
863 {
864     if(!a || !b || 2>max || !str)
865     {
866         return -1;
867     }
868
869     for( ; ; )
870     {
871         for(int i=0; 2>i; ++i)
872         {
873             int* num = 0==i?a:b;
874             for( ; ; )
875             {
876                 printf("   > Enter Device[%d] Number, %s: ", i+1, str);
877                 for(int ret=0; 1!=ret; )
878                 {
879                     ret = scanf("%d", num);
880                     for( ; 0x20<=getchar(); );  // for removing overflow garbages
881                                                 // '0x20<=code' is character region
882                 }
883                 if(0<*num && max>=*num)
884                 {
885                     break;
886                 }
887                 printf("     Entered Wrong Number. Please Enter Again\n");
888             }
889         }
890         if(*a != *b)
891         {
892             printf("\n");
893             return 0;
894         }
895     }
896
897     return -1;
898 }
899
900 static void printMenu(void)
901 {
902     printf("************************************************************\n");
903     printf("****** OIC Provisioning Client with using C-level API ******\n");
904     printf("************************************************************\n\n");
905
906     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
907     printf("** 10. Discover Multiple Ownership Transfer Enabled Devices on Network\n");
908     printf("** 11. Discover Multiple Owned Devices on Network\n\n");
909
910     printf("** [B] PERFORM MULTIPLE OWNERSHIP TRANSFER\n");
911     printf("** 20. Perform the Multiple Ownership Transfer for ALL discovered dievices\n\n");
912
913     printf("** [C] Get/Put Request for APPLICATION RESOURCE\n");
914     printf("** 30. Get LED resource\n");
915     printf("** 31. Put LED resource\n\n");
916
917     printf("** [D] LINK DEVICES\n");
918     printf("** 40. Provision ACL for LED Resource\n");
919     printf("** 41. Provison Credential\n\n");
920
921     printf("** [F] EXIT PROVISIONING CLIENT\n");
922     printf("** 99. Exit Provisionong Client\n\n");
923
924     printf("************************************************************\n\n");
925 }
926
927 // main function for provisioning client using C-level provisioning API
928 int main()
929 {
930     // initialize provisioning client
931     if(initProvisionClient())
932     {
933         OIC_LOG(ERROR, TAG, "ProvisionClient init error");
934         goto PMCLT_ERROR;
935     }
936
937     // main loop for provisioning manager
938     int mnNum = 0;
939     int selDevNum = 0;
940     for( ; ; )
941     {
942         printf("\n");
943         printMenu();
944         printf(">> Enter Menu Number: ");
945         for(int ret=0; 1!=ret; )
946         {
947             ret = scanf("%d", &mnNum);
948             for( ; 0x20<=getchar(); );  // for removing overflow garbages
949                                         // '0x20<=code' is character region
950         }
951         printf("\n");
952         switch(mnNum)
953         {
954         case _10_DISCOV_MOT_ENABLED_DEV_:
955             if(discoverMotSupportedDevices())
956             {
957                 OIC_LOG(ERROR, TAG, "_12_MOT_DISCOV_DEV_: error");
958             }
959             break;
960         case _11_DISCOV_MULTIPLE_OWNED_DEV_:
961             if(discoverSubOwnerDevices())
962             {
963                 OIC_LOG(ERROR, TAG, "_13_DISCOV_MULTIPLE_OWNED_DEV_: error");
964             }
965             break;
966         case _20_PERFORM_MOT_:
967             if(multipleOwnershipTransfer())
968             {
969                 OIC_LOG(ERROR, TAG, "_21_PERFORM_MOT_: error");
970             }
971             break;
972         case _30_GET_LED_RESOURCE_:
973             if(sendGetLed())
974             {
975                 OIC_LOG(ERROR, TAG, "_30_GET_LED_RESOURCE_: error");
976             }
977             break;
978         case _31_PUT_LED_RESOURCE_:
979             if(sendPutLed())
980             {
981                 OIC_LOG(ERROR, TAG, "_31_PUT_LED_RESOURCE_: error");
982             }
983             break;
984         case _40_PROVISION_ACL_:
985             if(provisionAclForLed())
986             {
987                 OIC_LOG(ERROR, TAG, "_40_PROVISION_ACL_: error");
988             }
989             break;
990         case _41_PROVISION_CRED_:
991             OIC_LOG(ERROR, TAG, "NOT SUPPORTED YET.");
992             break;
993             /*
994             if(provisionCred())
995             {
996                 OIC_LOG(ERROR, TAG, "_41_PROVISION_CRED_: error");
997             }
998             break;
999             */
1000         case _99_EXIT_PRVN_CLT_:
1001             goto PMCLT_ERROR;
1002         default:
1003             printf(">> Entered Wrong Number. Please Enter Again\n\n");
1004             break;
1005         }
1006     }
1007
1008 PMCLT_ERROR:
1009     if(OC_STACK_OK != OCStop())
1010     {
1011         OIC_LOG(ERROR, TAG, "OCStack stop error");
1012     }
1013     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
1014     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
1015     OCDeleteDiscoveredDevices(g_motdev_list);  // after here |g_motdev_list| points nothing
1016
1017     if(g_svr_fname)
1018     {
1019         OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
1020     }
1021     if(g_prvn_fname)
1022     {
1023         OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
1024     }
1025     return 0;  // always return normal case
1026 }
1027
1028 #ifdef __cplusplus
1029 }
1030 #endif //__cplusplus