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