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