45af1182bfc670fb89a2eb14977b0bfc912d795e
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / occlientbasicops.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 //      http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <stdint.h>
26 #include <sstream>
27
28 #include "ocstack.h"
29 #include "logger.h"
30 #include "occlientbasicops.h"
31 #include "cJSON.h"
32 #include "oic_malloc.h"
33 #include "oic_string.h"
34
35 #define MAX_IP_ADDR_ST_SZ  16 //string size of "155.255.255.255" (15 + 1)
36 #define MAX_PORT_ST_SZ  6     //string size of "65535" (5 + 1)
37
38 static int IPV4_ADDR_SIZE = 16;
39 static int UNICAST_DISCOVERY = 0;
40 static int TEST_CASE = 0;
41
42 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s:6298/oic/res";
43 static std::string putPayload = "{\"oic\":[{\"rep\":{\"power\":15,\"state\":true}}]}";
44
45 //The following variable determines the interface protocol (IP, etc)
46 //to be used for sending unicast messages. Default set to IP.
47 static OCConnectivityType OC_CONNTYPE = CT_ADAPTER_IP;
48 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
49
50 int gQuitFlag = 0;
51
52 struct ResourceNode *resourceList;
53 /*
54  * SIGINT handler: set gQuitFlag to 1 for graceful termination
55  * */
56 void handleSigInt(int signum)
57 {
58     if (signum == SIGINT)
59     {
60         gQuitFlag = 1;
61     }
62 }
63
64 static void PrintUsage()
65 {
66     OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
67     OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
68     OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
69     OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
70             " Initiate Nonconfirmable Get/Put/Post Requests");
71     OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
72             "Confirmable Get/Put/Post Requests");
73     OC_LOG(INFO, TAG, "-c <0|1> : IPv4/IPv6 (IPv6 not currently supported)");
74     OC_LOG(INFO, TAG, "Default connectivityType IPv4");
75 }
76
77 /*
78  * Returns the first resource in the list
79  */
80 const ResourceNode * getResource()
81 {
82     return resourceList;
83 }
84
85 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
86                                  OCConnectivityType connType, OCQualityOfService qos,
87         OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
88 {
89     OCStackResult ret;
90     OCCallbackData cbData;
91
92     cbData.cb = cb;
93     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
94     cbData.cd = NULL;
95
96     ret = OCDoResource(NULL, method, query.str().c_str(), 0,
97         (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload.c_str() : NULL,
98          connType, qos, &cbData, options, numOptions);
99
100     if (ret != OC_STACK_OK)
101     {
102         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
103                  ret, method);
104     }
105
106     return ret;
107 }
108
109 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle,
110                                 OCClientResponse * clientResponse)
111 {
112     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
113     {
114         OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
115     }
116     else
117     {
118         OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
119     }
120
121     if(clientResponse)
122     {
123         OC_LOG_V(INFO, TAG,"PUT Response: %s \nFrom %s:%d\n",
124                  clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
125     }
126     else
127     {
128         OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
129     }
130     return OC_STACK_DELETE_TRANSACTION;
131 }
132
133 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle,
134                           OCClientResponse *clientResponse)
135 {
136     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
137     {
138         OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
139     }
140     else
141     {
142         OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
143     }
144
145     if(clientResponse)
146     {
147         OC_LOG_V(INFO, TAG,"POST Response: %s \nFrom %s:%d\n",
148                     clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
149     }
150     else
151     {
152         OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
153     }
154
155     return OC_STACK_DELETE_TRANSACTION;
156 }
157
158 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
159                            OCClientResponse * clientResponse)
160 {
161     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
162     {
163         OC_LOG(INFO, TAG, "<====Callback Context for GET received successfully====>");
164     }
165     else
166     {
167         OC_LOG(ERROR, TAG, "<====Callback Context for GET fail====>");
168     }
169
170     if (clientResponse)
171     {
172         OC_LOG_V(INFO, TAG,"Get Response: %s \nFrom %s:%d\n",
173                 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
174
175         if (clientResponse->rcvdVendorSpecificHeaderOptions
176                 && clientResponse->numRcvdVendorSpecificHeaderOptions)
177         {
178             OC_LOG (INFO, TAG, "Received vendor specific options");
179             uint8_t i = 0;
180             OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
181             for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
182             {
183                 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
184                 {
185                     OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
186                             ((OCHeaderOption)rcvdOptions[i]).optionID );
187
188                     OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
189                         MAX_HEADER_OPTION_DATA_LENGTH);
190                 }
191             }
192         }
193     }
194     else
195     {
196         OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
197     }
198     return OC_STACK_DELETE_TRANSACTION;
199 }
200
201 /*
202  * This is a function called back when a device is discovered
203  */
204 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
205         OCClientResponse * clientResponse)
206 {
207     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
208     {
209         OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
210                "received successfully====>");
211     }
212     else
213     {
214         OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
215     }
216
217     if (clientResponse)
218     {
219         OC_LOG_V(INFO, TAG,
220                 "Device Discovered %s \n @ %s:%d\n",
221                 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
222
223         collectUniqueResource(clientResponse);
224     }
225     else
226     {
227         OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
228     }
229     return (UNICAST_DISCOVERY) ?
230            OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
231 }
232
233 int InitPutRequest(OCQualityOfService qos)
234 {
235     std::ostringstream query;
236     //Get most recently inserted resource
237     const ResourceNode * resource  = getResource();
238
239     if(!resource)
240     {
241         OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
242         return -1;
243     }
244     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
245     OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
246
247     return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
248            ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
249             putReqCB, NULL, 0));
250 }
251
252 int InitPostRequest(OCQualityOfService qos)
253 {
254     OCStackResult result;
255     std::ostringstream query;
256     //Get most recently inserted resource
257     const ResourceNode * resource  = getResource();
258
259     if(!resource)
260     {
261         OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
262         return -1;
263     }
264
265     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
266     OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
267
268     // First POST operation (to create an LED instance)
269     result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
270             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
271             postReqCB, NULL, 0);
272     if (OC_STACK_OK != result)
273     {
274         // Error can happen if for example, network connectivity is down
275         OC_LOG(ERROR, TAG, "First POST call did not succeed");
276     }
277
278     // Second POST operation (to create an LED instance)
279     result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
280             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
281             postReqCB, NULL, 0);
282     if (OC_STACK_OK != result)
283     {
284         OC_LOG(ERROR, TAG, "Second POST call did not succeed");
285     }
286
287     // This POST operation will update the original resourced /a/led
288     return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
289                 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
290                 postReqCB, NULL, 0));
291 }
292
293 int InitGetRequest(OCQualityOfService qos)
294 {
295     std::ostringstream query;
296     //Get most recently inserted resource
297     const ResourceNode * resource  = getResource();
298
299     if(!resource)
300     {
301         OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
302         return -1;
303     }
304     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
305     OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
306
307     return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
308             (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
309 }
310
311 int InitDiscovery()
312 {
313     OCStackResult ret;
314     OCCallbackData cbData;
315     /* Start a discovery query*/
316     char szQueryUri[64] = {};
317     if (UNICAST_DISCOVERY)
318     {
319         char ipv4addr[IPV4_ADDR_SIZE];
320         printf("Enter IPv4 address of the Server hosting "
321                "resource (Ex: 192.168.0.15)\n");
322         if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
323         {
324             //Strip newline char from ipv4addr
325             StripNewLineChar(ipv4addr);
326             snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
327         }
328         else
329         {
330             OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
331             return OC_STACK_INVALID_PARAM;
332         }
333     }
334     else
335     {
336         strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
337     }
338     cbData.cb = discoveryReqCB;
339     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
340     cbData.cd = NULL;
341     if (UNICAST_DISCOVERY)
342     {
343         ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
344                 OC_LOW_QOS, &cbData, NULL, 0);
345     }
346     else
347     {
348         ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT,
349                 OC_LOW_QOS, &cbData, NULL, 0);
350     }
351
352     if (ret != OC_STACK_OK)
353     {
354         OC_LOG(ERROR, TAG, "OCStack resource error");
355     }
356     return ret;
357 }
358
359 const char *getIPAddr(const OCClientResponse *clientResponse)
360 {
361     if (!clientResponse)
362     {
363         return "";
364     }
365
366     const OCDevAddr *devAddr = &clientResponse->devAddr;
367     char *ipaddr = (char *) OICCalloc(1, strlen(devAddr->addr));
368     if (ipaddr)
369     {
370         snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%s", devAddr->addr);
371     }
372     else
373     {
374         OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
375     }
376     return ipaddr;
377 }
378
379 const char *getPort(const OCClientResponse *clientResponse)
380 {
381     if(!clientResponse)
382     {
383         return "";
384     }
385
386     char *port = NULL;
387     if((port = (char *)OICCalloc(1, MAX_PORT_ST_SZ)))
388     {
389         snprintf(port, MAX_PORT_ST_SZ, "%d", clientResponse->devAddr.port);
390     }
391     else
392     {
393         OC_LOG(ERROR, TAG, "Memory not allocated to port");
394     }
395     return port;
396 }
397
398 int parseJSON(const char * resJSONPayload, char ** sid_c,
399               char *** uri_c, int * totalRes)
400 {
401     cJSON * root = NULL;
402     cJSON * oc = NULL;
403
404     root = cJSON_Parse((char *)(resJSONPayload));
405
406     if (!root)
407     {
408         OC_LOG(ERROR, TAG, "JSON Parsing Error");
409         return OC_STACK_INVALID_JSON;
410     }
411
412     oc = cJSON_GetObjectItem(root,"oic");
413     if (!oc)
414     {
415         OC_LOG(ERROR, TAG, "Invalid JSON : Missing oc object");
416         return OC_STACK_INVALID_JSON;
417     }
418
419     * totalRes = cJSON_GetArraySize(oc);
420
421     if(oc->type == cJSON_Array)
422     {
423         cJSON * resource = cJSON_GetArrayItem(oc, 0);
424
425         if(!resource)
426         {
427             return OC_STACK_INVALID_JSON;
428         }
429
430         if (cJSON_GetObjectItem(resource, "sid"))
431         {
432             char * sid = cJSON_GetObjectItem(resource, "sid")->valuestring;
433             if((* sid_c = (char *)OICCalloc(1, strlen (sid) + 1)))
434             {
435                 memcpy(* sid_c, sid, strlen(sid) + 1);
436             }
437             else
438             {
439                 OC_LOG(ERROR, TAG, "Memory not allocated to sid");
440                 return OC_STACK_NO_MEMORY;
441             }
442         }
443         else
444         {
445             OC_LOG(ERROR, TAG, "Invalid JSON : Missing sid object");
446             return OC_STACK_INVALID_JSON;
447         }
448
449         if(!(* uri_c =  (char ** )OICMalloc ((* totalRes) * sizeof(char *))))
450         {
451             OC_LOG(ERROR, TAG, "Memory not allocated to uri_c array");
452             return OC_STACK_NO_MEMORY;
453         }
454
455         int i = 0;
456
457         while(true)
458         {
459             if (cJSON_GetObjectItem(resource, "href"))
460             {
461                 char *uri= cJSON_GetObjectItem(resource, "href")->valuestring;
462                 if(((*uri_c)[i] = (char *)OICCalloc(1, strlen (uri) + 1)))
463                 {
464                     memcpy((*uri_c)[i], uri, strlen(uri) + 1);
465                 }
466                 else
467                 {
468                     OC_LOG(ERROR, TAG, "Memory not allocated to uri");
469                     return OC_STACK_NO_MEMORY;
470                 }
471                 i++;
472                 if(i >= (* totalRes))
473                     break;
474                 resource = cJSON_GetArrayItem(oc, i);
475             }
476             else
477             {
478                OC_LOG(ERROR, TAG, "Invalid JSON : Missing uri object");
479                return OC_STACK_INVALID_JSON;
480            }
481         }
482     }
483     else
484     {
485         return OC_STACK_INVALID_JSON;
486         OC_LOG(ERROR, TAG, "Invalid JSON : oc object type is not an array");
487     }
488     return OC_STACK_OK;
489 }
490
491 void queryResource()
492 {
493     printf("\n");
494     switch(TEST_CASE)
495     {
496         case TEST_DISCOVER_REQ:
497             break;
498         case TEST_NON_CON_OP:
499             InitGetRequest(OC_LOW_QOS);
500             InitPutRequest(OC_LOW_QOS);
501             InitPostRequest(OC_LOW_QOS);
502             break;
503         case TEST_CON_OP:
504             InitGetRequest(OC_HIGH_QOS);
505             InitPutRequest(OC_HIGH_QOS);
506             InitPostRequest(OC_HIGH_QOS);
507             break;
508         default:
509             PrintUsage();
510             break;
511     }
512     printf("\n");
513 }
514
515
516 void collectUniqueResource(const OCClientResponse * clientResponse)
517 {
518     char * sid = NULL;
519     char ** uri = NULL;
520     int totalRes = 0;
521     int i;
522
523     if(parseJSON(clientResponse->resJSONPayload, & sid, & uri, &totalRes)
524             != OC_STACK_OK)
525     {
526         OC_LOG(ERROR, TAG, "Error while parsing JSON payload in OCClientResponse");
527
528         OICFree(sid);
529         for (i = 0; i < totalRes; i++)
530         {
531             OICFree(uri[i]);
532         }
533         OICFree(uri);
534
535        return;
536     }
537
538     for(i = 0; i < totalRes; i++)
539     {
540         if(insertResource(sid, uri[i], clientResponse) == 1)
541         {
542             printf("%s%s%s%s\n",sid, ":", uri[i], " is new");
543             printResourceList();
544             queryResource();
545         }
546         else
547         {
548             printf("%s%s%s%s\n\n",sid, ":", uri[i], " has been seen before");
549         }
550     }
551
552     OICFree(sid);
553     for (i = 0; i < totalRes; i++)
554     {
555         OICFree(uri[i]);
556     }
557     OICFree(uri);
558 }
559
560 /* This function searches for the resource(sid:uri) in the ResourceList.
561  * If the Resource is found in the list then it returns 0 else insert
562  * the resource to front of the list and returns 1.
563  */
564 int insertResource(const char * sid, char const * uri,
565             const OCClientResponse * clientResponse)
566 {
567     ResourceNode * iter = resourceList;
568     char * sid_cpy =  OICStrdup(sid);
569     char * uri_cpy = OICStrdup(uri);
570
571     //Checking if the resource(sid:uri) is new
572     while(iter)
573     {
574         if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
575         {
576             OICFree(sid_cpy);
577             OICFree(uri_cpy);
578             return 0;
579         }
580         else
581         {
582             iter = iter->next;
583         }
584     }
585
586     //Creating new ResourceNode
587     if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
588     {
589         iter->sid = sid_cpy;
590         iter->uri = uri_cpy;
591         iter->ip = getIPAddr(clientResponse);
592         iter->port = getPort(clientResponse);
593         iter->connType = clientResponse->connType;
594         iter->next = NULL;
595     }
596     else
597     {
598         OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
599         OICFree(sid_cpy);
600         OICFree(uri_cpy);
601         return -1;
602     }
603
604     //Adding new ResourceNode to front of the ResourceList
605     if(!resourceList)
606     {
607         resourceList = iter;
608     }
609     else
610     {
611         iter->next = resourceList;
612         resourceList = iter;
613     }
614     return 1;
615 }
616
617 void printResourceList()
618 {
619     ResourceNode * iter;
620     iter = resourceList;
621     printf("\nResource List\n");
622     while(iter)
623     {
624         printf("*****************************************************\n");
625         printf("sid = %s \n",iter->sid);
626         printf("uri = %s\n", iter->uri);
627         printf("ip = %s\n", iter->ip);
628         printf("port = %s\n", iter->port);
629         switch (iter->connType & CT_MASK_ADAPTER)
630         {
631             case CT_ADAPTER_IP:
632                 printf("connType = %s\n","IPv4");
633                 break;
634             case OC_ADAPTER_GATT_BTLE:
635                 printf("connType = %s\n","BLE");
636                 break;
637             case OC_ADAPTER_RFCOMM_BTEDR:
638                 printf("connType = %s\n","BT");
639                 break;
640             default:
641                 printf("connType = %s\n","Invalid connType");
642                 break;
643         }
644         printf("*****************************************************\n");
645         iter = iter->next;
646     }
647 }
648
649 void freeResourceList()
650 {
651     OC_LOG(INFO, TAG, "Freeing ResourceNode List");
652     ResourceNode * temp;
653     while(resourceList)
654     {
655         temp = resourceList;
656         resourceList = resourceList->next;
657         OICFree((void *)temp->sid);
658         OICFree((void *)temp->uri);
659         OICFree((void *)temp->ip);
660         OICFree((void *)temp->port);
661         OICFree(temp);
662     }
663     resourceList = NULL;
664 }
665
666 int main(int argc, char* argv[])
667 {
668     int opt;
669     resourceList = NULL;
670     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
671     {
672         switch(opt)
673         {
674             case 'u':
675                 UNICAST_DISCOVERY = atoi(optarg);
676                 break;
677             case 't':
678                 TEST_CASE = atoi(optarg);
679                 break;
680             case 'c':
681                 OC_CONNTYPE = CT_ADAPTER_IP;
682                 break;
683             default:
684                 PrintUsage();
685                 return -1;
686         }
687     }
688
689     if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
690             (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
691     {
692         PrintUsage();
693         return -1;
694     }
695
696     /* Initialize OCStack*/
697     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
698     {
699         OC_LOG(ERROR, TAG, "OCStack init error");
700         return 0;
701     }
702
703     InitDiscovery();
704
705     // Break from loop with Ctrl+C
706     signal(SIGINT, handleSigInt);
707
708     while (!gQuitFlag)
709     {
710         if (OCProcess() != OC_STACK_OK)
711         {
712             OC_LOG(ERROR, TAG, "OCStack process error");
713             return 0;
714         }
715         sleep(2);
716     }
717
718     freeResourceList();
719     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
720     if (OCStop() != OC_STACK_OK)
721     {
722         OC_LOG(ERROR, TAG, "OCStack stop error");
723     }
724     return 0;
725 }
726
727