Imported Upstream version 0.9.1
[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 protocol (IPv4, IPv6, etc)
45 //to be used for sending unicast messages. Default set to IPv4.
46 static OCConnectivityType OC_CONNTYPE = OC_IPV4;
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> : IPv4/IPv6 (IPv6 not currently supported)");
73     OC_LOG(INFO, TAG, "Default connectivityType IPv4");
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         OCFree(sid);
560         OCFree(uri);
561         return;
562     }
563
564     int i;
565     for(i = 0; i < totalRes; i++)
566     {
567         if(insertResource(sid, uri[i], clientResponse) == 1)
568         {
569             printf("%s%s%s%s\n",sid, ":", uri[i], " is new");
570             printResourceList();
571             queryResource();
572         }
573         else
574         {
575             printf("%s%s%s%s\n\n",sid, ":", uri[i], " has been seen before");
576         }
577     }
578
579     OCFree(sid);
580     OCFree(uri);
581  }
582
583 /* This function searches for the resource(sid:uri) in the ResourceList.
584  * If the Resource is found in the list then it returns 0 else insert
585  * the resource to front of the list and returns 1.
586  */
587 int insertResource(const char * sid, char const * uri,
588             const OCClientResponse * clientResponse)
589 {
590     ResourceNode * iter = resourceList;
591
592     //Checking if the resource(sid:uri) is new
593     while(iter)
594     {
595         if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
596         {
597             return 0;
598         }
599         else
600         {
601             iter = iter->next;
602         }
603     }
604
605     //Creating new ResourceNode
606     if((iter = (ResourceNode *) OCMalloc(sizeof(ResourceNode))))
607     {
608         iter->sid = sid;
609         iter->uri = uri;
610         iter->ip = getIPAddr(clientResponse);
611         iter->port = getPort(clientResponse);
612         iter->connType = clientResponse->connType;
613         iter->next = NULL;
614     }
615     else
616     {
617         OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
618         return -1;
619     }
620
621     //Adding new ResourceNode to front of the ResourceList
622     if(!resourceList)
623     {
624         resourceList = iter;
625     }
626     else
627     {
628         iter->next = resourceList;
629         resourceList = iter;
630     }
631     return 1;
632 }
633
634 void printResourceList()
635 {
636     ResourceNode * iter;
637     iter = resourceList;
638     printf("\nResource List\n");
639     while(iter)
640     {
641         printf("*****************************************************\n");
642         printf("sid = %s \n",iter->sid);
643         printf("uri = %s\n", iter->uri);
644         printf("ip = %s\n", iter->ip);
645         printf("port = %s\n", iter->port);
646         switch (iter->connType)
647         {
648             case OC_IPV4:
649                 printf("connType = %s\n","IPv4");
650                 break;
651             case OC_IPV6:
652                 // TODO: Allow IPv6 when support is added
653                 printf("IPv6 not currently supported, default to IPv4\n");
654                 //printf("connType = %s\n","IPv6");
655                 printf("connType = %s\n","IPv4");
656                 break;
657             case OC_LE:
658                 printf("connType = %s\n","BLE");
659                 break;
660             case OC_EDR:
661                 printf("connType = %s\n","BT");
662                 break;
663             case OC_ALL:
664             default:
665                 printf("connType = %s\n","Invalid connType");
666                 break;
667         }
668         printf("*****************************************************\n");
669         iter = iter->next;
670     }
671 }
672
673 void freeResourceList()
674 {
675     OC_LOG(INFO, TAG, "Freeing ResourceNode List");
676     ResourceNode * temp;
677     while(resourceList)
678     {
679         temp = resourceList;
680         resourceList = resourceList->next;
681         OCFree((void *)temp->sid);
682         OCFree((void *)temp->uri);
683         OCFree((void *)temp->ip);
684         OCFree((void *)temp->port);
685         OCFree(temp);
686     }
687 }
688
689 int main(int argc, char* argv[])
690 {
691     int opt;
692     resourceList = NULL;
693     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
694     {
695         switch(opt)
696         {
697             case 'u':
698                 UNICAST_DISCOVERY = atoi(optarg);
699                 break;
700             case 't':
701                 TEST_CASE = atoi(optarg);
702                 break;
703             case 'c':
704                 // TODO: re-enable IPv4/IPv6 command line selection when IPv6 is supported
705                 // OC_CONNTYPE = OCConnectivityType(atoi(optarg));
706                 OC_CONNTYPE = OC_IPV4;
707                 OC_LOG(INFO, TAG, "Using default IPv4, IPv6 not currently supported.");
708                 break;
709             default:
710                 PrintUsage();
711                 return -1;
712         }
713     }
714
715     if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
716             (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
717     {
718         PrintUsage();
719         return -1;
720     }
721
722     /* Initialize OCStack*/
723     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
724     {
725         OC_LOG(ERROR, TAG, "OCStack init error");
726         return 0;
727     }
728
729     InitDiscovery();
730
731     // Break from loop with Ctrl+C
732     signal(SIGINT, handleSigInt);
733
734     while (!gQuitFlag)
735     {
736         if (OCProcess() != OC_STACK_OK)
737         {
738             OC_LOG(ERROR, TAG, "OCStack process error");
739             return 0;
740         }
741         sleep(2);
742     }
743
744     freeResourceList();
745     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
746     if (OCStop() != OC_STACK_OK)
747     {
748         OC_LOG(ERROR, TAG, "OCStack stop error");
749     }
750     return 0;
751 }
752
753