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