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