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