Imported Upstream version 1.1.1
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / secure / occlientdirectpairing.cpp
1 //******************************************************************\r
2 //\r
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.\r
4 //\r
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
6 //\r
7 // Licensed under the Apache License, Version 2.0 (the "License");\r
8 // you may not use this file except in compliance with the License.\r
9 // You may obtain a copy of the License at\r
10 //\r
11 //      http://www.apache.org/licenses/LICENSE-2.0\r
12 //\r
13 // Unless required by applicable law or agreed to in writing, software\r
14 // distributed under the License is distributed on an "AS IS" BASIS,\r
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16 // See the License for the specific language governing permissions and\r
17 // limitations under the License.\r
18 //\r
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
20 \r
21 #include <stdio.h>\r
22 #include <stdlib.h>\r
23 #include <string.h>\r
24 #include <signal.h>\r
25 #include <unistd.h>\r
26 #include <pthread.h>\r
27 #include <iostream>\r
28 #include <sstream>\r
29 #include "ocstack.h"\r
30 #include "logger.h"\r
31 #include "ocpayload.h"\r
32 #include "payload_logging.h"\r
33 #include "oic_malloc.h"\r
34 #include "oic_string.h"\r
35 #include "utlist.h"\r
36 \r
37 #define TAG "occlient-directpairing"\r
38 \r
39 #define BOLD_BEGIN    "\033[1m"\r
40 #define RED_BEGIN      "\033[1;31m"\r
41 #define GREEN_BEGIN  "\033[1;92m"\r
42 #define COLOR_END      "\033[0m"\r
43 #define MAX_LINE (1024)\r
44 #define DP_DISCOVERY_TIMEOUT   3  // 3 sec\r
45 #define DP_PIN_LENGTH 8 // 8 digit\r
46 \r
47 static char DISCOVERY_QUERY[] = "%s/oic/res";\r
48 \r
49 //Secure Virtual Resource database for Iotivity Client application\r
50 //It contains Client's Identity and the PSK credentials\r
51 //of other devices which the client trusts\r
52 static char CRED_FILE[] = "oic_svr_db_client_directpairing.dat";\r
53 \r
54 static const OCDPDev_t *discoveredDevs = NULL;\r
55 static const OCDPDev_t *pairedDevs = NULL;\r
56 \r
57 int gQuitFlag = 0;\r
58 \r
59 //-----------------------------------------------------------------------------\r
60 // Function prototype\r
61 //-----------------------------------------------------------------------------\r
62 \r
63 \r
64 \r
65 \r
66 //-----------------------------------------------------------------------------\r
67 // Function body\r
68 //-----------------------------------------------------------------------------\r
69 \r
70 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */\r
71 void handleSigInt(int signum)\r
72 {\r
73     if (signum == SIGINT)\r
74     {\r
75         gQuitFlag = 1;\r
76     }\r
77 }\r
78 \r
79 const char *readline(const char *in, const char *defaultStr)\r
80 {\r
81     static char rbuffer[MAX_LINE] = {0,};\r
82     char *cptr, *p;\r
83 \r
84     size_t in_len = strlen(in);\r
85     for (size_t i=0; i<in_len; i++)\r
86     {\r
87         fprintf(stdout, "%c", in[i]);\r
88     }\r
89 \r
90     if (NULL != (cptr = fgets(rbuffer, MAX_LINE, stdin)))\r
91     {\r
92         /* kill preceding whitespace but leave \n so we're guaranteed to have something */\r
93         /*while(*cptr == ' ' || *cptr == '\t')\r
94         {\r
95             cptr++;\r
96         }*/\r
97 \r
98         if ( (p = strchr(cptr, '\n')) != NULL )\r
99         {\r
100             *p = '\0';\r
101         }\r
102 \r
103         if (strlen(cptr)==0 && defaultStr)\r
104         {\r
105             return defaultStr;\r
106         }\r
107         return cptr;\r
108     }\r
109     else\r
110     {\r
111         return 0;\r
112     }\r
113 }\r
114 \r
115 const char *getResult(OCStackResult result) {\r
116     switch (result) {\r
117     case OC_STACK_OK:\r
118         return "OC_STACK_OK";\r
119     case OC_STACK_RESOURCE_CREATED:\r
120         return "OC_STACK_RESOURCE_CREATED";\r
121     case OC_STACK_RESOURCE_DELETED:\r
122         return "OC_STACK_RESOURCE_DELETED";\r
123     case OC_STACK_INVALID_URI:\r
124         return "OC_STACK_INVALID_URI";\r
125     case OC_STACK_INVALID_QUERY:\r
126         return "OC_STACK_INVALID_QUERY";\r
127     case OC_STACK_INVALID_IP:\r
128         return "OC_STACK_INVALID_IP";\r
129     case OC_STACK_INVALID_PORT:\r
130         return "OC_STACK_INVALID_PORT";\r
131     case OC_STACK_INVALID_CALLBACK:\r
132         return "OC_STACK_INVALID_CALLBACK";\r
133     case OC_STACK_INVALID_METHOD:\r
134         return "OC_STACK_INVALID_METHOD";\r
135     case OC_STACK_NO_MEMORY:\r
136         return "OC_STACK_NO_MEMORY";\r
137     case OC_STACK_COMM_ERROR:\r
138         return "OC_STACK_COMM_ERROR";\r
139     case OC_STACK_INVALID_PARAM:\r
140         return "OC_STACK_INVALID_PARAM";\r
141     case OC_STACK_NOTIMPL:\r
142         return "OC_STACK_NOTIMPL";\r
143     case OC_STACK_NO_RESOURCE:\r
144         return "OC_STACK_NO_RESOURCE";\r
145     case OC_STACK_RESOURCE_ERROR:\r
146         return "OC_STACK_RESOURCE_ERROR";\r
147     case OC_STACK_SLOW_RESOURCE:\r
148         return "OC_STACK_SLOW_RESOURCE";\r
149     case OC_STACK_NO_OBSERVERS:\r
150         return "OC_STACK_NO_OBSERVERS";\r
151     #ifdef WITH_PRESENCE\r
152     case OC_STACK_PRESENCE_STOPPED:\r
153         return "OC_STACK_PRESENCE_STOPPED";\r
154     #endif\r
155     case OC_STACK_ERROR:\r
156         return "OC_STACK_ERROR";\r
157     default:\r
158         return "UNKNOWN";\r
159     }\r
160 }\r
161 \r
162 OCDPDev_t* getDev(const OCDPDev_t* pList, const uint32_t dev_num)\r
163 {\r
164     if(NULL == pList)\r
165     {\r
166         printf("     Device List is Empty..\n");\r
167         return NULL;\r
168     }\r
169 \r
170     OCDPDev_t* lst =  (OCDPDev_t*)pList;\r
171     for(size_t i=0; lst; )\r
172     {\r
173         if(dev_num == ++i)\r
174         {\r
175             return lst;\r
176         }\r
177         lst = lst->next;\r
178     }\r
179 \r
180     return NULL;  // in here |lst| is always |NULL|\r
181 }\r
182 \r
183 int printList(const OCDPDev_t* pList)\r
184 {\r
185     if(!pList)\r
186     {\r
187         printf("     Device List is Empty..\n\n");\r
188         return 0;\r
189     }\r
190 \r
191     const OCDPDev_t* lst = pList;\r
192     int lst_cnt = 0;\r
193     for( ; lst; )\r
194     {\r
195         printf("     [%d] ", ++lst_cnt);\r
196         for(int i=0; i<UUID_IDENTITY_SIZE; i++)\r
197         {\r
198             fprintf(stdout, "%c", (char)lst->deviceID.id[i]);\r
199         }\r
200         printf("\n");\r
201         lst = lst->next;\r
202     }\r
203     printf("\n");\r
204 \r
205     return lst_cnt;\r
206 }\r
207 \r
208 bool printPairingMethod(const OCDPDev_t* pDev)\r
209 {\r
210     printf("\n   * List of supported pairing method\n");\r
211 \r
212     if(!pDev || false == pDev->edp)\r
213     {\r
214         printf("     Invalid device or Not support direct-pairing..\n\n");\r
215         return false;\r
216     }\r
217 \r
218     if(!pDev->prm || 0 == pDev->prmLen)\r
219     {\r
220         printf("     Not exist any support method..\n\n");\r
221         return false;\r
222     }\r
223 \r
224     bool bAvailable = true;\r
225     for(size_t i=0; i<pDev->prmLen; i++)\r
226     {\r
227         printf("     [%ld] ", i+1);\r
228         switch (pDev->prm[i])\r
229         {\r
230             case DP_PRE_CONFIGURED:\r
231                 printf("Pre-Configured PIN");\r
232                 break;\r
233             case DP_RANDOM_PIN:\r
234                 printf("Random PIN");\r
235                 break;\r
236             default:\r
237                 printf("NOT Allowed (%d)", pDev->prm[i]);\r
238                 bAvailable = false;\r
239                 break;\r
240         }\r
241         printf("\n");\r
242     }\r
243     printf("\n");\r
244 \r
245     return bAvailable;\r
246 }\r
247 \r
248 // This is a function called back when a device is discovered\r
249 OCStackApplicationResult discoveryReqCB(void*, OCDoHandle,\r
250         OCClientResponse * clientResponse)\r
251 {\r
252     OIC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");\r
253 \r
254     if (clientResponse)\r
255     {\r
256         OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));\r
257         OIC_LOG_V(INFO, TAG,\r
258                 "Device =============> Discovered @ %s:%d",\r
259                 clientResponse->devAddr.addr,\r
260                 clientResponse->devAddr.port);\r
261 \r
262         if (clientResponse->result == OC_STACK_OK)\r
263         {\r
264             OIC_LOG_PAYLOAD(INFO, clientResponse->payload);\r
265         }\r
266     }\r
267 \r
268     return OC_STACK_DELETE_TRANSACTION;\r
269 \r
270 }\r
271 \r
272 // This is a function called back when direct-pairing status is changed\r
273 void pairingReqCB(void *ctx, OCDPDev_t* peer, OCStackResult result)\r
274 {\r
275     OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing establishment\n");\r
276 \r
277     (void) ctx;\r
278     if (OC_STACK_OK == result)\r
279     {\r
280         OIC_LOG_V(INFO, TAG,\r
281                 "Direct-Pairing SUCCESS =============> Target @ %s:%d\n",\r
282                 peer->endpoint.addr,\r
283                 peer->endpoint.port);\r
284     }\r
285     else\r
286     {\r
287         OIC_LOG(ERROR, TAG, "Direct-Pairing FAILED..\n");\r
288     }\r
289 }\r
290 \r
291 OCStackApplicationResult getReqCB(void * ctx, OCDoHandle handle, OCClientResponse *clientResponse)\r
292 {\r
293     OIC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");\r
294 \r
295     (void)ctx;\r
296     (void)handle;\r
297     if (clientResponse)\r
298     {\r
299         OIC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));\r
300         OIC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);\r
301         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);\r
302         if ((OCSecurityPayload*)clientResponse->payload)\r
303         {\r
304             OIC_LOG(INFO, TAG, PCF("=============> Get Response"));\r
305         }\r
306     }\r
307     return OC_STACK_DELETE_TRANSACTION;\r
308 }\r
309 \r
310 int DeviceDiscovery()\r
311 {\r
312     OCStackResult ret;\r
313     OCCallbackData cbData;\r
314     char queryUri[200];\r
315     char ipaddr[100] = { '\0' };\r
316 \r
317     snprintf(queryUri, sizeof (queryUri), DISCOVERY_QUERY, ipaddr);\r
318 \r
319     cbData.cb = discoveryReqCB;\r
320     cbData.context = NULL;\r
321     cbData.cd = NULL;\r
322 \r
323     /* Start a discovery query*/\r
324     OIC_LOG_V(INFO, TAG, "Resource Discovery : %s\n", queryUri);\r
325 \r
326     ret = OCDoResource(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,\r
327                        OC_LOW_QOS, &cbData, NULL, 0);\r
328     if (ret != OC_STACK_OK)\r
329     {\r
330         OIC_LOG(ERROR, TAG, "OCStack resource error");\r
331     }\r
332     return ret;\r
333 }\r
334 \r
335 OCStackResult DirectPairingDiscovery()\r
336 {\r
337     // initiate direct pairing discovery\r
338     OIC_LOG(INFO, TAG, "   Discovering Only Owned Devices on Network..");\r
339     discoveredDevs = OCDiscoverDirectPairingDevices(DP_DISCOVERY_TIMEOUT);\r
340     if(NULL == discoveredDevs)\r
341     {\r
342         OIC_LOG(ERROR, TAG, "OCDiscoverDirectPairingDevices API error");\r
343         return OC_STACK_ERROR;\r
344     }\r
345 \r
346     // display the discovered unowned list\r
347     printf("   > Discovered Direct-Pairing Support Devices\n");\r
348     printList(discoveredDevs);\r
349 \r
350     return OC_STACK_OK;\r
351 }\r
352 \r
353 OCStackResult DoDirectPairing(OCDPDev_t* peer, OCPrm_t pmSel, char *pinNumber)\r
354 {\r
355     if (NULL == peer || NULL == pinNumber)\r
356     {\r
357         OIC_LOG(ERROR, TAG, "invalid parameter");\r
358         return OC_STACK_INVALID_PARAM;\r
359     }\r
360 \r
361     // start direct pairing\r
362     OIC_LOG(INFO, TAG, "   Start Direct Pairing..");\r
363     if(OC_STACK_OK != OCDoDirectPairing(NULL, peer, pmSel, pinNumber, pairingReqCB))\r
364     {\r
365         OIC_LOG(ERROR, TAG, "OCDoDirectPairing API error");\r
366         return OC_STACK_ERROR;\r
367     }\r
368 \r
369     return OC_STACK_OK;\r
370 }\r
371 \r
372 OCStackResult SendGetRequest(OCDPDev_t* peer)\r
373 {\r
374     OIC_LOG(INFO, TAG, "Send Get REQ to Led server");\r
375 \r
376     char szQueryUri[] = "/a/led";\r
377     OCDoHandle handle;\r
378     OCCallbackData cbData;\r
379     OCDevAddr endpoint;\r
380     OCStackResult ret;\r
381 \r
382     memcpy(&endpoint, &peer->endpoint, sizeof(OCDevAddr));\r
383     endpoint.port = peer->securePort;\r
384     endpoint.flags = (OCTransportFlags)(endpoint.flags | OC_SECURE);\r
385 \r
386     cbData.cb = getReqCB;\r
387     cbData.context = NULL;\r
388     cbData.cd = NULL;\r
389 \r
390     OIC_LOG(INFO, TAG, "Request to /a/light ");\r
391     ret = OCDoResource(&handle, OC_REST_GET, szQueryUri,\r
392                &endpoint, NULL, peer->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
393     if (ret != OC_STACK_OK)\r
394     {\r
395         OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, OC_REST_GET);\r
396     }\r
397 \r
398     return ret;\r
399 }\r
400 \r
401 FILE* client_fopen(const char *path, const char *mode)\r
402 {\r
403     (void)path;\r
404     return fopen(CRED_FILE, mode);\r
405 }\r
406 \r
407 void *CLInterface(void *data)\r
408 {\r
409     printf(RED_BEGIN"#Ready to operation ('h' for help)#\n"COLOR_END);\r
410 \r
411     (void)data;\r
412     OCStackResult ret;\r
413     char query[MAX_LINE] = {0,};\r
414     const char prompt[] = BOLD_BEGIN"IoTivity-DP#"COLOR_END" ";\r
415     const char* helpmsg[6] = {\r
416             GREEN_BEGIN"# h  (or help) : show help message"COLOR_END,\r
417             GREEN_BEGIN"# dd (DP device discovery) : discover Direct-Pairing devices"COLOR_END,\r
418             GREEN_BEGIN"# dp (start Direct-Pairing) : negotiate DP method & start Direct-Pairing"COLOR_END,\r
419             GREEN_BEGIN"# sd (send data) : send data to device"COLOR_END,\r
420             GREEN_BEGIN"# ll (list all device) : list all discovered/paired devices"COLOR_END,\r
421             GREEN_BEGIN"# q  (quit) : quit test"COLOR_END,\r
422         };\r
423 \r
424     for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)\r
425     {\r
426         fprintf(stderr, "%s\n", helpmsg[i]);\r
427     }\r
428     printf("\n");\r
429 \r
430     // cli\r
431     for (;;)\r
432     {\r
433         const char *input = readline(prompt, NULL);\r
434         if (!input) {\r
435             continue;\r
436         }\r
437 \r
438         strncpy(query, input, MAX_LINE);\r
439         if (!strlen(query))\r
440         {\r
441             continue;\r
442         }\r
443         else if (!strcmp(query, "h") || !strcmp(query, "help"))\r
444         {\r
445             for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)\r
446             {\r
447                 fprintf(stderr, "%s\n", helpmsg[i]);\r
448             }\r
449             continue;\r
450         }\r
451         else\r
452         {\r
453             if (!strcmp(query, "dd"))\r
454             {\r
455                 OIC_LOG(INFO, TAG, "- Direct-Pairing device discovery -");\r
456 \r
457                 ret = DirectPairingDiscovery();\r
458                 if (OC_STACK_OK != ret)\r
459                 {\r
460                     OIC_LOG(ERROR, TAG, "Error in DirectPairingDiscovery()");\r
461                 }\r
462             }\r
463             else if (!strcmp(query, "dp"))\r
464             {\r
465                 OIC_LOG(INFO, TAG, "- Negotiate DP method & Start Direct-Pairing -");\r
466 \r
467                 printf("\n   * List of  discovered device\n");\r
468                 printList(discoveredDevs);\r
469 \r
470                 // target peer\r
471                 OCDPDev_t *peer = NULL;\r
472                 long peerIdx;\r
473                 input = readline("   > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);\r
474                 if (!input || !strlen(input))\r
475                 {\r
476                     continue;\r
477                 }\r
478                 char *ptr;\r
479                 peerIdx = strtol(input, &ptr, 10);\r
480 \r
481                 peer = getDev(discoveredDevs, (uint32_t)peerIdx);\r
482                 if (NULL == peer)\r
483                 {\r
484                     OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");\r
485                     continue;\r
486                 }\r
487 \r
488                 // get pairing method\r
489                 long pmIdx;\r
490                 OCPrm_t pmSel = DP_NOT_ALLOWED;\r
491                 if (false == printPairingMethod(peer))\r
492                 {\r
493                     OIC_LOG(ERROR, TAG, "Target does not support the Direct-Pairing");\r
494                     continue;\r
495                 }\r
496                 input = readline("   > Enter pairing method: ", NULL);\r
497                 if (!input || !strlen(input))\r
498                 {\r
499                     continue;\r
500                 }\r
501                 pmIdx = strtol(input, &ptr, 10);\r
502                 printf("\n");\r
503                 if (0 >= pmIdx || peer->prmLen+1 < (size_t)pmIdx)\r
504                 {\r
505                     OIC_LOG(ERROR, TAG, "Invalid mode selection");\r
506                     continue;\r
507                 }\r
508                 pmSel = peer->prm[pmIdx-1];\r
509 \r
510                 // get PIN\r
511                 char pinNumber[DP_PIN_LENGTH+1];\r
512                 input = readline("   > Enter PIN Number for authentication (ex - '00000000' [8 digit] ): ", NULL);\r
513                 if (!input || DP_PIN_LENGTH != strlen(input))\r
514                 {\r
515                     OIC_LOG(ERROR, TAG, "Invalid PIN");\r
516                     continue;\r
517                 }\r
518                 sscanf(input, "%8s", pinNumber);\r
519                 printf("\n");\r
520 \r
521                 ret = DoDirectPairing(peer, pmSel, pinNumber);\r
522                 if (OC_STACK_OK != ret)\r
523                 {\r
524                     OIC_LOG(ERROR, TAG, "Error in DoDirectPairing()");\r
525                 }\r
526             }\r
527             else if (!strcmp(query, "sd"))\r
528             {\r
529                 OIC_LOG(INFO, TAG, "- Send data(GET Request) to device(led server) -");\r
530 \r
531                 //pairedDevs = OCGetDirectPairedDevices();\r
532                 //printList(pairedDevs);\r
533                 printList(discoveredDevs);\r
534 \r
535                 // target peer\r
536                 OCDPDev_t *peer = NULL;\r
537                 long peerIdx;\r
538                 input = readline("   > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);\r
539                 if (!input || !strlen(input))\r
540                 {\r
541                     continue;\r
542                 }\r
543                 char *ptr;\r
544                 peerIdx = strtol(input, &ptr, 10);\r
545 \r
546                 //peer = getDev(pairedDevs, peerIdx);\r
547                 peer = getDev(discoveredDevs, (uint32_t)peerIdx);\r
548                 if (NULL == peer)\r
549                 {\r
550                     OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");\r
551                     continue;\r
552                 }\r
553 \r
554                 // send Get Req\r
555                 ret = SendGetRequest(peer);\r
556                 if (OC_STACK_OK != ret)\r
557                 {\r
558                     OIC_LOG(ERROR, TAG, "Error in SendGetRequest()");\r
559                 }\r
560             }\r
561             else if (!strcmp(query, "ll"))\r
562             {\r
563                 OIC_LOG(INFO, TAG, "- List all discovered and paired devices) -");\r
564 \r
565                 printf("  > List of discovered devices\n");\r
566                 printList(discoveredDevs);\r
567                 printf("\n");\r
568 \r
569                 printf("  > List of paired devices\n");\r
570                 pairedDevs = OCGetDirectPairedDevices();\r
571                 printList(pairedDevs);\r
572                 printf("\n");\r
573             }\r
574             else if (!strcmp(query, "q"))\r
575             {\r
576                 printf("QUIT\n");\r
577                 gQuitFlag = 1;\r
578                 break;\r
579             }\r
580         }\r
581     }\r
582 \r
583     return 0;\r
584 }\r
585 \r
586 int main(void)\r
587 {\r
588     struct timespec timeout;\r
589 \r
590     // Initialize Persistent Storage for SVR database\r
591     OCPersistentStorage ps = { client_fopen, fread, fwrite, fclose, unlink };\r
592     OCRegisterPersistentStorageHandler(&ps);\r
593 \r
594     /* Initialize OCStack*/\r
595     if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)\r
596     {\r
597         OIC_LOG(ERROR, TAG, "OCStack init error");\r
598         return 0;\r
599     }\r
600 \r
601 //    DeviceDiscovery();\r
602 \r
603     timeout.tv_sec  = 0;\r
604     timeout.tv_nsec = 100000000L;\r
605 \r
606     // Break from loop with Ctrl+C\r
607     OIC_LOG(INFO, TAG, "Entering occlient main loop...");\r
608     signal(SIGINT, handleSigInt);\r
609 \r
610     // CLI\r
611     int thr_id;\r
612     pthread_t p_thread;\r
613     thr_id = pthread_create(&p_thread, NULL, CLInterface, (void *)NULL);\r
614     if (thr_id < 0)\r
615     {\r
616         OIC_LOG(ERROR, TAG, "create CLI Thread error");\r
617         return 0;\r
618     }\r
619 \r
620     // loop\r
621     while (!gQuitFlag)\r
622     {\r
623         if (OCProcess() != OC_STACK_OK)\r
624         {\r
625             OIC_LOG(ERROR, TAG, "OCStack process error");\r
626             return 0;\r
627         }\r
628 \r
629         nanosleep(&timeout, NULL);\r
630     }\r
631     OIC_LOG(INFO, TAG, "Exiting occlient main loop...");\r
632 \r
633     if (OCStop() != OC_STACK_OK)\r
634     {\r
635         OIC_LOG(ERROR, TAG, "OCStack stop error");\r
636     }\r
637 \r
638     return 0;\r
639 }\r
640 \r
641 \r
642 \r