Fix Wformat build error
[platform/upstream/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 void LedCB(void *ctx, OCDoHandle UNUSED,
173                                                     OCClientResponse *clientResponse)
174 {
175     if(clientResponse)
176     {
177         if(OC_STACK_OK == clientResponse->result)
178         {
179             printf("Received OC_STACK_OK from server\n");
180             if(clientResponse->payload)
181             {
182                 printf("Response ===================> %p\n", clientResponse->payload);
183             }
184         }
185         else if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
186         {
187             printf("Received OC_STACK_RESOURCE_CHANGED from server\n");
188         }
189         else
190         {
191             printf("Error in response : %d\n", clientResponse->result);
192         }
193     }
194     else
195     {
196         printf("Hit the response callback but can not find response data\n");
197     }
198
199     g_doneCB = true;
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,
396                        query, sizeof(query), "/a/led"))
397     {
398         g_doneCB = false;
399         printf("query=%s\n", query);
400         if(OC_STACK_OK != OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, selDev->connType,
401                                        OC_HIGH_QOS, &cbData, NULL, 0))
402         {
403             printf("********************************\n");
404             printf("Failed to send GET request to %s\n", query);
405             printf("********************************\n");
406             g_doneCB = true;
407             return -1;
408         }
409
410         waitCallbackRet();
411     }
412     else
413     {
414         printf("Failed to generate GET request for /a/led\n");
415         return -1;
416     }
417
418     return 0;
419 }
420
421 static int sendPutLed()
422 {
423     int selDevNum;
424     char query[256] = {0};
425     OCCallbackData cbData;
426     cbData.cb = &LedCB;
427     cbData.context = NULL;
428     cbData.cd = NULL;
429
430     printDevList(g_mowned_list);
431     // select device for provisioning access control list
432     for( ; ; )
433     {
434         printf("   > Enter Device Number, for sending PUT LED request: ");
435         for(int ret=0; 1!=ret; )
436         {
437             ret = scanf("%d", &selDevNum);
438             for( ; 0x20<=getchar(); );  // for removing overflow garbages
439                                         // '0x20<=code' is character region
440         }
441         if(0<selDevNum && g_mowned_cnt>=selDevNum)
442         {
443             break;
444         }
445         printf("     Entered Wrong Number. Please Enter Again\n");
446     }
447
448     OCProvisionDev_t* selDev = getDevInst(g_mowned_list, selDevNum);
449     if(NULL == selDev)
450     {
451         printf("Failed to getDevInst()\n");
452         return -1;
453     }
454
455     if(PMGenerateQuery(true, selDev->endpoint.addr, selDev->securePort, selDev->connType,
456                        query, sizeof(query), "/a/led"))
457     {
458         g_doneCB = false;
459         printf("query=%s\n", query);
460         if(OC_STACK_OK != OCDoResource(NULL, OC_REST_PUT, query, NULL, NULL, selDev->connType,
461                                        OC_LOW_QOS, &cbData, NULL, 0))
462         {
463             printf("********************************\n");
464             printf("Failed to send PUT request to %s\n", query);
465             printf("********************************\n");
466             g_doneCB = true;
467             return -1;
468         }
469
470         waitCallbackRet();
471     }
472     else
473     {
474         printf("Failed to generate PUT request for /a/led\n");
475         return -1;
476     }
477
478     return 0;
479 }
480
481
482 static OicSecAcl_t* createAclForLEDAccess(const OicUuid_t* subject)
483 {
484     if(NULL == subject)
485     {
486         OIC_LOG(ERROR, TAG, "createAcl: Invalid paramters");
487         return NULL;
488     }
489     // allocate memory for |acl| struct
490     OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
491     if(!acl)
492     {
493         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
494         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
495     }
496     OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
497     if(!ace)
498     {
499         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
500         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
501     }
502     LL_APPEND(acl->aces, ace);
503     memcpy(ace->subjectuuid.id, subject->id, sizeof(subject->id));
504
505     // fill the href
506     char* rsrc_in = "/a/led";  // '1' for null termination
507     OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
508     if(!rsrc)
509     {
510         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
511         goto CRACL_ERROR;
512     }
513
514     size_t len = strlen(rsrc_in)+1;  // '1' for null termination
515     rsrc->href = (char*) OICCalloc(len, sizeof(char));
516     if(!rsrc->href)
517     {
518         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
519         goto CRACL_ERROR;
520     }
521     OICStrcpy(rsrc->href, len, rsrc_in);
522
523     //fill the resource type (rt)
524     rsrc->typeLen = 1;
525     rsrc->types = (char**)OICCalloc(1, sizeof(char*));
526     if(!rsrc->types)
527     {
528         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
529         goto CRACL_ERROR;
530     }
531     rsrc->types[0] = OICStrdup("oic.r.core");
532     if(!rsrc->types[0])
533     {
534         OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
535         goto CRACL_ERROR;
536     }
537
538     //fill the interface (if)
539     rsrc->interfaceLen = 1;
540     rsrc->interfaces = (char**)OICCalloc(1, sizeof(char*));
541     if(!rsrc->interfaces)
542     {
543         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
544         goto CRACL_ERROR;
545     }
546     rsrc->interfaces[0] = OICStrdup("oic.if.baseline");
547     if(!rsrc->interfaces[0])
548     {
549         OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
550         goto CRACL_ERROR;
551     }
552
553     LL_APPEND(ace->resources, rsrc);
554
555     // full permission for /a/led
556     ace->permission = PERMISSION_FULL_CONTROL;
557
558     ace->eownerID = (OicUuid_t*)OICCalloc(1, sizeof(OicUuid_t));
559     if(NULL == ace->eownerID)
560     {
561         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
562         goto CRACL_ERROR;
563     }
564
565     memcpy(ace->eownerID->id, subject->id, sizeof(subject->id));
566
567     return acl;
568
569 CRACL_ERROR:
570     OCDeleteACLList(acl);  // after here |acl| points nothing
571     return NULL;
572 }
573
574 static int provisionAclForLed()
575 {
576     OicSecAcl_t* acl = NULL;
577
578     // check |own_list| for provisioning access control list
579     if(!g_mowned_list || 1> g_mowned_cnt)
580     {
581         printf("   > MOT Device List is Empty\n");
582         printf("   > Please Perform MOT first, with [12|21] Menu\n");
583         return 0;  // normal case
584     }
585
586     // display the MOT dev list
587     printf("   > MOT Devices\n");
588     g_mowned_cnt = printDevList(g_mowned_list);
589
590     // select device for provisioning access control list
591     int dev_num = 0;
592     for( ; ; )
593     {
594         printf("   > Enter Device Number, for Provisioning LED's ACL: ");
595         for(int ret=0; 1!=ret; )
596         {
597             ret = scanf("%d", &dev_num);
598             for( ; 0x20<=getchar(); );  // for removing overflow garbages
599                                         // '0x20<=code' is character region
600         }
601         if(0<dev_num && g_mowned_list>=dev_num)
602         {
603             break;
604         }
605         printf("     Entered Wrong Number. Please Enter Again\n");
606     }
607
608     g_doneCB = false;
609     printf("   Provisioning Selected ACL..\n");
610     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_mowned_list, dev_num);
611     if(!dev)
612     {
613         OIC_LOG(ERROR, TAG, "provisionAcl: device instance empty");
614         goto PVACL_ERROR;
615     }
616
617     acl = createAclForLEDAccess(&dev->doxm->subOwners->uuid);
618     if(NULL == acl)
619     {
620         OIC_LOG(ERROR, TAG, "provisionAcl: Failed to create ACL for LED");
621         return -1;
622     }
623
624     OCStackResult rst = OCProvisionACL((void*) g_ctx, dev, acl, provisionAclCB);
625     if(OC_STACK_OK != rst)
626     {
627         OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", rst);
628         goto PVACL_ERROR;
629     }
630     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
631     {
632         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
633         goto PVACL_ERROR;
634     }
635     // display the ACL-provisioned result
636     printf("   > Provisioned Selected ACL\n");
637
638     OCDeleteACLList(acl);  // after here |acl| points nothing
639     return 0;
640
641 PVACL_ERROR:
642     OCDeleteACLList(acl);
643     return -1;
644 }
645
646 static int provisionCred()
647 {
648     // check |unown_list| for registering devices
649     if(!g_mowned_list|| 0 >=g_mowned_cnt)
650     {
651         printf("   > Multiple Owned Device List is Empty\n");
652         printf("   > Please Discover Devices first, with [13] Menu\n");
653         return 0;  // normal case
654     }
655
656     // display the MOT dev list
657     printf("   > Multiple Owned Devices\n");
658     g_mowned_cnt = printDevList(g_mowned_list);
659
660     int dev_num = 0;
661     for( ; ; )
662     {
663         printf("   > Enter Multiple Owned Device Number to link : ");
664         for(int ret=0; 1!=ret; )
665         {
666             ret = scanf("%d", &dev_num);
667             for( ; 0x20<=getchar(); );  // for removing overflow garbages
668                                         // '0x20<=code' is character region
669         }
670         if(0<dev_num && g_mowned_cnt>=dev_num)
671         {
672             break;
673         }
674         printf("     Entered Wrong Number. Please Enter Again\n");
675     }
676
677     OCProvisionDev_t* motDev = getDevInst(g_mowned_list, dev_num);
678     if(NULL == motDev)
679     {
680         OIC_LOG(ERROR, TAG, "Failed to getDevInst()");
681         return -1;
682     }
683
684     // display the MOT dev list
685     printf("   > Owned Devices\n");
686     g_own_cnt = printDevList(g_own_list);
687
688     for( ; ; )
689     {
690         printf("   > Enter Owned Device Number to link : ");
691         for(int ret=0; 1!=ret; )
692         {
693             ret = scanf("%d", &dev_num);
694             for( ; 0x20<=getchar(); );  // for removing overflow garbages
695                                         // '0x20<=code' is character region
696         }
697         if(0<dev_num && g_own_cnt>=dev_num)
698         {
699             break;
700         }
701         printf("     Entered Wrong Number. Please Enter Again\n");
702     }
703
704     OCProvisionDev_t* ownDev = getDevInst(g_own_list, dev_num);
705     if(NULL == ownDev)
706     {
707         OIC_LOG(ERROR, TAG, "Failed to getDevInst()");
708         return -1;
709     }
710
711     // call |OCProvisionCredentials| API actually
712     // calling this API with callback actually acts like blocking
713     // for error checking, the return value saved and printed
714     g_doneCB = false;
715     printf("   Provisioning Selected Pairwise Devices..\n");
716     OCStackResult rst = OCProvisionCredentials((void*) g_ctx,
717                     SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
718                     ownDev, motDev, provisionCredCB);
719     if(OC_STACK_OK != rst)
720     {
721         OIC_LOG_V(ERROR, TAG, "OCProvisionPairwiseDevices API error: %d", rst);
722         goto PVPWS_ERROR;
723     }
724     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
725     {
726         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
727         goto PVPWS_ERROR;
728     }
729
730     // display the pairwise-provisioned result
731     printf("   > Provisioned Selected Pairwise Devices\n");
732
733     return 0;
734
735 PVPWS_ERROR:
736     return -1;
737 }
738
739 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
740 {
741     if(!dev_lst || 0>=dev_num)
742     {
743         printf("     Device List is Empty..\n");
744         return NULL;
745     }
746
747     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
748     for(int i=0; lst; )
749     {
750         if(dev_num == ++i)
751         {
752             return lst;
753         }
754         lst = lst->next;
755     }
756
757     return NULL;  // in here |lst| is always |NULL|
758 }
759
760 static int printDevList(const OCProvisionDev_t* dev_lst)
761 {
762     if(!dev_lst)
763     {
764         printf("     Device List is Empty..\n\n");
765         return 0;
766     }
767
768     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
769     int lst_cnt = 0;
770     for( ; lst; )
771     {
772         printf("     [%d] ", ++lst_cnt);
773         printUuid((const OicUuid_t*) &lst->doxm->deviceID);
774         printf("\n");
775         lst = lst->next;
776     }
777     printf("\n");
778
779     return lst_cnt;
780 }
781
782 static size_t printUuidList(const OCUuidList_t* uid_lst)
783 {
784     if(!uid_lst)
785     {
786         printf("     Device List is Empty..\n\n");
787         return 0;
788     }
789
790     OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
791     size_t lst_cnt = 0;
792     for( ; lst; )
793     {
794         printf("     [%zu] ", ++lst_cnt);
795         printUuid((const OicUuid_t*) &lst->dev);
796         printf("\n");
797         lst = lst->next;
798     }
799     printf("\n");
800
801     return lst_cnt;
802 }
803
804 static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
805 {
806     if(!rslt_lst || 0>=rslt_cnt)
807     {
808         printf("     Device List is Empty..\n\n");
809         return 0;
810     }
811
812     int lst_cnt = 0;
813     for( ; rslt_cnt>lst_cnt; ++lst_cnt)
814     {
815         printf("     [%d] ", lst_cnt+1);
816         printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
817         printf(" - result: %d\n", rslt_lst[lst_cnt].res);
818     }
819     printf("\n");
820
821     return lst_cnt;
822 }
823
824 static void printUuid(const OicUuid_t* uid)
825 {
826     for(int i=0; i<UUID_LENGTH; )
827     {
828         printf("%02X", (*uid).id[i++]);
829         if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
830         {
831             printf("-");
832         }
833     }
834 }
835
836 static FILE* fopen_prvnMng(const char* path, const char* mode)
837 {
838     (void)path;  // unused |path| parameter
839
840     // input |g_svr_db_fname| internally by force, not using |path| parameter
841     // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
842     // with its own |SVR_DB_FILE_NAME|
843     return fopen(SVR_DB_FILE_NAME, mode);
844 }
845
846 static int waitCallbackRet(void)
847 {
848     for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
849     {
850         sleep(1);
851         if(OC_STACK_OK != OCProcess())
852         {
853             OIC_LOG(ERROR, TAG, "OCStack process error");
854             return -1;
855         }
856     }
857
858     if(!g_doneCB)
859     {
860         OCPDMCleanupForTimeout();
861     }
862
863     return 0;
864 }
865
866 static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
867 {
868     if(!a || !b || 2>max || !str)
869     {
870         return -1;
871     }
872
873     for( ; ; )
874     {
875         for(int i=0; 2>i; ++i)
876         {
877             int* num = 0==i?a:b;
878             for( ; ; )
879             {
880                 printf("   > Enter Device[%d] Number, %s: ", i+1, str);
881                 for(int ret=0; 1!=ret; )
882                 {
883                     ret = scanf("%d", num);
884                     for( ; 0x20<=getchar(); );  // for removing overflow garbages
885                                                 // '0x20<=code' is character region
886                 }
887                 if(0<*num && max>=*num)
888                 {
889                     break;
890                 }
891                 printf("     Entered Wrong Number. Please Enter Again\n");
892             }
893         }
894         if(*a != *b)
895         {
896             printf("\n");
897             return 0;
898         }
899     }
900
901     return -1;
902 }
903
904 static void printMenu(void)
905 {
906     printf("************************************************************\n");
907     printf("****** OIC Provisioning Client with using C-level API ******\n");
908     printf("************************************************************\n\n");
909
910     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
911     printf("** 10. Discover Multiple Ownership Transfer Enabled Devices on Network\n");
912     printf("** 11. Discover Multiple Owned Devices on Network\n\n");
913
914     printf("** [B] PERFORM MULTIPLE OWNERSHIP TRANSFER\n");
915     printf("** 20. Perform the Multiple Ownership Transfer for ALL discovered dievices\n\n");
916
917     printf("** [C] Get/Put Request for APPLICATION RESOURCE\n");
918     printf("** 30. Get LED resource\n");
919     printf("** 31. Put LED resource\n\n");
920
921     printf("** [D] LINK DEVICES\n");
922     printf("** 40. Provision ACL for LED Resource\n");
923     printf("** 41. Provison Credential\n\n");
924
925     printf("** [F] EXIT PROVISIONING CLIENT\n");
926     printf("** 99. Exit Provisionong Client\n\n");
927
928     printf("************************************************************\n\n");
929 }
930
931 // main function for provisioning client using C-level provisioning API
932 int main()
933 {
934     // initialize provisioning client
935     if(initProvisionClient())
936     {
937         OIC_LOG(ERROR, TAG, "ProvisionClient init error");
938         goto PMCLT_ERROR;
939     }
940
941     // main loop for provisioning manager
942     int mnNum = 0;
943     int selDevNum = 0;
944     for( ; ; )
945     {
946         printf("\n");
947         printMenu();
948         printf(">> Enter Menu Number: ");
949         for(int ret=0; 1!=ret; )
950         {
951             ret = scanf("%d", &mnNum);
952             for( ; 0x20<=getchar(); );  // for removing overflow garbages
953                                         // '0x20<=code' is character region
954         }
955         printf("\n");
956         switch(mnNum)
957         {
958         case _10_DISCOV_MOT_ENABLED_DEV_:
959             if(discoverMotSupportedDevices())
960             {
961                 OIC_LOG(ERROR, TAG, "_12_MOT_DISCOV_DEV_: error");
962             }
963             break;
964         case _11_DISCOV_MULTIPLE_OWNED_DEV_:
965             if(discoverSubOwnerDevices())
966             {
967                 OIC_LOG(ERROR, TAG, "_13_DISCOV_MULTIPLE_OWNED_DEV_: error");
968             }
969             break;
970         case _20_PERFORM_MOT_:
971             if(multipleOwnershipTransfer())
972             {
973                 OIC_LOG(ERROR, TAG, "_21_PERFORM_MOT_: error");
974             }
975             break;
976         case _30_GET_LED_RESOURCE_:
977             if(sendGetLed())
978             {
979                 OIC_LOG(ERROR, TAG, "_30_GET_LED_RESOURCE_: error");
980             }
981             break;
982         case _31_PUT_LED_RESOURCE_:
983             if(sendPutLed())
984             {
985                 OIC_LOG(ERROR, TAG, "_31_PUT_LED_RESOURCE_: error");
986             }
987             break;
988         case _40_PROVISION_ACL_:
989             if(provisionAclForLed())
990             {
991                 OIC_LOG(ERROR, TAG, "_40_PROVISION_ACL_: error");
992             }
993             break;
994         case _41_PROVISION_CRED_:
995             OIC_LOG(ERROR, TAG, "NOT SUPPORTED YET.");
996             break;
997             /*
998             if(provisionCred())
999             {
1000                 OIC_LOG(ERROR, TAG, "_41_PROVISION_CRED_: error");
1001             }
1002             break;
1003             */
1004         case _99_EXIT_PRVN_CLT_:
1005             goto PMCLT_ERROR;
1006         default:
1007             printf(">> Entered Wrong Number. Please Enter Again\n\n");
1008             break;
1009         }
1010     }
1011
1012 PMCLT_ERROR:
1013     if(OC_STACK_OK != OCStop())
1014     {
1015         OIC_LOG(ERROR, TAG, "OCStack stop error");
1016     }
1017     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
1018     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
1019     OCDeleteDiscoveredDevices(g_motdev_list);  // after here |g_motdev_list| points nothing
1020
1021     if(g_svr_fname)
1022     {
1023         OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
1024     }
1025     if(g_prvn_fname)
1026     {
1027         OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
1028     }
1029     return 0;  // always return normal case
1030 }
1031
1032 #ifdef __cplusplus
1033 }
1034 #endif //__cplusplus