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