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