1f6051d1f8ee5f7e3192c501f132922502ffa36d
[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
211                     OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
212                         MAX_HEADER_OPTION_DATA_LENGTH);
213                 }
214             }
215         }
216     }
217     else
218     {
219         OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
220     }
221     return OC_STACK_DELETE_TRANSACTION;
222 }
223
224 /*
225  * This is a function called back when a device is discovered
226  */
227 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
228         OCClientResponse * clientResponse)
229 {
230     uint8_t remoteIpAddr[4];
231     uint16_t remotePortNu;
232     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
233     {
234         OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
235                "received successfully====>");
236     }
237     else
238     {
239         OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
240     }
241
242     if (clientResponse)
243     {
244         OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
245                 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
246         OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
247
248         OC_LOG_V(INFO, TAG,
249                 "Device Discovered %s \n @ %d.%d.%d.%d:%d\n",
250                 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
251                 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
252
253         collectUniqueResource(clientResponse);
254     }
255     else
256     {
257         OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
258     }
259     return (UNICAST_DISCOVERY) ?
260            OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
261 }
262
263 int InitPutRequest(OCQualityOfService qos)
264 {
265     std::ostringstream query;
266     //Get most recently inserted resource
267     const ResourceNode * resource  = getResource();
268
269     if(!resource)
270     {
271         OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
272         return -1;
273     }
274     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
275     OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
276
277     return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
278            ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
279             putReqCB, NULL, 0));
280 }
281
282 int InitPostRequest(OCQualityOfService qos)
283 {
284     OCStackResult result;
285     std::ostringstream query;
286     //Get most recently inserted resource
287     const ResourceNode * resource  = getResource();
288
289     if(!resource)
290     {
291         OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
292         return -1;
293     }
294
295     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
296     OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
297
298     // First POST operation (to create an LED instance)
299     result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
300             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
301             postReqCB, NULL, 0);
302     if (OC_STACK_OK != result)
303     {
304         // Error can happen if for example, network connectivity is down
305         OC_LOG(ERROR, TAG, "First POST call did not succeed");
306     }
307
308     // Second POST operation (to create an LED instance)
309     result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
310             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
311             postReqCB, NULL, 0);
312     if (OC_STACK_OK != result)
313     {
314         OC_LOG(ERROR, TAG, "Second POST call did not succeed");
315     }
316
317     // This POST operation will update the original resourced /a/led
318     return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
319                 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
320                 postReqCB, NULL, 0));
321 }
322
323 int InitGetRequest(OCQualityOfService qos)
324 {
325     std::ostringstream query;
326     //Get most recently inserted resource
327     const ResourceNode * resource  = getResource();
328
329     if(!resource)
330     {
331         OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
332         return -1;
333     }
334     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
335     OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
336
337     return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
338             (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
339 }
340
341 int InitDiscovery()
342 {
343     OCStackResult ret;
344     OCCallbackData cbData;
345     /* Start a discovery query*/
346     char szQueryUri[64] = {};
347     if (UNICAST_DISCOVERY)
348     {
349         char ipv4addr[IPV4_ADDR_SIZE];
350         printf("Enter IPv4 address of the Server hosting "
351                "resource (Ex: 192.168.0.15)\n");
352         if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
353         {
354             //Strip newline char from ipv4addr
355             StripNewLineChar(ipv4addr);
356             snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
357         }
358         else
359         {
360             OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
361             return OC_STACK_INVALID_PARAM;
362         }
363     }
364     else
365     {
366         strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
367     }
368     cbData.cb = discoveryReqCB;
369     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
370     cbData.cd = NULL;
371     if (UNICAST_DISCOVERY)
372     {
373         ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
374                 OC_LOW_QOS, &cbData, NULL, 0);
375     }
376     else
377     {
378         ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, (OC_ALL),
379                 OC_LOW_QOS, &cbData, NULL, 0);
380     }
381
382     if (ret != OC_STACK_OK)
383     {
384         OC_LOG(ERROR, TAG, "OCStack resource error");
385     }
386     return ret;
387 }
388
389
390
391 const char * getIPAddr(const OCClientResponse * clientResponse)
392 {
393     uint8_t a, b, c, d;
394    if(!clientResponse || 0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d))
395     {
396         return "";
397     }
398
399     char * ipaddr = NULL;
400     if((ipaddr = (char *) OCCalloc(1, MAX_IP_ADDR_ST_SZ)))
401     {
402         snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%d.%d.%d.%d", a,b,c,d);
403     }
404     else
405     {
406         OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
407     }
408     return ipaddr;
409 }
410
411 const char * getPort(const OCClientResponse * clientResponse)
412 {
413     uint16_t p = 0;
414     if(!clientResponse || 0 != OCDevAddrToPort(clientResponse->addr, &p) )
415     {
416         return "";
417     }
418
419     char * port = NULL;
420     if((port = (char *) OCCalloc(1, MAX_PORT_ST_SZ)))
421     {
422         snprintf(port, MAX_PORT_ST_SZ, "%d", p);
423     }
424     else
425     {
426         OC_LOG(ERROR, TAG, "Memory not allocated to port");
427     }
428     return port;
429 }
430
431 int parseJSON(const char * resJSONPayload, char ** sid_c,
432               char *** uri_c, int * totalRes)
433 {
434     cJSON * root = NULL;
435     cJSON * oc = NULL;
436
437     root = cJSON_Parse((char *)(resJSONPayload));
438
439     if (!root)
440     {
441         OC_LOG(ERROR, TAG, "JSON Parsing Error");
442         return OC_STACK_INVALID_JSON;
443     }
444
445     oc = cJSON_GetObjectItem(root,"oc");
446     if (!oc)
447     {
448         OC_LOG(ERROR, TAG, "Invalid JSON : Missing oc object");
449         return OC_STACK_INVALID_JSON;
450     }
451
452     * totalRes = cJSON_GetArraySize(oc);
453
454     if(oc->type == cJSON_Array)
455     {
456         cJSON * resource = cJSON_GetArrayItem(oc, 0);
457
458         if(!resource)
459         {
460             return OC_STACK_INVALID_JSON;
461         }
462
463         if (cJSON_GetObjectItem(resource, "sid"))
464         {
465             char * sid = cJSON_GetObjectItem(resource, "sid")->valuestring;
466             if((* sid_c = (char *)OCCalloc(1, strlen (sid) + 1)))
467             {
468                 memcpy(* sid_c, sid, strlen(sid) + 1);
469             }
470             else
471             {
472                 OC_LOG(ERROR, TAG, "Memory not allocated to sid");
473                 return OC_STACK_NO_MEMORY;
474             }
475         }
476         else
477         {
478             OC_LOG(ERROR, TAG, "Invalid JSON : Missing sid object");
479             return OC_STACK_INVALID_JSON;
480         }
481
482         if(!(* uri_c =  (char ** )OCMalloc ((* totalRes) * sizeof(char **))))
483         {
484             OC_LOG(ERROR, TAG, "Memory not allocated to sid_c array");
485             return OC_STACK_NO_MEMORY;
486         }
487
488         int i = 0;
489
490         while(true)
491         {
492             if (cJSON_GetObjectItem(resource, "href"))
493             {
494                 char *uri= cJSON_GetObjectItem(resource, "href")->valuestring;
495                 if(((*uri_c)[i] = (char *)OCCalloc(1, strlen (uri) + 1)))
496                 {
497                     memcpy((*uri_c)[i], uri, strlen(uri) + 1);
498                 }
499                 else
500                 {
501                     OC_LOG(ERROR, TAG, "Memory not allocated to uri");
502                     return OC_STACK_NO_MEMORY;
503                 }
504                 i++;
505                 if(i >= (* totalRes))
506                     break;
507                 resource = cJSON_GetArrayItem(oc, i);
508             }
509             else
510             {
511                OC_LOG(ERROR, TAG, "Invalid JSON : Missing uri object");
512                return OC_STACK_INVALID_JSON;
513            }
514         }
515     }
516     else
517     {
518         return OC_STACK_INVALID_JSON;
519         OC_LOG(ERROR, TAG, "Invalid JSON : oc object type is not an array");
520     }
521     return OC_STACK_OK;
522 }
523
524 void queryResource()
525 {
526     printf("\n");
527     switch(TEST_CASE)
528     {
529         case TEST_DISCOVER_REQ:
530             break;
531         case TEST_NON_CON_OP:
532             InitGetRequest(OC_LOW_QOS);
533             InitPutRequest(OC_LOW_QOS);
534             InitPostRequest(OC_LOW_QOS);
535             break;
536         case TEST_CON_OP:
537             InitGetRequest(OC_HIGH_QOS);
538             InitPutRequest(OC_HIGH_QOS);
539             InitPostRequest(OC_HIGH_QOS);
540             break;
541         default:
542             PrintUsage();
543             break;
544     }
545     printf("\n");
546 }
547
548
549 void collectUniqueResource(const OCClientResponse * clientResponse)
550 {
551     char * sid = NULL;
552     char ** uri = NULL;
553     int totalRes = 0;
554
555     if(parseJSON(clientResponse->resJSONPayload, & sid, & uri, &totalRes)
556             != OC_STACK_OK)
557     {
558         OC_LOG(ERROR, TAG, "Error while parsing JSON payload in OCClientResponse");
559     }
560
561     int i;
562     for(i = 0; i < totalRes; i++)
563     {
564         if(insertResource(sid, uri[i], clientResponse) == 1)
565         {
566             printf("%s%s%s%s\n",sid, ":", uri[i], " is new");
567             printResourceList();
568             queryResource();
569         }
570         else
571         {
572             printf("%s%s%s%s\n\n",sid, ":", uri[i], " has been seen before");
573         }
574     }
575
576     OCFree(uri);
577  }
578
579 /* This function searches for the resource(sid:uri) in the ResourceList.
580  * If the Resource is found in the list then it returns 0 else insert
581  * the resource to front of the list and returns 1.
582  */
583 int insertResource(const char * sid, char const * uri,
584             const OCClientResponse * clientResponse)
585 {
586     ResourceNode * iter = resourceList;
587
588     //Checking if the resource(sid:uri) is new
589     while(iter)
590     {
591         if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
592         {
593             return 0;
594         }
595         else
596         {
597             iter = iter->next;
598         }
599     }
600
601     //Creating new ResourceNode
602     if((iter = (ResourceNode *) OCMalloc(sizeof(ResourceNode))))
603     {
604         iter->sid = sid;
605         iter->uri = uri;
606         iter->ip = getIPAddr(clientResponse);
607         iter->port = getPort(clientResponse);
608         iter->connType = clientResponse->connType;
609         iter->next = NULL;
610     }
611     else
612     {
613         OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
614         return -1;
615     }
616
617     //Adding new ResourceNode to front of the ResourceList
618     if(!resourceList)
619     {
620         resourceList = iter;
621     }
622     else
623     {
624         iter->next = resourceList;
625         resourceList = iter;
626     }
627     return 1;
628 }
629
630 void printResourceList()
631 {
632     ResourceNode * iter;
633     iter = resourceList;
634     printf("\nResource List\n");
635     while(iter)
636     {
637         printf("*****************************************************\n");
638         printf("sid = %s \n",iter->sid);
639         printf("uri = %s\n", iter->uri);
640         printf("ip = %s\n", iter->ip);
641         printf("port = %s\n", iter->port);
642         switch (iter->connType)
643         {
644             case OC_ETHERNET:
645                 printf("connType = %s\n","Ethernet");
646                 break;
647             case OC_WIFI:
648                 printf("connType = %s\n","WiFi");
649                 break;
650             case OC_LE:
651                 printf("connType = %s\n","BLE");
652                 break;
653             case OC_EDR:
654                 printf("connType = %s\n","BT");
655                 break;
656             case OC_ALL:
657             default:
658                 printf("connType = %s\n","Invalid connType");
659                 break;
660         }
661         printf("*****************************************************\n");
662         iter = iter->next;
663     }
664 }
665
666 void freeResourceList()
667 {
668     OC_LOG(INFO, TAG, "Freeing ResourceNode List");
669     ResourceNode * temp;
670     while(resourceList)
671     {
672         temp = resourceList;
673         resourceList = resourceList->next;
674         OCFree((void *)temp->sid);
675         OCFree((void *)temp->uri);
676         OCFree((void *)temp->ip);
677         OCFree((void *)temp->port);
678         OCFree(temp);
679     }
680 }
681
682 int main(int argc, char* argv[])
683 {
684     int opt;
685     resourceList = NULL;
686     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
687     {
688         switch(opt)
689         {
690             case 'u':
691                 UNICAST_DISCOVERY = atoi(optarg);
692                 break;
693             case 't':
694                 TEST_CASE = atoi(optarg);
695                 break;
696             case 'c':
697                 OC_CONNTYPE = OCConnectivityType(atoi(optarg));
698                 break;
699             default:
700                 PrintUsage();
701                 return -1;
702         }
703     }
704
705     if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
706             (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
707     {
708         PrintUsage();
709         return -1;
710     }
711
712     /* Initialize OCStack*/
713     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
714     {
715         OC_LOG(ERROR, TAG, "OCStack init error");
716         return 0;
717     }
718
719     InitDiscovery();
720
721     // Break from loop with Ctrl+C
722     signal(SIGINT, handleSigInt);
723
724     while (!gQuitFlag)
725     {
726         if (OCProcess() != OC_STACK_OK)
727         {
728             OC_LOG(ERROR, TAG, "OCStack process error");
729             return 0;
730         }
731         sleep(2);
732     }
733
734     freeResourceList();
735     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
736     if (OCStop() != OC_STACK_OK)
737     {
738         OC_LOG(ERROR, TAG, "OCStack stop error");
739     }
740     return 0;
741 }
742
743