[Hotfix] Remove the segmentation fault while MOT.
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / sample / sampleclient_owned_by_subowner.cpp
1 /******************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *****************************************************************/
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "logger.h"
26 #include "oic_malloc.h"
27 #include "oic_string.h"
28 #include "ocprovisioningmanager.h"
29 #include "oxmjustworks.h"
30 #include "oxmrandompin.h"
31 #include "securevirtualresourcetypes.h"
32 #include "srmutility.h"
33 #include "pmtypes.h"
34
35 #include <pthread.h>
36
37 #ifdef __cplusplus
38 extern "C"
39 {
40 #endif //__cplusplus
41
42 #define TAG "ClientOwnedBySubOwner"
43 static bool g_doneCB;
44
45 static pthread_t oc_process_thread;
46 static bool g_LoopFlag = true;
47
48 static void* oc_process_loop(void* ptr)
49 {
50     struct timespec timeout;
51     timeout.tv_sec  = 0;
52     timeout.tv_nsec = 100000000L;
53
54     while(g_LoopFlag)
55     {
56         OCProcess();
57         nanosleep(&timeout, NULL);
58     }
59     pthread_join(&oc_process_thread, NULL);
60     return NULL;
61 }
62
63 static void StartOCProcessThread()
64 {
65     pthread_create(&oc_process_thread, NULL, oc_process_loop, NULL);
66 }
67
68 static void StopOCProcessThread()
69 {
70     g_LoopFlag = false;
71 }
72
73 // declaration(s) for provisioning client using C-level provisioning API
74 // user input definition for main loop on provisioning client
75 #define _10_DISCOV_OWN_DEVS_    10
76 #define _20_GET_LED_RESOURCE_ 20
77 #define _21_PUT_LED_RESOURCE_ 21
78 #define _99_EXIT_PRVN_CLT_      99
79
80 #define DISCOVERY_TIMEOUT   5  // 10 sec
81 #define CALLBACK_TIMEOUT    60  // 1 min
82
83 static const char* SVR_DB_FILE_NAME = "oic_svr_db_client_owned_by_subowner.dat";
84         // '_' for separaing from the same constant variable in |srmresourcestrings.c|
85 static const char* PRVN_DB_FILE_NAME = "oic_prvn_cobs.db";
86 // |g_ctx| means provision manager application context and
87 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
88 // for accessing all function(s) for these, they are declared on global domain
89 static const char* g_ctx = "Provision Manager Client Application Context";
90 static char* g_svr_fname;
91 static char* g_prvn_fname;
92 static OCProvisionDev_t* g_own_list;
93 static int g_own_cnt;
94
95 // function declaration(s) for calling them before implementing
96 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
97 static int printDevList(const OCProvisionDev_t*);
98 static size_t printUuidList(const OCUuidList_t*);
99 static int printResultList(const OCProvisionResult_t*, const int);
100 static void printUuid(const OicUuid_t*);
101 static FILE* fopen_prvnMng(const char*, const char*);
102 static int waitCallbackRet(void);
103 static int selectTwoDiffNum(int*, int*, const int, const char*);
104
105 // callback function(s) for provisioning client using C-level provisioning API
106 static void ownershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
107 {
108     if(!hasError)
109     {
110         OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
111     }
112     else
113     {
114         OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
115         printResultList((const OCProvisionResult_t*) arr, nOfRes);
116     }
117     g_doneCB = true;
118 }
119
120 // response handler for LED requests.
121 static void LedCB(void *ctx, OCDoHandle UNUSED,
122                                                     OCClientResponse *clientResponse)
123 {
124     if(clientResponse)
125     {
126         if(clientResponse->result == OC_STACK_OK)
127         {
128             printf("Get OC_STACK_OK from server\n");
129             if(clientResponse->payload)
130             {
131                 printf("Response ===================> %s\n", clientResponse->payload);
132             }
133         }
134         else
135         {
136             printf("Error in response : %d\n", clientResponse->result);
137         }
138     }
139     else
140     {
141         printf("Hit the response callback but can not find response data\n");
142     }
143
144     g_doneCB = true;
145 }
146
147
148 // function(s) for provisioning client using C-level provisioning API
149 static int initProvisionClient(void)
150 {
151     // initialize persistent storage for SVR DB
152         static OCPersistentStorage ps = {fopen_prvnMng, fread, fwrite, fclose, unlink};
153     if(OC_STACK_OK != OCRegisterPersistentStorageHandler(&ps))
154     {
155         OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
156         return -1;
157     }
158
159     // initialize OC stack and provisioning manager
160     if(OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
161     {
162         OIC_LOG(ERROR, TAG, "OCStack init error");
163         return -1;
164     }
165
166     if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
167     {
168         printf("************************************************************\n");
169         printf("************Provisioning DB file already exists.************\n");
170         printf("************************************************************\n");
171     }
172     else
173     {
174         printf("*************************************************************\n");
175         printf("************No provisioning DB file, creating new************\n");
176         printf("*************************************************************\n");
177     }
178
179     if(OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
180     {
181         OIC_LOG(ERROR, TAG, "OC_PM init error");
182         return -1;
183     }
184
185     return 0;
186 }
187
188 static int discoverOwnedDevices(void)
189 {
190     // delete owned device list before updating it
191     if(g_own_list)
192     {
193         OCDeleteDiscoveredDevices(g_own_list);
194         g_own_list = NULL;
195     }
196
197     // call |OCDiscoverOwnedDevices| API actually
198     printf("   Discovering Only Owned Devices on Network..\n");
199     if(OC_STACK_OK != OCDiscoverOwnedDevices(DISCOVERY_TIMEOUT, &g_own_list))
200     {
201         OIC_LOG(ERROR, TAG, "OCDiscoverOwnedDevices API error");
202         return -1;
203     }
204
205     // display the discovered owned list
206     printf("   > Discovered Owned Devices\n");
207     g_own_cnt = printDevList(g_own_list);
208
209     return 0;
210 }
211
212 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
213 {
214     if(!dev_lst || 0>=dev_num)
215     {
216         printf("     Device List is Empty..\n");
217         return NULL;
218     }
219
220     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
221     for(int i=0; lst; )
222     {
223         if(dev_num == ++i)
224         {
225             return lst;
226         }
227         lst = lst->next;
228     }
229
230     return NULL;  // in here |lst| is always |NULL|
231 }
232
233 static int printDevList(const OCProvisionDev_t* dev_lst)
234 {
235     if(!dev_lst)
236     {
237         printf("     Device List is Empty..\n\n");
238         return 0;
239     }
240
241     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
242     int lst_cnt = 0;
243     for( ; lst; )
244     {
245         printf("     [%d] ", ++lst_cnt);
246         printUuid((const OicUuid_t*) &lst->doxm->deviceID);
247         printf("\n");
248         lst = lst->next;
249     }
250     printf("\n");
251
252     return lst_cnt;
253 }
254
255 static size_t printUuidList(const OCUuidList_t* uid_lst)
256 {
257     if(!uid_lst)
258     {
259         printf("     Device List is Empty..\n\n");
260         return 0;
261     }
262
263     OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
264     size_t lst_cnt = 0;
265     for( ; lst; )
266     {
267         printf("     [%zu] ", ++lst_cnt);
268         printUuid((const OicUuid_t*) &lst->dev);
269         printf("\n");
270         lst = lst->next;
271     }
272     printf("\n");
273
274     return lst_cnt;
275 }
276
277 static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
278 {
279     if(!rslt_lst || 0>=rslt_cnt)
280     {
281         printf("     Device List is Empty..\n\n");
282         return 0;
283     }
284
285     int lst_cnt = 0;
286     for( ; rslt_cnt>lst_cnt; ++lst_cnt)
287     {
288         printf("     [%d] ", lst_cnt+1);
289         printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
290         printf(" - result: %d\n", rslt_lst[lst_cnt].res);
291     }
292     printf("\n");
293
294     return lst_cnt;
295 }
296
297 static void printUuid(const OicUuid_t* uid)
298 {
299     int i;
300     for(i=0; i<UUID_LENGTH; )
301     {
302         printf("%02X", (*uid).id[i++]);
303         if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
304         {
305             printf("-");
306         }
307     }
308
309     printf("\t(");
310     for(i = 0; i < UUID_LENGTH; i++)
311     {
312         printf("%c", (*uid).id[i]);
313     }
314     printf(")");
315 }
316
317 static FILE* fopen_prvnMng(const char* path, const char* mode)
318 {
319     (void)path;  // unused |path| parameter
320
321     // input |g_svr_db_fname| internally by force, not using |path| parameter
322     // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
323     // with its own |SVR_DB_FILE_NAME|
324     return fopen(SVR_DB_FILE_NAME, mode);
325 }
326
327 static int waitCallbackRet(void)
328 {
329     for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
330     {
331         sleep(1);
332     }
333
334     return 0;
335 }
336
337 static void printMenu(void)
338 {
339     printf("************************************************************\n");
340     printf("****** OIC MOT Client with using C-level API ******\n");
341     printf("************************************************************\n\n");
342
343     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
344     printf("** 10. Discover Owned Devices on Network\n\n");
345
346     printf("** [B] SEND GET/PUT Request\n");
347     printf("** 20. Send GET request\n");
348     printf("** 21. Send PUT request\n\n");
349
350     printf("** [G] EXIT PROVISIONING CLIENT\n");
351     printf("** 99. Exit Provisionong Client\n\n");
352
353     printf("************************************************************\n\n");
354 }
355
356 #if 0 // Code for enabling path configuration for PDB and SVR DBf
357 static void printUsage(void)
358 {
359     printf("\n");
360     printf("OIC Provisioning Client with using C-level API\n");
361     printf("Usage: provisioningclient [option]...\n");
362     printf("\n");
363     printf("  -h                           print help for this provisioning client\n");
364     printf("  -p=[prvn_db_file_path/name]  input PRVN DB file path and name\n");
365     printf("                               if not exists, will load default DB file\n");
366     printf("                               (default: |oic_prvn_mng.db| on working dir)\n");
367     printf("                               (ex. -p=oic_prvn_mng.db)\n");
368     printf("  -s=[svr_db_file_path/name]   input SVR DB file path and name\n");
369     printf("                               if not exists, will load default DB file\n");
370     printf("                               (default: |oic_svr_db_client.json| on working dir)\n");
371     printf("                               (ex. -s=oic_svr_db_client.json)\n");
372     printf("\n");
373 }
374 #endif
375
376 // main function for provisioning client using C-level provisioning API
377 int main()
378 {
379     OCProvisionDev_t* selDev = NULL;
380     int selDevNum = 0;
381     int mn_num = 0;
382
383     // initialize provisioning client
384     if(initProvisionClient())
385     {
386         OIC_LOG(ERROR, TAG, "ProvisionClient init error");
387         goto PMCLT_ERROR;
388     }
389
390     StartOCProcessThread();
391     printf("Client started...\n");
392     // main loop for provisioning manager
393     for( ; ; )
394     {
395         printf("\n");
396         printMenu();
397         printf(">> Enter Menu Number: ");
398         for(int ret=0; 1!=ret; )
399         {
400             ret = scanf("%d", &mn_num);
401             for( ; 0x20<=getchar(); );  // for removing overflow garbages
402                                         // '0x20<=code' is character region
403         }
404         printf("\n");
405         switch(mn_num)
406         {
407         case _10_DISCOV_OWN_DEVS_:
408             if(discoverOwnedDevices())
409             {
410                 OIC_LOG(ERROR, TAG, "_12_DISCOV_OWN_DEVS_: error");
411             }
412             break;
413         case _20_GET_LED_RESOURCE_:
414         {
415             char query[256] = {0};
416             OCCallbackData cbData;
417             cbData.cb = &LedCB;
418             cbData.context = NULL;
419             cbData.cd = NULL;
420
421             printDevList(g_own_list);
422
423             for( ; ; )
424             {
425                 printf("Select the device : ");
426                 for(int ret=0; 1!=ret; )
427                 {
428                     scanf(" %d", &selDevNum);
429                     for( ; 0x20<=getchar(); );  // for removing overflow garbages
430                                                 // '0x20<=code' is character region
431                 }
432                 if(0<selDevNum && g_own_cnt>=selDevNum)
433                 {
434                     break;
435                 }
436                 printf("     Entered Wrong Number. Please Enter Again\n");
437             }
438
439             selDev = getDevInst(g_own_list, selDevNum);
440             if(!selDev)
441             {
442                 OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
443                 goto PMCLT_ERROR;
444             }
445
446             g_doneCB = false;
447             snprintf(query, MAX_URI_LENGTH, "coaps://%s:%d/a/led", selDev->endpoint.addr, selDev->securePort);
448             if(OC_STACK_OK != OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, selDev->connType, OC_LOW_QOS, &cbData, NULL, 0))
449             {
450                 printf("********************************\n");
451                 printf("Failed to send GET request to %s\n", query);
452                 printf("********************************\n");
453                 g_doneCB = true;
454                 break;
455             }
456
457             waitCallbackRet();
458
459             break;
460         }
461         case _21_PUT_LED_RESOURCE_:
462         {
463             char query[256] = {0};
464             OCCallbackData cbData;
465             cbData.cb = &LedCB;
466             cbData.context = NULL;
467             cbData.cd = NULL;
468
469             printDevList(g_own_list);
470
471             for( ; ; )
472             {
473                 printf("Select the device : ");
474                 for(int ret=0; 1!=ret; )
475                 {
476                     scanf(" %d", &selDevNum);
477                     for( ; 0x20<=getchar(); );  // for removing overflow garbages
478                                                 // '0x20<=code' is character region
479                 }
480                 if(0<selDevNum && g_own_cnt>=selDevNum)
481                 {
482                     break;
483                 }
484                 printf("     Entered Wrong Number. Please Enter Again\n");
485             }
486
487             selDev = getDevInst(g_own_list, selDevNum);
488             if(!selDev)
489             {
490                 OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
491                 goto PMCLT_ERROR;
492             }
493
494             g_doneCB = false;
495             snprintf(query, MAX_URI_LENGTH, "coaps://%s:%d/a/led", selDev->endpoint.addr, selDev->securePort);
496             if(OC_STACK_OK != OCDoResource(NULL, OC_REST_PUT, query, NULL, NULL, selDev->connType, OC_LOW_QOS, &cbData, NULL, 0))
497             {
498                 printf("********************************\n");
499                 printf("Failed to send PUT request to %s\n", query);
500                 printf("********************************\n");
501                 g_doneCB = true;
502                 break;
503             }
504
505             waitCallbackRet();
506
507             break;
508         }
509         case _99_EXIT_PRVN_CLT_:
510             goto PMCLT_ERROR;
511         default:
512             printf(">> Entered Wrong Number. Please Enter Again\n\n");
513             break;
514         }
515     }
516
517 PMCLT_ERROR:
518     if(OC_STACK_OK != OCStop())
519     {
520         OIC_LOG(ERROR, TAG, "OCStack stop error");
521     }
522     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
523
524     if(g_svr_fname)
525     {
526         OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
527     }
528     if(g_prvn_fname)
529     {
530         OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
531     }
532
533     StopOCProcessThread();
534
535     return 0;  // always return normal case
536 }
537
538 #ifdef __cplusplus
539 }
540 #endif //__cplusplus