Merge RA branch to master
[iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / ocremoteaccessclient.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 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 "ocpayload.h"
31 #include "payload_logging.h"
32 #include "ocremoteaccessclient.h"
33
34 #define SET_BUT_NOT_USED(x) (void) x
35 // Tracking user input
36 static int TEST_CASE = 0;
37
38 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
39
40 static std::string coapServerIP = "255.255.255.255";
41 static std::string coapServerPort = "5683";
42 static std::string coapServerResource = "/a/light";
43 static OCDevAddr responseAddr;
44 //Use ipv4addr for both InitDiscovery and InitPlatformOrDeviceDiscovery
45 char remoteServerJabberID[MAX_ADDR_STR_SIZE];
46 void StripNewLineChar(char* str);
47 static uint16_t maxNotification = 15;
48
49 // The handle for the observe registration
50 OCDoHandle gObserveDoHandle;
51 #ifdef WITH_PRESENCE
52 // The handle for observe registration
53 OCDoHandle gPresenceHandle;
54 #endif
55 // After this crosses a threshold client deregisters for further notifications
56 int gNumObserveNotifies = 0;
57
58 #ifdef WITH_PRESENCE
59 int gNumPresenceNotifies = 0;
60 #endif
61
62 int gQuitFlag = 0;
63 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
64 void handleSigInt(int signum)
65 {
66     if (signum == SIGINT)
67     {
68         gQuitFlag = 1;
69     }
70 }
71
72 OCPayload* putPayload()
73 {
74     OCRepPayload* payload = OCRepPayloadCreate();
75
76     if(!payload)
77     {
78         std::cout << "Failed to create put payload object"<<std::endl;
79         std::exit(1);
80     }
81     OCRepPayloadSetPropInt(payload, "power", 42);
82     OCRepPayloadSetPropBool(payload, "state", true);
83     return (OCPayload*) payload;
84 }
85
86 static void PrintUsage()
87 {
88     OC_LOG(INFO, TAG, "This sample makes all requests via the remote access adapter");
89     OC_LOG(INFO, TAG, "Usage : ocremoteaccessclient -t <number>");
90     OC_LOG(INFO, TAG, "-t 1  :  Discover Resources");
91     OC_LOG(INFO, TAG, "-t 2  :  Discover & Get");
92     OC_LOG(INFO, TAG, "-t 3  :  Discover & Put");
93     OC_LOG(INFO, TAG, "-t 4  :  Discover & Post");
94     OC_LOG(INFO, TAG, "-t 5  :  Discover & Delete");
95     OC_LOG(INFO, TAG, "-t 6  :  Discover & Observe");
96     OC_LOG(INFO, TAG, "-t 7  :  Discover & Observe then cancel immediately with High QOS");
97 }
98
99 OCStackResult InvokeOCDoResource(std::ostringstream &query,
100                                  OCMethod method,
101                                  OCQualityOfService qos,
102                                  OCClientResponseHandler cb,
103                                  OCHeaderOption * options,
104                                  uint8_t numOptions)
105 {
106     OCCallbackData cbData;
107     OCDoHandle handle;
108
109     cbData.cb       = cb;
110     cbData.context  = (void*)DEFAULT_CONTEXT_VALUE;
111     cbData.cd       = NULL;
112
113     OCStackResult ret = OCDoResource(
114         &handle,
115         method,
116         query.str().c_str(),
117         &responseAddr,
118         (method == OC_REST_PUT) ? putPayload() : NULL,
119         CT_ADAPTER_REMOTE_ACCESS,
120         qos,
121         &cbData,
122         options,
123         numOptions);
124
125     if (ret != OC_STACK_OK)
126     {
127         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
128     }
129     else if (method == OC_REST_OBSERVE || method == OC_REST_OBSERVE_ALL)
130     {
131         gObserveDoHandle = handle;
132     }
133 #ifdef WITH_PRESENCE
134     else if (method == OC_REST_PRESENCE)
135     {
136         gPresenceHandle = handle;
137     }
138 #endif
139
140     return ret;
141 }
142
143 OCStackApplicationResult restRequestCB(void* ctx,
144         OCDoHandle handle, OCClientResponse * clientResponse)
145 {
146     if(clientResponse == NULL)
147     {
148         OC_LOG(INFO, TAG, "Received NULL response");
149         return   OC_STACK_DELETE_TRANSACTION;
150     }
151     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
152     {
153         OC_LOG(INFO, TAG, "Callback Context recvd successfully");
154     }
155
156     OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
157     OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
158     OC_LOG_PAYLOAD(INFO, clientResponse->payload);
159
160     if(clientResponse->numRcvdVendorSpecificHeaderOptions > 0)
161     {
162         OC_LOG (INFO, TAG, "Received vendor specific options. Ignoring");
163     }
164     SET_BUT_NOT_USED(handle);
165     return OC_STACK_DELETE_TRANSACTION;
166 }
167
168 OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
169 {
170     if(!clientResponse)
171     {
172         OC_LOG_V(INFO, TAG, "obsReqCB received NULL response");
173     }
174     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
175     {
176         OC_LOG(INFO, TAG, "Callback Context recvd successfully");
177     }
178     OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
179     OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
180     OC_LOG_V(INFO, TAG, "OBSERVE notification %d recvd", gNumObserveNotifies);
181     OC_LOG_PAYLOAD(INFO, clientResponse->payload);
182
183     gNumObserveNotifies++;
184     if (gNumObserveNotifies == maxNotification)
185     {
186         if (OCCancel (gObserveDoHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK)
187         {
188             OC_LOG(ERROR, TAG, "Observe cancel error");
189         }
190         return OC_STACK_DELETE_TRANSACTION;
191     }
192     if (gNumObserveNotifies == 1 && TEST_CASE == TEST_OBS_REQ_NON_CANCEL_IMM)
193     {
194         if (OCCancel (gObserveDoHandle, OC_HIGH_QOS, NULL, 0) != OC_STACK_OK)
195         {
196             OC_LOG(ERROR, TAG, "Observe cancel error");
197         }
198     }
199     if(clientResponse->sequenceNumber == OC_OBSERVE_REGISTER)
200     {
201         OC_LOG(INFO, TAG, "Registration confirmed");
202     }
203     else if(clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER)
204     {
205         OC_LOG(INFO, TAG, "de-registration confirmed");
206         return OC_STACK_DELETE_TRANSACTION;
207     }
208     else if(clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION)
209     {
210         OC_LOG(INFO, TAG, "Registration/deregistration failed");
211         return OC_STACK_DELETE_TRANSACTION;
212     }
213
214     SET_BUT_NOT_USED(handle);
215     return OC_STACK_KEEP_TRANSACTION;
216 }
217 #ifdef WITH_PRESENCE
218 OCStackApplicationResult presenceCB(void* ctx,
219         OCDoHandle handle, OCClientResponse * clientResponse)
220 {
221     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
222     {
223         OC_LOG(INFO, TAG, "Callback Context recvd successfully");
224     }
225
226     if (clientResponse)
227     {
228         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
229         OC_LOG_V(INFO, TAG, "NONCE NUMBER: %u", clientResponse->sequenceNumber);
230         OC_LOG_V(INFO, TAG, "PRESENCE notification %d recvd", gNumPresenceNotifies);
231         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
232
233         gNumPresenceNotifies++;
234         if (gNumPresenceNotifies == maxNotification)
235         {
236             if (OCCancel(gPresenceHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK)
237             {
238                 OC_LOG(ERROR, TAG, "Presence cancel error");
239             }
240             return OC_STACK_DELETE_TRANSACTION;
241         }
242     }
243     else
244     {
245         OC_LOG_V(INFO, TAG, "presenceCB received Null clientResponse");
246     }
247     SET_BUT_NOT_USED(handle);
248     return OC_STACK_KEEP_TRANSACTION;
249 }
250 #endif
251
252 // This is a function called back when a device is discovered
253 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
254         OCClientResponse * clientResponse)
255 {
256     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
257     {
258         OC_LOG(INFO, TAG, "DISCOVER  callback recvd");
259     }
260
261     if (!clientResponse)
262     {
263         OC_LOG_V(INFO, TAG, "discoveryReqCB received Null clientResponse");
264     }
265
266     OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
267     OC_LOG_PAYLOAD(INFO, clientResponse->payload);
268
269     responseAddr = clientResponse->devAddr;
270
271     switch(TEST_CASE)
272     {
273         OC_LOG_V(INFO, TAG, "TEST_CASE %u\n", TEST_CASE);
274         case TEST_GET_REQ_NON:
275             InitGetRequest(OC_LOW_QOS);
276             break;
277         case TEST_PUT_REQ_NON:
278             InitPutRequest(OC_LOW_QOS);
279             break;
280         case TEST_POST_REQ_NON:
281             InitPostRequest(OC_LOW_QOS);
282             break;
283         case TEST_DELETE_REQ_NON:
284             InitDeleteRequest(OC_LOW_QOS);
285             break;
286         case TEST_OBS_REQ_NON:
287         case TEST_OBS_REQ_NON_CANCEL_IMM:
288             InitObserveRequest(OC_LOW_QOS);
289             break;
290         default:
291             PrintUsage();
292             break;
293     }
294     SET_BUT_NOT_USED(handle);
295     return OC_STACK_KEEP_TRANSACTION;
296 }
297
298 OCStackApplicationResult PlatformDiscoveryReqCB (void* ctx, OCDoHandle handle,
299                 OCClientResponse * clientResponse)
300 {
301     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
302     {
303         OC_LOG(INFO, TAG, "Callback Context for Platform DISCOVER query recvd successfully");
304     }
305
306     if(clientResponse)
307     {
308         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
309     }
310     else
311     {
312         OC_LOG_V(INFO, TAG, "PlatformDiscoveryReqCB received Null clientResponse");
313     }
314
315     SET_BUT_NOT_USED(handle);
316     return OC_STACK_DELETE_TRANSACTION;
317 }
318
319 OCStackApplicationResult DeviceDiscoveryReqCB (void* ctx, OCDoHandle handle,
320         OCClientResponse * clientResponse)
321 {
322     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
323     {
324         OC_LOG(INFO, TAG, "Callback Context for Device DISCOVER query recvd successfully");
325     }
326
327     if(clientResponse)
328     {
329         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
330     }
331     else
332     {
333         OC_LOG_V(INFO, TAG, "PlatformDiscoveryReqCB received Null clientResponse");
334     }
335
336     SET_BUT_NOT_USED(handle);
337     return OC_STACK_DELETE_TRANSACTION;
338 }
339
340 int InitObserveRequest(OCQualityOfService qos)
341 {
342     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
343     std::ostringstream query;
344     query << coapServerResource;
345     return (InvokeOCDoResource(query,
346             OC_REST_OBSERVE, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, obsReqCB, NULL, 0));
347 }
348
349 int InitPutRequest(OCQualityOfService qos)
350 {
351     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
352     std::ostringstream query;
353     query << coapServerResource;
354     return (InvokeOCDoResource(query, OC_REST_PUT, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
355             restRequestCB, NULL, 0));
356 }
357
358 int InitPostRequest(OCQualityOfService qos)
359 {
360     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
361     std::ostringstream query;
362     query << coapServerResource;
363     // First POST operation (to create an Light instance)
364     OCStackResult result = InvokeOCDoResource(query, OC_REST_POST,
365                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
366                                restRequestCB, NULL, 0);
367     if (OC_STACK_OK != result)
368     {
369         // Error can happen if for example, network connectivity is down
370         OC_LOG(INFO, TAG, "First POST call did not succeed");
371     }
372
373     // Second POST operation (to create an Light instance)
374     result = InvokeOCDoResource(query, OC_REST_POST,
375                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
376                                restRequestCB, NULL, 0);
377     if (OC_STACK_OK != result)
378     {
379         OC_LOG(INFO, TAG, "Second POST call did not succeed");
380     }
381
382     // This POST operation will update the original resourced /a/light
383     return (InvokeOCDoResource(query, OC_REST_POST,
384                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
385                                restRequestCB, NULL, 0));
386 }
387
388 int InitDeleteRequest(OCQualityOfService qos)
389 {
390     std::ostringstream query;
391     query << coapServerResource;
392     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
393
394     // First DELETE operation
395     OCStackResult result = InvokeOCDoResource(query, OC_REST_DELETE,
396                                qos,
397                                restRequestCB, NULL, 0);
398     if (OC_STACK_OK != result)
399     {
400         // Error can happen if for example, network connectivity is down
401         OC_LOG(INFO, TAG, "DELETE call did not succeed");
402     }
403     return result;
404 }
405
406 int InitGetRequest(OCQualityOfService qos)
407 {
408     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
409     std::ostringstream query;
410     query << coapServerResource;
411     return (InvokeOCDoResource(query, OC_REST_GET,
412                 (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, restRequestCB, NULL, 0));
413 }
414
415 int InitDiscovery(OCQualityOfService qos)
416 {
417     OCCallbackData cbData;
418     cbData.cb       = discoveryReqCB;
419     cbData.context  = (void*)DEFAULT_CONTEXT_VALUE;
420     cbData.cd       = NULL;
421
422     OCDevAddr dest;
423     dest.adapter    = OC_ADAPTER_REMOTE_ACCESS;
424     dest.flags      = OC_DEFAULT_FLAGS;
425     strncpy (dest.addr, remoteServerJabberID, MAX_ADDR_STR_SIZE - 1);
426
427     OCStackResult ret = OCDoResource(NULL,
428                 OC_REST_GET,
429                 MULTICAST_RESOURCE_DISCOVERY_QUERY,
430                 &dest,
431                 NULL,
432                 CT_ADAPTER_REMOTE_ACCESS,
433                 (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
434                 &cbData,
435                 NULL,
436                 0
437             );
438
439     if (ret != OC_STACK_OK)
440     {
441         OC_LOG_V(ERROR, TAG, "Error %u in OCDoResource with discovery", ret);
442     }
443     return ret;
444 }
445
446 static void jidbound(char *jid)
447 {
448     OC_LOG_V(INFO, TAG, "\n\n    Bound JID: %s\n\n", jid);
449 }
450
451 int main(int argc, char* argv[])
452 {
453     char host[] = "localhost";
454     char user[] = "test1";
455     char pass[] = "intel123";
456     char empstr[] = "";
457     OCRAInfo_t rainfo = {.hostname = host, .port = 5222,
458         .xmpp_domain = host, .username = user, .password = pass,
459         .resource = empstr, .user_jid = empstr, .jidbound = jidbound};
460
461     int opt = 0;
462     while ((opt = getopt(argc, argv, "t:s:p:d:u:w:r:j:")) != -1)
463     {
464         switch(opt)
465         {
466             case 't':
467                 TEST_CASE = atoi(optarg);
468                 break;
469             case 's':
470                 rainfo.hostname = optarg;
471                 break;
472             case 'p':
473                 rainfo.port = atoi(optarg);
474                 break;
475             case 'd':
476                 rainfo.xmpp_domain = optarg;
477                 break;
478             case 'u':
479                 rainfo.username = optarg;
480                 break;
481             case 'w':
482                 rainfo.password = optarg;
483                 break;
484             case 'j':
485                 rainfo.user_jid = optarg;
486                 break;
487             case 'r':
488                 rainfo.resource = optarg;
489                 break;
490             default:
491                 PrintUsage();
492                 return -1;
493         }
494     }
495
496     if (OCSetRAInfo(&rainfo) != OC_STACK_OK)
497     {
498         OC_LOG(ERROR, TAG, "Error initiating remote access adapter");
499         return 0;
500     }
501
502     if ((TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS))
503     {
504         PrintUsage();
505         return -1;
506     }
507
508     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
509     {
510         OC_LOG(ERROR, TAG, "OCStack init error");
511         return 0;
512     }
513
514     OC_LOG(INFO, TAG, "Enter JID of remote server");
515     if (fgets(remoteServerJabberID, MAX_ADDR_STR_SIZE, stdin))
516     {
517         StripNewLineChar(remoteServerJabberID);
518     }
519     else
520     {
521         OC_LOG(ERROR, TAG, "Bad input for jabberID");
522         return OC_STACK_INVALID_PARAM;
523     }
524
525     InitDiscovery(OC_LOW_QOS);
526
527     // Break from loop with Ctrl+C
528     OC_LOG(INFO, TAG, "Press CTRL+C to stop the stack");
529     signal(SIGINT, handleSigInt);
530     while (!gQuitFlag)
531     {
532         if (OCProcess() != OC_STACK_OK)
533         {
534             OC_LOG(ERROR, TAG, "OCStack process error");
535             return 0;
536         }
537
538         sleep(2);
539     }
540     OC_LOG(INFO, TAG, "Exiting ocremoteaccessclient main loop...");
541
542     if (OCStop() != OC_STACK_OK)
543     {
544         OC_LOG(ERROR, TAG, "OCStack stop error");
545     }
546
547     return 0;
548 }