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