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