Clean up the C samples
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / occlient.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 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <iostream>
27 #include <sstream>
28 #include "ocstack.h"
29 #include "logger.h"
30 #include "occlient.h"
31
32 static int UNICAST_DISCOVERY = 0;
33 static int TEST_CASE = 0;
34 static const char * UNICAST_DISCOVERY_QUERY = "coap://%s:5298/oc/core";
35 static const char * UNICAST_DEVICE_DISCOVERY_QUERY = "coap://%s:5298/oc/core/d";
36 static const char * MULTICAST_DEVICE_DISCOVERY_QUERY = "/oc/core/d";
37 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oc/core";
38 //The following variable determines the interface (wifi, ethernet etc.)
39 //to be used for sending unicast messages. Default set to WIFI.
40 static OCConnectivityType OC_CONNTYPE = OC_WIFI;
41 static std::string putPayload = "{\"state\":\"on\",\"power\":5}";
42 static std::string coapServerIP = "255.255.255.255";
43 static std::string coapServerPort = "5683";
44 static std::string coapServerResource = "/a/light";
45 static const int IPV4_ADDR_SIZE = 16;
46 //Use ipv4addr for both InitDiscovery and InitDeviceDiscovery
47 char ipv4addr[IPV4_ADDR_SIZE];
48 void StripNewLineChar(char* str);
49
50 // The handle for the observe registration
51 OCDoHandle gObserveDoHandle;
52 #ifdef WITH_PRESENCE
53 // The handle for observe registration
54 OCDoHandle gPresenceHandle;
55 #endif
56 // After this crosses a threshold client deregisters for further notifications
57 int gNumObserveNotifies = 0;
58
59 #ifdef WITH_PRESENCE
60 int gNumPresenceNotifies = 0;
61 #endif
62
63 int gQuitFlag = 0;
64 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
65 void handleSigInt(int signum) {
66     if (signum == SIGINT) {
67         gQuitFlag = 1;
68     }
69 }
70
71 static void PrintUsage()
72 {
73     OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3|4|5|6|7> -c <0|1>");
74     OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
75     OC_LOG(INFO, TAG, "-c <0|1> : Send unicast messages over Ethernet or WIFI");
76     OC_LOG(INFO, TAG, "-t 1  :  Discover Resources");
77     OC_LOG(INFO, TAG, "-t 2  :  Discover Resources and Initiate Nonconfirmable Get Request");
78     OC_LOG(INFO, TAG, "-t 3  :  Discover Resources and Initiate Nonconfirmable Put Requests");
79     OC_LOG(INFO, TAG, "-t 4  :  Discover Resources and Initiate Nonconfirmable Post Requests");
80     OC_LOG(INFO, TAG, "-t 5  :  Discover Resources and Initiate Nonconfirmable Delete Requests");
81     OC_LOG(INFO, TAG, "-t 6  :  Discover Resources and Initiate Nonconfirmable Observe Requests");
82     OC_LOG(INFO, TAG, "-t 7  :  Discover Resources and Initiate Nonconfirmable Get Request for a resource which is unavailable");
83
84     OC_LOG(INFO, TAG, "-t 8  :  Discover Resources and Initiate Confirmable Get Request");
85     OC_LOG(INFO, TAG, "-t 9  :  Discover Resources and Initiate Confirmable Post Request");
86     OC_LOG(INFO, TAG, "-t 10 :  Discover Resources and Initiate Confirmable Delete Requests");
87     OC_LOG(INFO, TAG, "-t 11 :  Discover Resources and Initiate Confirmable Observe Requests");
88
89     #ifdef WITH_PRESENCE
90     OC_LOG(INFO, TAG, "-t 12 :  Discover Resources and Initiate Nonconfirmable presence");
91     OC_LOG(INFO, TAG, "-t 13 :  Discover Resources and Initiate Nonconfirmable presence with "\
92             "filter");
93     OC_LOG(INFO, TAG, "-t 14 :  Discover Resources and Initiate Nonconfirmable presence with "\
94             "2 filters");
95     #endif
96
97     OC_LOG(INFO, TAG, "-t 15 :  Discover Resources and Initiate Nonconfirmable Observe Requests "\
98             "then cancel immediately");
99     OC_LOG(INFO, TAG, "-t 16 :  Discover Resources and Initiate Nonconfirmable Get Request and "\
100             "add  vendor specific header options");
101     OC_LOG(INFO, TAG, "-t 17 :  Discover Devices");
102 }
103
104 OCStackResult InvokeOCDoResource(std::ostringstream &query,
105                                  OCMethod method, OCQualityOfService qos,
106                                  OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
107 {
108     OCStackResult ret;
109     OCCallbackData cbData;
110     OCDoHandle handle;
111
112     cbData.cb = cb;
113     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
114     cbData.cd = NULL;
115
116     ret = OCDoResource(&handle, method, query.str().c_str(), 0,
117                        (method == OC_REST_PUT) ? putPayload.c_str() : NULL,
118                        (OC_CONNTYPE), qos, &cbData, options, numOptions);
119
120     if (ret != OC_STACK_OK)
121     {
122         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
123     }
124     else if (method == OC_REST_OBSERVE || method == OC_REST_OBSERVE_ALL)
125     {
126         gObserveDoHandle = handle;
127     }
128     #ifdef WITH_PRESENCE
129     else if (method == OC_REST_PRESENCE)
130     {
131         gPresenceHandle = handle;
132     }
133     #endif
134
135     return ret;
136 }
137
138 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
139     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
140     {
141         OC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully");
142     }
143
144     if(clientResponse)
145     {
146         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
147         OC_LOG_V(INFO, TAG, "JSON = %s =============> Put Response", clientResponse->resJSONPayload);
148     }
149     return OC_STACK_DELETE_TRANSACTION;
150 }
151
152 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle, OCClientResponse *clientResponse)
153 {
154     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
155     {
156         OC_LOG(INFO, TAG, "Callback Context for POST recvd successfully");
157     }
158
159     if(clientResponse)
160     {
161         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
162         OC_LOG_V(INFO, TAG, "JSON = %s =============> Post Response", clientResponse->resJSONPayload);
163     }
164     return OC_STACK_DELETE_TRANSACTION;
165 }
166
167 OCStackApplicationResult deleteReqCB(void *ctx, OCDoHandle handle, OCClientResponse *clientResponse)
168 {
169     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
170     {
171         OC_LOG(INFO, TAG, "Callback Context for DELETE recvd successfully");
172     }
173
174     if(clientResponse)
175     {
176         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
177         OC_LOG_V(INFO, TAG, "JSON = %s =============> Delete Response", clientResponse->resJSONPayload);
178     }
179     return OC_STACK_DELETE_TRANSACTION;
180 }
181
182 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
183 {
184     if(clientResponse == NULL)
185     {
186         OC_LOG(INFO, TAG, "The clientResponse is NULL");
187         return   OC_STACK_DELETE_TRANSACTION;
188     }
189     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
190     {
191         OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
192     }
193
194     OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
195     OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
196     OC_LOG_V(INFO, TAG, "JSON = %s =============> Get Response", clientResponse->resJSONPayload);
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     return OC_STACK_DELETE_TRANSACTION;
216 }
217
218 OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
219     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
220     {
221         OC_LOG(INFO, TAG, "Callback Context for OBS query recvd successfully");
222     }
223
224     if(clientResponse)
225     {
226         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
227         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
228         OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumObserveNotifies);
229         OC_LOG_V(INFO, TAG, "JSON = %s =============> Obs Response", clientResponse->resJSONPayload);
230         gNumObserveNotifies++;
231         if (gNumObserveNotifies == 3)   //large number to test observing in DELETE case.
232         {
233             if(TEST_CASE == TEST_OBS_REQ_NON || TEST_CASE == TEST_OBS_REQ_CON){
234                 if (OCCancel (gObserveDoHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK){
235                     OC_LOG(ERROR, TAG, "Observe cancel error");
236                 }
237                 return OC_STACK_DELETE_TRANSACTION;
238             }else if(TEST_CASE == TEST_OBS_REQ_NON_CANCEL_IMM){
239                 if (OCCancel (gObserveDoHandle, OC_HIGH_QOS, NULL, 0) != OC_STACK_OK){
240                     OC_LOG(ERROR, TAG, "Observe cancel error");
241                 }
242             }
243         }
244         if(clientResponse->sequenceNumber == OC_OBSERVE_REGISTER){
245             OC_LOG(INFO, TAG, "This also serves as a registration confirmation");
246         }else if(clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER){
247             OC_LOG(INFO, TAG, "This also serves as a deregistration confirmation");
248             return OC_STACK_DELETE_TRANSACTION;
249         }else if(clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION){
250             OC_LOG(INFO, TAG, "This also tells you that registration/deregistration failed");
251             return OC_STACK_DELETE_TRANSACTION;
252         }
253     }
254     return OC_STACK_KEEP_TRANSACTION;
255 }
256 #ifdef WITH_PRESENCE
257 OCStackApplicationResult presenceCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
258     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
259     {
260         OC_LOG(INFO, TAG, "Callback Context for Presence recvd successfully");
261     }
262
263     if(clientResponse)
264     {
265         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
266         OC_LOG_V(INFO, TAG, "NONCE NUMBER: %u", clientResponse->sequenceNumber);
267         OC_LOG_V(INFO, TAG, "Callback Context for Presence notification recvd successfully %d", gNumPresenceNotifies);
268         OC_LOG_V(INFO, TAG, "JSON = %s =============> Presence Response", clientResponse->resJSONPayload);
269         gNumPresenceNotifies++;
270         if (gNumPresenceNotifies == 20)
271         {
272             if (OCCancel (gPresenceHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK){
273                 OC_LOG(ERROR, TAG, "Presence cancel error");
274             }
275             return OC_STACK_DELETE_TRANSACTION;
276         }
277     }
278     return OC_STACK_KEEP_TRANSACTION;
279 }
280 #endif
281
282 // This is a function called back when a device is discovered
283 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
284         OCClientResponse * clientResponse) {
285     uint8_t remoteIpAddr[4];
286     uint16_t remotePortNu;
287
288     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
289     {
290         OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
291     }
292
293     if (clientResponse)
294     {
295         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
296
297         OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
298                 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
299         OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
300
301         std::string connectionType = getConnectivityType (clientResponse->connType);
302         OC_LOG_V(INFO, TAG, "Discovered on %s", connectionType.c_str());
303         OC_LOG_V(INFO, TAG,
304                 "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
305                 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
306                 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
307
308         parseClientResponse(clientResponse);
309
310         switch(TEST_CASE)
311         {
312             case TEST_GET_REQ_NON:
313                 InitGetRequest(OC_LOW_QOS, 0);
314                 break;
315             case TEST_PUT_REQ_NON:
316                 InitPutRequest();
317                 break;
318             case TEST_POST_REQ_NON:
319                 InitPostRequest(OC_LOW_QOS);
320                 break;
321             case TEST_DELETE_REQ_NON:
322                 InitDeleteRequest(OC_LOW_QOS);
323                 break;
324             case TEST_OBS_REQ_NON:
325             case TEST_OBS_REQ_NON_CANCEL_IMM:
326                 InitObserveRequest(OC_LOW_QOS);
327                 break;
328             case TEST_GET_UNAVAILABLE_RES_REQ_NON:
329                 InitGetRequestToUnavailableResource();
330                 break;
331             case TEST_GET_REQ_CON:
332                 InitGetRequest(OC_HIGH_QOS, 0);
333                 break;
334             case TEST_POST_REQ_CON:
335                 InitPostRequest(OC_HIGH_QOS);
336                 break;
337             case TEST_DELETE_REQ_CON:
338                 InitDeleteRequest(OC_HIGH_QOS);
339                 break;
340             case TEST_OBS_REQ_CON:
341                 InitObserveRequest(OC_HIGH_QOS);
342                 break;
343             #ifdef WITH_PRESENCE
344             case TEST_OBS_PRESENCE:
345             case TEST_OBS_PRESENCE_WITH_FILTER:
346             case TEST_OBS_PRESENCE_WITH_FILTERS:
347                 InitPresence();
348                 break;
349             #endif
350             case TEST_GET_REQ_NON_WITH_VENDOR_HEADER_OPTIONS:
351                 InitGetRequest(OC_LOW_QOS, 1);
352                 break;
353             case TEST_DISCOVER_DEV_REQ:
354                 InitDeviceDiscovery();
355                 break;
356             default:
357                 PrintUsage();
358                 break;
359         }
360     }
361     return OC_STACK_KEEP_TRANSACTION;
362 }
363
364 OCStackApplicationResult DeviceDiscoveryReqCB (void* ctx, OCDoHandle handle,
365         OCClientResponse * clientResponse)
366 {
367     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
368     {
369         OC_LOG(INFO, TAG, "Callback Context for Device DISCOVER query recvd successfully");
370     }
371
372     if(clientResponse)
373     {
374         //OC_LOG truncates the response as it is too long.
375         fprintf(stderr, "Discovery response: \n %s\n", clientResponse->resJSONPayload);
376         fflush(stderr);
377     }
378
379     return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
380 }
381
382 #ifdef WITH_PRESENCE
383 int InitPresence()
384 {
385     OCStackResult result = OC_STACK_OK;
386     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
387     std::ostringstream query;
388     std::ostringstream querySuffix;
389     query << "coap://" << coapServerIP << ":" << coapServerPort << OC_PRESENCE_URI;
390     if(TEST_CASE == TEST_OBS_PRESENCE)
391     {
392         result = InvokeOCDoResource(query, OC_REST_PRESENCE, OC_LOW_QOS,
393                 presenceCB, NULL, 0);
394     }
395     if(TEST_CASE == TEST_OBS_PRESENCE_WITH_FILTER || TEST_CASE == TEST_OBS_PRESENCE_WITH_FILTERS)
396     {
397         querySuffix.str("");
398         querySuffix << query.str() << "?rt=core.light";
399         result = InvokeOCDoResource(querySuffix, OC_REST_PRESENCE, OC_LOW_QOS,
400                 presenceCB, NULL, 0);
401     }
402     if(TEST_CASE == TEST_OBS_PRESENCE_WITH_FILTERS)
403     {
404         if(result == OC_STACK_OK)
405         {
406             querySuffix.str("");
407             querySuffix << query.str() << "?rt=core.fan";
408             result = InvokeOCDoResource(querySuffix, OC_REST_PRESENCE, OC_LOW_QOS,
409                     presenceCB, NULL, 0);
410         }
411     }
412     return result;
413 }
414 #endif
415
416 int InitGetRequestToUnavailableResource()
417 {
418     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
419     std::ostringstream query;
420     query << "coap://" << coapServerIP << ":" << coapServerPort << "/SomeUnknownResource";
421     return (InvokeOCDoResource(query, OC_REST_GET, OC_LOW_QOS, getReqCB, NULL, 0));
422 }
423
424 int InitObserveRequest(OCQualityOfService qos)
425 {
426     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
427     std::ostringstream query;
428     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
429     return (InvokeOCDoResource(query, OC_REST_OBSERVE, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, obsReqCB, NULL, 0));
430 }
431
432 int InitPutRequest()
433 {
434     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
435     std::ostringstream query;
436     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
437     return (InvokeOCDoResource(query, OC_REST_PUT, OC_LOW_QOS, putReqCB, NULL, 0));
438 }
439
440 int InitPostRequest(OCQualityOfService qos)
441 {
442     OCStackResult result;
443     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
444     std::ostringstream query;
445     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
446
447     // First POST operation (to create an Light instance)
448     result = InvokeOCDoResource(query, OC_REST_POST,
449                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
450                                postReqCB, NULL, 0);
451     if (OC_STACK_OK != result)
452     {
453         // Error can happen if for example, network connectivity is down
454         OC_LOG(INFO, TAG, "First POST call did not succeed");
455     }
456
457     // Second POST operation (to create an Light instance)
458     result = InvokeOCDoResource(query, OC_REST_POST,
459                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
460                                postReqCB, NULL, 0);
461     if (OC_STACK_OK != result)
462     {
463         OC_LOG(INFO, TAG, "Second POST call did not succeed");
464     }
465
466     // This POST operation will update the original resourced /a/light
467     return (InvokeOCDoResource(query, OC_REST_POST,
468                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
469                                postReqCB, NULL, 0));
470 }
471
472 void* RequestDeleteDeathResourceTask(void* myqos)
473 {
474     sleep (30); //long enough to give the server time to finish deleting the resource.
475     std::ostringstream query;
476     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
477
478     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
479
480     // Second DELETE operation to delete the resource that might have been removed already.
481     OCQualityOfService qos;
482     if (myqos == NULL)
483         qos = OC_LOW_QOS;
484     else
485         qos = OC_HIGH_QOS;
486
487     OCStackResult result = InvokeOCDoResource(query, OC_REST_DELETE,
488                                qos,
489                                deleteReqCB, NULL, 0);
490
491     if (OC_STACK_OK != result)
492     {
493         OC_LOG(INFO, TAG, "Second DELETE call did not succeed");
494     }
495
496     return NULL;
497 }
498
499 int InitDeleteRequest(OCQualityOfService qos)
500 {
501     OCStackResult result;
502     std::ostringstream query;
503     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
504
505     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
506
507     // First DELETE operation
508     result = InvokeOCDoResource(query, OC_REST_DELETE,
509                                qos,
510                                deleteReqCB, NULL, 0);
511     if (OC_STACK_OK != result)
512     {
513         // Error can happen if for example, network connectivity is down
514         OC_LOG(INFO, TAG, "First DELETE call did not succeed");
515     }
516     else
517     {
518         //Create a thread to delete this resource again
519         pthread_t threadId;
520         pthread_create (&threadId, NULL, RequestDeleteDeathResourceTask, (void*)qos);
521     }
522
523     OC_LOG_V(INFO, TAG, "\n\nExit  %s", __func__);
524     return result;
525 }
526
527 int InitGetRequest(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptions)
528 {
529     OCHeaderOption options[MAX_HEADER_OPTIONS];
530
531     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
532     std::ostringstream query;
533     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
534
535     if(withVendorSpecificHeaderOptions)
536     {
537         uint8_t option0[] = {1,2,3,4,5,6,7,8,9,10};
538         uint8_t option1[] = {11,12,13,14,15,16,17,18,19,20};
539         memset(options, 0, sizeof(OCHeaderOption) * MAX_HEADER_OPTIONS);
540         options[0].protocolID = OC_COAP_ID;
541         options[0].optionID = 2048;
542         memcpy(options[0].optionData, option0, sizeof(option0));
543         options[0].optionLength = 10;
544         options[1].protocolID = OC_COAP_ID;
545         options[1].optionID = 3000;
546         memcpy(options[1].optionData, option1, sizeof(option1));
547         options[1].optionLength = 10;
548     }
549     if(withVendorSpecificHeaderOptions)
550     {
551         return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, getReqCB, options, 2));
552     }
553     else
554     {
555         return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
556     }
557 }
558
559 int InitDeviceDiscovery()
560 {
561     OCStackResult ret;
562     OCCallbackData cbData;
563     OCDoHandle handle;
564     char szQueryUri[64] = { 0 };
565
566     cbData.cb = DeviceDiscoveryReqCB;
567     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
568     cbData.cd = NULL;
569
570     if(UNICAST_DISCOVERY)
571     {
572         snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DEVICE_DISCOVERY_QUERY, ipv4addr);
573     }
574     else
575     {
576         strncpy(szQueryUri, MULTICAST_DEVICE_DISCOVERY_QUERY,
577                 (strlen(MULTICAST_DEVICE_DISCOVERY_QUERY) + 1));
578     }
579
580     if(UNICAST_DISCOVERY)
581     {
582         ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
583                 OC_LOW_QOS, &cbData, NULL, 0);
584     }
585     else
586     {
587         ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, (OC_ALL),
588                 OC_LOW_QOS, &cbData, NULL, 0);
589     }
590
591     if (ret != OC_STACK_OK)
592     {
593         OC_LOG(ERROR, TAG, "OCStack device error");
594     }
595
596     return ret;
597 }
598
599 int InitDiscovery()
600 {
601     OCStackResult ret;
602     OCCallbackData cbData;
603     OCDoHandle handle;
604     /* Start a discovery query*/
605     char szQueryUri[64] = { 0 };
606
607     if (UNICAST_DISCOVERY)
608     {
609         snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
610     }
611     else
612     {
613         strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
614     }
615
616     cbData.cb = discoveryReqCB;
617     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
618     cbData.cd = NULL;
619     if(UNICAST_DISCOVERY)
620     {
621         ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
622                 OC_LOW_QOS, &cbData, NULL, 0);
623     }
624     else
625     {
626         ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, (OC_ALL),
627                 OC_LOW_QOS, &cbData, NULL, 0);
628     }
629     if (ret != OC_STACK_OK)
630     {
631         OC_LOG(ERROR, TAG, "OCStack resource error");
632     }
633     return ret;
634 }
635
636 int main(int argc, char* argv[]) {
637     int opt;
638
639     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
640     {
641         switch(opt)
642         {
643             case 'u':
644                 UNICAST_DISCOVERY = atoi(optarg);
645                 break;
646             case 't':
647                 TEST_CASE = atoi(optarg);
648                 break;
649             case 'c':
650                 OC_CONNTYPE = OCConnectivityType(atoi(optarg));
651                 break;
652             default:
653                 PrintUsage();
654                 return -1;
655         }
656     }
657
658     if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
659             (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
660     {
661         PrintUsage();
662         return -1;
663     }
664
665     /* Initialize OCStack*/
666     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK) {
667         OC_LOG(ERROR, TAG, "OCStack init error");
668         return 0;
669     }
670     if (UNICAST_DISCOVERY)
671     {
672         printf("Enter IPv4 address of the Server hosting resource (Ex: 192.168.0.15)\n");
673         if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
674         {
675            //Strip newline char from ipv4addr
676             StripNewLineChar(ipv4addr);
677         }
678         else
679         {
680             OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
681             return OC_STACK_INVALID_PARAM;
682         }
683      }
684
685     if(UNICAST_DISCOVERY  == 0  && TEST_CASE == TEST_DISCOVER_DEV_REQ)
686     {
687         InitDeviceDiscovery();
688     }
689     else
690     {
691         InitDiscovery();
692     }
693
694     // Break from loop with Ctrl+C
695     OC_LOG(INFO, TAG, "Entering occlient main loop...");
696     signal(SIGINT, handleSigInt);
697     while (!gQuitFlag) {
698
699         if (OCProcess() != OC_STACK_OK) {
700             OC_LOG(ERROR, TAG, "OCStack process error");
701             return 0;
702         }
703
704         sleep(2);
705     }
706     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
707
708     if (OCStop() != OC_STACK_OK) {
709         OC_LOG(ERROR, TAG, "OCStack stop error");
710     }
711
712     return 0;
713 }
714
715 std::string getIPAddrTBServer(OCClientResponse * clientResponse) {
716     if(!clientResponse) return "";
717     if(!clientResponse->addr) return "";
718     uint8_t a, b, c, d = 0;
719     if(0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d) ) return "";
720
721     char ipaddr[16] = {'\0'};
722     snprintf(ipaddr,  sizeof(ipaddr), "%d.%d.%d.%d", a,b,c,d); // ostringstream not working correctly here, hence snprintf
723     return std::string (ipaddr);
724 }
725
726 std::string getPortTBServer(OCClientResponse * clientResponse){
727     if(!clientResponse) return "";
728     if(!clientResponse->addr) return "";
729     uint16_t p = 0;
730     if(0 != OCDevAddrToPort(clientResponse->addr, &p) ) return "";
731     std::ostringstream ss;
732     ss << p;
733     return ss.str();
734 }
735
736 std::string getConnectivityType (OCConnectivityType connType)
737 {
738     switch (connType)
739     {
740         case OC_ETHERNET:
741             return "Ethernet";
742
743         case OC_WIFI:
744             return "WiFi";
745
746         case OC_LE:
747             return "BLE";
748
749         case OC_EDR:
750             return "BT";
751
752         default:
753             return "Incorrect connectivity";
754     }
755 }
756
757 std::string getQueryStrForGetPut(OCClientResponse * clientResponse){
758
759     return "/a/light";
760 }
761
762 void parseClientResponse(OCClientResponse * clientResponse){
763     coapServerIP = getIPAddrTBServer(clientResponse);
764     coapServerPort = getPortTBServer(clientResponse);
765     coapServerResource = getQueryStrForGetPut(clientResponse);
766 }