Change occlient to cancel observe on every registration.
[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 #include "ocpayload.h"
32 #include "payload_logging.h"
33
34 #ifdef ROUTING_GATEWAY
35 /**
36  * Maximum number of gateway requests to form the routing table.
37  */
38 #define MAX_NUM_GATEWAY_REQUEST 20
39
40 /**
41  * Sleep duration after every OCProcess().
42  */
43 #define SLEEP_DURATION 100000
44 #endif
45 // Tracking user input
46 static int UnicastDiscovery = 0;
47 static int TestCase = 0;
48 static int Connectivity = 0;
49
50 static const char *DEVICE_DISCOVERY_QUERY = "%s/oic/d";
51 static const char *PLATFORM_DISCOVERY_QUERY = "%s/oic/p";
52 static const char *RESOURCE_DISCOVERY_QUERY = "%s/oic/res";
53
54 //The following variable determines the interface protocol (IPv4, IPv6, etc)
55 //to be used for sending unicast messages. Default set to IP dual stack.
56 static OCConnectivityType ConnType = CT_ADAPTER_IP;
57 static OCDevAddr serverAddr;
58 static char discoveryAddr[100];
59 static std::string coapServerResource = "/a/light";
60
61 void StripNewLineChar(char* str);
62
63 #ifdef WITH_PRESENCE
64 // The handle for observe registration
65 OCDoHandle gPresenceHandle;
66 #endif
67 // After this crosses a threshold client deregisters for further notifications
68 int gNumObserveNotifies = 0;
69
70 #ifdef WITH_PRESENCE
71 int gNumPresenceNotifies = 0;
72 #endif
73
74 int gQuitFlag = 0;
75 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
76 void handleSigInt(int signum)
77 {
78     if (signum == SIGINT)
79     {
80         gQuitFlag = 1;
81     }
82 }
83
84 OCPayload* putPayload()
85 {
86     OCRepPayload* payload = OCRepPayloadCreate();
87
88     if (!payload)
89     {
90         std::cout << "Failed to create put payload object"<<std::endl;
91         std::exit(1);
92     }
93
94     OCRepPayloadSetPropInt(payload, "power", 15);
95     OCRepPayloadSetPropBool(payload, "state", true);
96
97     return (OCPayload*) payload;
98 }
99
100 static void PrintUsage()
101 {
102     OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1..17> -c <0|1>");
103     OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
104     OC_LOG(INFO, TAG, "-c 0 : Use Default connectivity(IP)");
105     OC_LOG(INFO, TAG, "-c 1 : IP Connectivity Type");
106     OC_LOG(INFO, TAG, "-t 1  :  Discover Resources");
107     OC_LOG(INFO, TAG, "-t 2  :  Discover Resources and Initiate Nonconfirmable Get Request");
108     OC_LOG(INFO, TAG, "-t 3  :  Discover Resources and Initiate Nonconfirmable Get Request"
109             " with query filter.");
110     OC_LOG(INFO, TAG, "-t 4  :  Discover Resources and Initiate Nonconfirmable Put Requests");
111     OC_LOG(INFO, TAG, "-t 5  :  Discover Resources and Initiate Nonconfirmable Post Requests");
112     OC_LOG(INFO, TAG, "-t 6  :  Discover Resources and Initiate Nonconfirmable Delete Requests");
113     OC_LOG(INFO, TAG, "-t 7  :  Discover Resources and Initiate Nonconfirmable Observe Requests");
114     OC_LOG(INFO, TAG, "-t 8  :  Discover Resources and Initiate Nonconfirmable Get Request "\
115             "for a resource which is unavailable");
116     OC_LOG(INFO, TAG, "-t 9  :  Discover Resources and Initiate Confirmable Get Request");
117     OC_LOG(INFO, TAG, "-t 10 :  Discover Resources and Initiate Confirmable Post Request");
118     OC_LOG(INFO, TAG, "-t 11 :  Discover Resources and Initiate Confirmable Delete Requests");
119     OC_LOG(INFO, TAG, "-t 12 :  Discover Resources and Initiate Confirmable Observe Requests"\
120             " and cancel with Low QoS");
121
122 #ifdef WITH_PRESENCE
123     OC_LOG(INFO, TAG, "-t 13 :  Discover Resources and Initiate Nonconfirmable presence");
124     OC_LOG(INFO, TAG, "-t 14 :  Discover Resources and Initiate Nonconfirmable presence with "\
125             "filter");
126     OC_LOG(INFO, TAG, "-t 15 :  Discover Resources and Initiate Nonconfirmable presence with "\
127             "2 filters");
128     OC_LOG(INFO, TAG, "-t 16 :  Discover Resources and Initiate Nonconfirmable multicast presence.");
129 #endif
130
131     OC_LOG(INFO, TAG, "-t 17 :  Discover Resources and Initiate Nonconfirmable Observe Requests "\
132             "then cancel immediately with High QOS");
133     OC_LOG(INFO, TAG, "-t 18 :  Discover Resources and Initiate Nonconfirmable Get Request and "\
134             "add  vendor specific header options");
135     OC_LOG(INFO, TAG, "-t 19 :  Discover Platform");
136     OC_LOG(INFO, TAG, "-t 20 :  Discover Devices");
137 }
138
139 OCStackResult InvokeOCDoResource(std::ostringstream &query,
140                                  OCDevAddr *remoteAddr,
141                                  OCMethod method,
142                                  OCQualityOfService qos,
143                                  OCClientResponseHandler cb,
144                                  OCHeaderOption * options,
145                                  uint8_t numOptions)
146 {
147     OCStackResult ret;
148     OCCallbackData cbData;
149     OCDoHandle handle;
150
151     cbData.cb = cb;
152     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
153     cbData.cd = NULL;
154
155     ret = OCDoResource(&handle, method, query.str().c_str(), remoteAddr,
156                        (method == OC_REST_PUT) ? putPayload() : NULL,
157                        (ConnType), qos, &cbData, options, numOptions);
158
159     if (ret != OC_STACK_OK)
160     {
161         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
162     }
163 #ifdef WITH_PRESENCE
164     else if (method == OC_REST_PRESENCE)
165     {
166         gPresenceHandle = handle;
167     }
168 #endif
169
170     return ret;
171 }
172
173 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle /*handle*/,
174                                   OCClientResponse * clientResponse)
175 {
176     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
177     {
178         OC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully");
179     }
180
181     if (clientResponse)
182     {
183         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
184         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
185         OC_LOG(INFO, TAG, ("=============> Put Response"));
186     }
187     else
188     {
189         OC_LOG_V(INFO, TAG, "putReqCB received Null clientResponse");
190     }
191     return OC_STACK_DELETE_TRANSACTION;
192 }
193
194 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle /*handle*/,
195                                    OCClientResponse *clientResponse)
196 {
197     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
198     {
199         OC_LOG(INFO, TAG, "Callback Context for POST recvd successfully");
200     }
201
202     if (clientResponse)
203     {
204         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
205         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
206         OC_LOG(INFO, TAG, ("=============> Post Response"));
207     }
208     else
209     {
210         OC_LOG_V(INFO, TAG, "postReqCB received Null clientResponse");
211     }
212     return OC_STACK_DELETE_TRANSACTION;
213 }
214
215 OCStackApplicationResult deleteReqCB(void *ctx,
216                                      OCDoHandle /*handle*/,
217                                      OCClientResponse *clientResponse)
218 {
219     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
220     {
221         OC_LOG(INFO, TAG, "Callback Context for DELETE recvd successfully");
222     }
223
224     if (clientResponse)
225     {
226         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
227         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
228         OC_LOG(INFO, TAG, ("=============> Delete Response"));
229     }
230     else
231     {
232         OC_LOG_V(INFO, TAG, "deleteReqCB received Null clientResponse");
233     }
234     return OC_STACK_DELETE_TRANSACTION;
235 }
236
237 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle /*handle*/,
238                                   OCClientResponse * clientResponse)
239 {
240     if (clientResponse == NULL)
241     {
242         OC_LOG(INFO, TAG, "getReqCB received NULL clientResponse");
243         return   OC_STACK_DELETE_TRANSACTION;
244     }
245
246     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
247     {
248         OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
249     }
250
251     OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
252     OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
253     OC_LOG_PAYLOAD(INFO, clientResponse->payload);
254     OC_LOG(INFO, TAG, ("=============> Get Response"));
255
256     if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0)
257     {
258         OC_LOG (INFO, TAG, "Received vendor specific options");
259         uint8_t i = 0;
260         OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
261         for( i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
262         {
263             if (((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
264             {
265                 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
266                         ((OCHeaderOption)rcvdOptions[i]).optionID );
267
268                 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
269                     MAX_HEADER_OPTION_DATA_LENGTH);
270             }
271         }
272     }
273     return OC_STACK_DELETE_TRANSACTION;
274 }
275
276 OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle,
277                                   OCClientResponse * clientResponse)
278 {
279     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
280     {
281         OC_LOG(INFO, TAG, "Callback Context for OBS query recvd successfully");
282     }
283
284     if (clientResponse)
285     {
286         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
287         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
288         OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d",
289                 gNumObserveNotifies);
290         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
291         OC_LOG(INFO, TAG, ("=============> Obs Response"));
292         gNumObserveNotifies++;
293         if (gNumObserveNotifies > 15) //large number to test observing in DELETE case.
294         {
295             if (TestCase == TEST_OBS_REQ_NON || TestCase == TEST_OBS_REQ_CON)
296             {
297                 OC_LOG(ERROR, TAG, "Cancelling with LOW QOS");
298                 if (OCCancel (handle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK)
299                 {
300                     OC_LOG(ERROR, TAG, "Observe cancel error");
301                 }
302                 return OC_STACK_DELETE_TRANSACTION;
303             }
304             else if (TestCase == TEST_OBS_REQ_NON_CANCEL_IMM)
305             {
306                 OC_LOG(ERROR, TAG, "Cancelling with HIGH QOS");
307                 if (OCCancel (handle, OC_HIGH_QOS, NULL, 0) != OC_STACK_OK)
308                 {
309                     OC_LOG(ERROR, TAG, "Observe cancel error");
310                 }
311             }
312         }
313         if (clientResponse->sequenceNumber == OC_OBSERVE_REGISTER)
314         {
315             OC_LOG(INFO, TAG, "This also serves as a registration confirmation");
316         }
317         else if (clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER)
318         {
319             OC_LOG(INFO, TAG, "This also serves as a deregistration confirmation");
320             return OC_STACK_DELETE_TRANSACTION;
321         }
322         else if (clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION)
323         {
324             OC_LOG(INFO, TAG, "This also tells you that registration/deregistration failed");
325             return OC_STACK_DELETE_TRANSACTION;
326         }
327     }
328     else
329     {
330         OC_LOG_V(INFO, TAG, "obsReqCB received Null clientResponse");
331     }
332     return OC_STACK_KEEP_TRANSACTION;
333 }
334 #ifdef WITH_PRESENCE
335 OCStackApplicationResult presenceCB(void* ctx, OCDoHandle /*handle*/,
336                                     OCClientResponse * clientResponse)
337 {
338     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
339     {
340         OC_LOG(INFO, TAG, "Callback Context for Presence recvd successfully");
341     }
342
343     if (clientResponse)
344     {
345         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
346         OC_LOG_V(INFO, TAG, "Callback Context for Presence notification recvd successfully %d",
347                 gNumPresenceNotifies);
348         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
349         OC_LOG(INFO, TAG, ("=============> Presence Response"));
350         gNumPresenceNotifies++;
351         if (gNumPresenceNotifies == 20)
352         {
353             if (OCCancel(gPresenceHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK)
354             {
355                 OC_LOG(ERROR, TAG, "Presence cancel error");
356             }
357             return OC_STACK_DELETE_TRANSACTION;
358         }
359     }
360     else
361     {
362         OC_LOG_V(INFO, TAG, "presenceCB received Null clientResponse");
363     }
364     return OC_STACK_KEEP_TRANSACTION;
365 }
366 #endif
367
368 // This is a function called back when a device is discovered
369 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle /*handle*/,
370                                         OCClientResponse * clientResponse)
371 {
372     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
373     {
374         OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
375     }
376
377     if (clientResponse)
378     {
379         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
380
381         std::string connectionType = getConnectivityType (clientResponse->connType);
382         OC_LOG_V(INFO, TAG, "Discovered on %s", connectionType.c_str());
383         OC_LOG_V(INFO, TAG,
384                 "Device =============> Discovered @ %s:%d",
385                 clientResponse->devAddr.addr,
386                 clientResponse->devAddr.port);
387         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
388
389         ConnType = clientResponse->connType;
390         serverAddr = clientResponse->devAddr;
391         parseClientResponse(clientResponse);
392
393         switch(TestCase)
394         {
395             case TEST_GET_REQ_NON:
396                 InitGetRequest(OC_LOW_QOS, 0, 0);
397                 break;
398             case TEST_GET_REQ_NON_WITH_FILTERS:
399                 InitGetRequest(OC_LOW_QOS, 0, 1);
400                 break;
401             case TEST_PUT_REQ_NON:
402                 InitPutRequest(OC_LOW_QOS);
403                 break;
404             case TEST_POST_REQ_NON:
405                 InitPostRequest(OC_LOW_QOS);
406                 break;
407             case TEST_DELETE_REQ_NON:
408                 InitDeleteRequest(OC_LOW_QOS);
409                 break;
410             case TEST_OBS_REQ_NON:
411             case TEST_OBS_REQ_NON_CANCEL_IMM:
412                 InitObserveRequest(OC_LOW_QOS);
413                 break;
414             case TEST_GET_UNAVAILABLE_RES_REQ_NON:
415                 InitGetRequestToUnavailableResource(OC_LOW_QOS);
416                 break;
417             case TEST_GET_REQ_CON:
418                 InitGetRequest(OC_HIGH_QOS, 0, 0);
419                 break;
420             case TEST_POST_REQ_CON:
421                 InitPostRequest(OC_HIGH_QOS);
422                 break;
423             case TEST_DELETE_REQ_CON:
424                 InitDeleteRequest(OC_HIGH_QOS);
425                 break;
426             case TEST_OBS_REQ_CON:
427                 InitObserveRequest(OC_HIGH_QOS);
428                 break;
429 #ifdef WITH_PRESENCE
430             case TEST_OBS_PRESENCE:
431             case TEST_OBS_PRESENCE_WITH_FILTER:
432             case TEST_OBS_PRESENCE_WITH_FILTERS:
433             case TEST_OBS_MULTICAST_PRESENCE:
434                 InitPresence();
435                 break;
436 #endif
437             case TEST_GET_REQ_NON_WITH_VENDOR_HEADER_OPTIONS:
438                 InitGetRequest(OC_LOW_QOS, 1, 0);
439                 break;
440             case TEST_DISCOVER_PLATFORM_REQ:
441                 InitPlatformDiscovery(OC_LOW_QOS);
442                 break;
443             case TEST_DISCOVER_DEV_REQ:
444                 InitDeviceDiscovery(OC_LOW_QOS);
445                 break;
446             default:
447                 PrintUsage();
448                 break;
449         }
450     }
451     else
452     {
453         OC_LOG_V(INFO, TAG, "discoveryReqCB received Null clientResponse");
454     }
455     return OC_STACK_KEEP_TRANSACTION;
456 }
457
458 OCStackApplicationResult PlatformDiscoveryReqCB(void* ctx,
459                                                 OCDoHandle /*handle*/,
460                                                 OCClientResponse * clientResponse)
461 {
462     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
463     {
464         OC_LOG(INFO, TAG, "Callback Context for Platform DISCOVER query recvd successfully");
465     }
466
467     if (clientResponse)
468     {
469         OC_LOG(INFO, TAG, ("Discovery Response:"));
470         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
471     }
472     else
473     {
474         OC_LOG_V(INFO, TAG, "PlatformDiscoveryReqCB received Null clientResponse");
475     }
476
477     return (UnicastDiscovery) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
478 }
479
480 OCStackApplicationResult DeviceDiscoveryReqCB(void* ctx, OCDoHandle /*handle*/,
481                                               OCClientResponse * clientResponse)
482 {
483     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
484     {
485         OC_LOG(INFO, TAG, "Callback Context for Device DISCOVER query recvd successfully");
486     }
487
488     if (clientResponse)
489     {
490         OC_LOG(INFO, TAG, ("Discovery Response:"));
491         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
492     }
493     else
494     {
495         OC_LOG_V(INFO, TAG, "PlatformDiscoveryReqCB received Null clientResponse");
496     }
497
498     return (UnicastDiscovery) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
499 }
500
501 #ifdef WITH_PRESENCE
502 int InitPresence()
503 {
504     OCStackResult result = OC_STACK_OK;
505     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
506     std::ostringstream query;
507     std::ostringstream querySuffix;
508     query << OC_RSRVD_PRESENCE_URI;
509     if (TestCase == TEST_OBS_PRESENCE)
510     {
511         result = InvokeOCDoResource(query, &serverAddr, OC_REST_PRESENCE,
512                 OC_LOW_QOS, presenceCB, NULL, 0);
513     }
514     if (TestCase == TEST_OBS_PRESENCE_WITH_FILTER || TestCase == TEST_OBS_PRESENCE_WITH_FILTERS)
515     {
516         querySuffix.str("");
517         querySuffix << query.str() << "?rt=core.led";
518         result = InvokeOCDoResource(querySuffix, &serverAddr, OC_REST_PRESENCE,
519                 OC_LOW_QOS, presenceCB, NULL, 0);
520     }
521     if (TestCase == TEST_OBS_PRESENCE_WITH_FILTERS)
522     {
523         if (result == OC_STACK_OK)
524         {
525             querySuffix.str("");
526             querySuffix << query.str() << "?rt=core.fan";
527             result = InvokeOCDoResource(querySuffix, &serverAddr, OC_REST_PRESENCE, OC_LOW_QOS,
528                     presenceCB, NULL, 0);
529         }
530     }
531     if (TestCase == TEST_OBS_MULTICAST_PRESENCE)
532     {
533         if (result == OC_STACK_OK)
534         {
535             std::ostringstream multicastPresenceQuery;
536             multicastPresenceQuery.str("");
537             multicastPresenceQuery << "coap://" << OC_MULTICAST_PREFIX << OC_RSRVD_PRESENCE_URI;
538             result = InvokeOCDoResource(multicastPresenceQuery, &serverAddr, OC_REST_PRESENCE, OC_LOW_QOS,
539                     presenceCB, NULL, 0);
540         }
541     }
542     return result;
543 }
544 #endif
545
546 int InitGetRequestToUnavailableResource(OCQualityOfService qos)
547 {
548     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
549     std::ostringstream query;
550     query << "/SomeUnknownResource";
551     return (InvokeOCDoResource(query, &serverAddr, OC_REST_GET, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
552             getReqCB, NULL, 0));
553 }
554
555 int InitObserveRequest(OCQualityOfService qos)
556 {
557     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
558     std::ostringstream query;
559     query << coapServerResource;
560     return (InvokeOCDoResource(query, &serverAddr, OC_REST_OBSERVE,
561               (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, obsReqCB, NULL, 0));
562 }
563
564 int InitPutRequest(OCQualityOfService qos)
565 {
566     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
567     std::ostringstream query;
568     query << coapServerResource;
569     return (InvokeOCDoResource(query, &serverAddr, OC_REST_PUT, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
570             putReqCB, NULL, 0));
571 }
572
573 int InitPostRequest(OCQualityOfService qos)
574 {
575     OCStackResult result;
576     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
577     std::ostringstream query;
578     query << coapServerResource;
579
580     // First POST operation (to create an Light instance)
581     result = InvokeOCDoResource(query, &serverAddr, OC_REST_POST,
582                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
583                                postReqCB, NULL, 0);
584     if (OC_STACK_OK != result)
585     {
586         // Error can happen if for example, network connectivity is down
587         OC_LOG(INFO, TAG, "First POST call did not succeed");
588     }
589
590     // Second POST operation (to create an Light instance)
591     result = InvokeOCDoResource(query, &serverAddr, OC_REST_POST,
592                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
593                                postReqCB, NULL, 0);
594     if (OC_STACK_OK != result)
595     {
596         OC_LOG(INFO, TAG, "Second POST call did not succeed");
597     }
598
599     // This POST operation will update the original resourced /a/light
600     return (InvokeOCDoResource(query, &serverAddr, OC_REST_POST,
601                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
602                                postReqCB, NULL, 0));
603 }
604
605 void* RequestDeleteDeathResourceTask(void* myqos)
606 {
607     sleep (30);//long enough to give the server time to finish deleting the resource.
608     std::ostringstream query;
609     query << coapServerResource;
610
611     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
612
613     // Second DELETE operation to delete the resource that might have been removed already.
614     OCQualityOfService qos;
615     if (myqos == NULL)
616     {
617         qos = OC_LOW_QOS;
618     }
619     else
620     {
621         qos = OC_HIGH_QOS;
622     }
623
624     OCStackResult result = InvokeOCDoResource(query, &serverAddr, OC_REST_DELETE,
625                                qos,
626                                deleteReqCB, NULL, 0);
627
628     if (OC_STACK_OK != result)
629     {
630         OC_LOG(INFO, TAG, "Second DELETE call did not succeed");
631     }
632
633     return NULL;
634 }
635
636 int InitDeleteRequest(OCQualityOfService qos)
637 {
638     OCStackResult result;
639     std::ostringstream query;
640     query << coapServerResource;
641
642     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
643
644     // First DELETE operation
645     result = InvokeOCDoResource(query, &serverAddr, OC_REST_DELETE,
646                                qos,
647                                deleteReqCB, NULL, 0);
648     if (OC_STACK_OK != result)
649     {
650         // Error can happen if for example, network connectivity is down
651         OC_LOG(INFO, TAG, "First DELETE call did not succeed");
652     }
653     else
654     {
655         //Create a thread to delete this resource again
656         pthread_t threadId;
657         pthread_create (&threadId, NULL, RequestDeleteDeathResourceTask, (void*)qos);
658     }
659
660     OC_LOG_V(INFO, TAG, "\n\nExit  %s", __func__);
661     return result;
662 }
663
664 int InitGetRequest(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptions, bool getWithQuery)
665 {
666
667     OCHeaderOption options[MAX_HEADER_OPTIONS];
668
669     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
670     std::ostringstream query;
671     query << coapServerResource;
672
673     // ocserver is written to only process "power<X" query.
674     if (getWithQuery)
675     {
676         OC_LOG(INFO, TAG, "Using query power<50");
677         query << "?power<50";
678     }
679
680     if (withVendorSpecificHeaderOptions)
681     {
682         uint8_t option0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
683         uint8_t option1[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
684         memset(options, 0, sizeof(OCHeaderOption) * MAX_HEADER_OPTIONS);
685         options[0].protocolID = OC_COAP_ID;
686         options[0].optionID = 2048;
687         memcpy(options[0].optionData, option0, sizeof(option0));
688         options[0].optionLength = 10;
689         options[1].protocolID = OC_COAP_ID;
690         options[1].optionID = 3000;
691         memcpy(options[1].optionData, option1, sizeof(option1));
692         options[1].optionLength = 10;
693     }
694     if (withVendorSpecificHeaderOptions)
695     {
696         return (InvokeOCDoResource(query, &serverAddr, OC_REST_GET,
697                 (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, getReqCB, options, 2));
698     }
699     else
700     {
701         return (InvokeOCDoResource(query, &serverAddr, OC_REST_GET,
702                 (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, getReqCB, NULL, 0));
703     }
704 }
705
706 int InitPlatformDiscovery(OCQualityOfService qos)
707 {
708     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
709
710     OCStackResult ret;
711     OCCallbackData cbData;
712     char szQueryUri[64] = { 0 };
713
714     snprintf(szQueryUri, sizeof (szQueryUri) - 1, PLATFORM_DISCOVERY_QUERY, discoveryAddr);
715
716     cbData.cb = PlatformDiscoveryReqCB;
717     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
718     cbData.cd = NULL;
719
720     ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
721                        (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
722                        &cbData, NULL, 0);
723     if (ret != OC_STACK_OK)
724     {
725         OC_LOG(ERROR, TAG, "OCStack device error");
726     }
727
728     return ret;
729 }
730
731 int InitDeviceDiscovery(OCQualityOfService qos)
732 {
733     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
734
735     OCStackResult ret;
736     OCCallbackData cbData;
737     char szQueryUri[100] = { 0 };
738
739     snprintf(szQueryUri, sizeof (szQueryUri) - 1, DEVICE_DISCOVERY_QUERY, discoveryAddr);
740
741     cbData.cb = DeviceDiscoveryReqCB;
742     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
743     cbData.cd = NULL;
744
745     ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
746                        (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
747                        &cbData, NULL, 0);
748     if (ret != OC_STACK_OK)
749     {
750         OC_LOG(ERROR, TAG, "OCStack device error");
751     }
752
753     return ret;
754 }
755
756 int InitDiscovery(OCQualityOfService qos)
757 {
758     OCStackResult ret;
759     OCCallbackData cbData;
760     char szQueryUri[100] = { 0 };
761
762     snprintf(szQueryUri, sizeof (szQueryUri) - 1, RESOURCE_DISCOVERY_QUERY, discoveryAddr);
763
764     cbData.cb = discoveryReqCB;
765     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
766     cbData.cd = NULL;
767
768     ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
769                        (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
770                        &cbData, NULL, 0);
771     if (ret != OC_STACK_OK)
772     {
773         OC_LOG(ERROR, TAG, "OCStack resource error");
774     }
775     return ret;
776 }
777
778 int main(int argc, char* argv[])
779 {
780     int opt;
781
782     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
783     {
784         switch(opt)
785         {
786             case 'u':
787                 UnicastDiscovery = atoi(optarg);
788                 break;
789             case 't':
790                 TestCase = atoi(optarg);
791                 break;
792             case 'c':
793                 Connectivity = atoi(optarg);
794                 break;
795             default:
796                 PrintUsage();
797                 return -1;
798         }
799     }
800
801     if ((UnicastDiscovery != 0 && UnicastDiscovery != 1) ||
802             (TestCase < TEST_DISCOVER_REQ || TestCase >= MAX_TESTS) ||
803             (Connectivity < CT_ADAPTER_DEFAULT || Connectivity >= MAX_CT))
804     {
805         PrintUsage();
806         return -1;
807     }
808
809     if (OCInit1(OC_CLIENT, OC_DEFAULT_FLAGS, OC_DEFAULT_FLAGS) != OC_STACK_OK)
810     {
811         OC_LOG(ERROR, TAG, "OCStack init error");
812         return 0;
813     }
814
815 #ifdef ROUTING_GATEWAY
816     /*
817      * Before invoking Discover resource, we process the gateway requests
818      * and form the routing table.
819      */
820     for (int index = 0; index < MAX_NUM_GATEWAY_REQUEST; index++)
821     {
822         if (OC_STACK_OK != OCProcess())
823         {
824             OC_LOG(ERROR, TAG, "OCStack process error");
825             return 0;
826         }
827         usleep(SLEEP_DURATION);
828     }
829 #endif
830     if (Connectivity == CT_ADAPTER_DEFAULT || Connectivity == CT_IP)
831     {
832         ConnType = CT_ADAPTER_IP;
833     }
834     else
835     {
836         OC_LOG(INFO, TAG, "Default Connectivity type selected...");
837         PrintUsage();
838     }
839
840     discoveryAddr[0] = '\0';
841
842     if (UnicastDiscovery)
843     {
844         OC_LOG(INFO, TAG, "Enter IP address of server with optional port number");
845         OC_LOG(INFO, TAG, "IPv4: 192.168.0.15:45454\n");
846         OC_LOG(INFO, TAG, "IPv6: [fe80::20c:29ff:fe1b:9c5]:45454\n");
847
848         if (fgets(discoveryAddr, sizeof (discoveryAddr), stdin))
849         {
850             //Strip newline char from ipv4addr
851             StripNewLineChar(discoveryAddr);
852         }
853         else
854         {
855             OC_LOG(ERROR, TAG, "!! Bad input for IP address. !!");
856             return OC_STACK_INVALID_PARAM;
857         }
858     }
859
860     if (UnicastDiscovery == 0 && TestCase == TEST_DISCOVER_DEV_REQ)
861     {
862         InitDeviceDiscovery(OC_LOW_QOS);
863     }
864     else if (UnicastDiscovery == 0 && TestCase == TEST_DISCOVER_PLATFORM_REQ)
865     {
866         InitPlatformDiscovery(OC_LOW_QOS);
867     }
868     else
869     {
870         InitDiscovery(OC_LOW_QOS);
871     }
872
873     // Break from loop with Ctrl+C
874     OC_LOG(INFO, TAG, "Entering occlient main loop...");
875     signal(SIGINT, handleSigInt);
876     while (!gQuitFlag)
877     {
878
879         if (OCProcess() != OC_STACK_OK)
880         {
881             OC_LOG(ERROR, TAG, "OCStack process error");
882             return 0;
883         }
884 #ifndef ROUTING_GATEAWAY
885         sleep(1);
886 #endif
887     }
888     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
889
890     if (OCStop() != OC_STACK_OK)
891     {
892         OC_LOG(ERROR, TAG, "OCStack stop error");
893     }
894
895     return 0;
896 }
897
898 std::string getConnectivityType (OCConnectivityType connType)
899 {
900     switch (connType & CT_MASK_ADAPTER)
901     {
902         case CT_ADAPTER_IP:
903             return "IP";
904
905         case CT_IP_USE_V4:
906             return "IPv4";
907
908         case CT_IP_USE_V6:
909             return "IPv6";
910
911         case CT_ADAPTER_GATT_BTLE:
912             return "GATT";
913
914         case CT_ADAPTER_RFCOMM_BTEDR:
915             return "RFCOMM";
916
917         default:
918             return "Incorrect connectivity";
919     }
920 }
921
922 std::string getQueryStrForGetPut(OCClientResponse * /*clientResponse*/)
923 {
924     return "/a/light";
925 }
926
927 void parseClientResponse(OCClientResponse * clientResponse)
928 {
929     coapServerResource = getQueryStrForGetPut(clientResponse);
930 }