Merge branch 'master' into resource-manipulation
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / occlientcoll.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 <ocstack.h>
27 #include <iostream>
28 #include <sstream>
29 #include "logger.h"
30 const char *getResult(OCStackResult result);
31 std::string getIPAddrTBServer(OCClientResponse * clientResponse);
32 std::string getPortTBServer(OCClientResponse * clientResponse);
33 std::string getQueryStrForGetPut(const char * responsePayload);
34
35 #define TAG PCF("occlient")
36 #define DEFAULT_CONTEXT_VALUE 0x99
37 #ifndef MAX_LENGTH_IPv4_ADDR
38 #define MAX_LENGTH_IPv4_ADDR 16
39 #endif
40
41 typedef enum
42 {
43     TEST_INVALID = 0,
44     TEST_GET_DEFAULT,
45     TEST_GET_BATCH,
46     TEST_GET_LINK_LIST,
47     TEST_PUT_DEFAULT,
48     TEST_PUT_BATCH,
49     TEST_PUT_LINK_LIST,
50     TEST_UNKNOWN_RESOURCE_GET_DEFAULT,
51     TEST_UNKNOWN_RESOURCE_GET_BATCH,
52     TEST_UNKNOWN_RESOURCE_GET_LINK_LIST,
53     MAX_TESTS
54 } CLIENT_TEST;
55
56 /**
57  * List of connectivity types that can be initiated from the client
58  * Required for user input validation
59  */
60 typedef enum {
61     CT_ADAPTER_DEFAULT = 0,
62     CT_IPV4,
63     CT_IPV6,
64     MAX_CT
65 } CLIENT_CONNECTIVITY_TYPE;
66
67 unsigned static int TEST = TEST_INVALID;
68 unsigned static int CONNECTIVITY = 0;
69
70 typedef struct
71 {
72     char text[30];
73     CLIENT_TEST test;
74 } testToTextMap;
75
76 testToTextMap queryInterface[] = {
77         {"invalid", TEST_INVALID},
78         {"?if=oic.if.baseline", TEST_GET_DEFAULT},
79         {"?if=oic.if.b", TEST_GET_BATCH},
80         {"?if=oic.if.ll", TEST_GET_LINK_LIST},
81         {"?if=oic.if.baseline", TEST_UNKNOWN_RESOURCE_GET_DEFAULT},
82         {"?if=oic.if.b", TEST_UNKNOWN_RESOURCE_GET_BATCH},
83         {"?if=oic.if.ll", TEST_UNKNOWN_RESOURCE_GET_LINK_LIST},
84         {"?if=oic.if.baseline", TEST_PUT_DEFAULT},
85         {"?if=oic.if.b", TEST_PUT_BATCH},
86         {"?if=oic.if.ll", TEST_PUT_LINK_LIST},
87 };
88
89 static std::string putPayload = "{\"state\":\"off\",\"power\":\"0\"}";
90
91 //The following variable determines the interface protocol (IP, etc)
92 //to be used for sending unicast messages. Default set to IP.
93 static OCConnectivityType OC_CONNTYPE = CT_ADAPTER_IP;
94 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
95
96 // The handle for the observe registration
97 OCDoHandle gObserveDoHandle;
98 // After this crosses a threshold client deregisters for further observations
99 int gNumObserveNotifies = 1;
100
101 int gQuitFlag = 0;
102 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
103 void handleSigInt(int signum)
104 {
105     if (signum == SIGINT)
106     {
107         gQuitFlag = 1;
108     }
109 }
110
111 // Forward Declaration
112 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse);
113 int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse);
114 int InitObserveRequest(OCClientResponse * clientResponse);
115 int InitPutRequest(OCClientResponse * clientResponse);
116 int InitGetRequest(OCClientResponse * clientResponse);
117 int InitDiscovery();
118
119 void PrintUsage()
120 {
121     OC_LOG(INFO, TAG, "Usage : occlientcoll -t <Test Case> -c <CA connectivity Type>");
122     OC_LOG(INFO, TAG, "-c 0 : Default IPv4 and IPv6 auto-selection");
123     OC_LOG(INFO, TAG, "-c 1 : IPv4 Connectivity Type");
124     OC_LOG(INFO, TAG, "-c 2 : IPv6 Connectivity Type (IPv6 not currently supported)");
125     OC_LOG(INFO, TAG, "Test Case 1 : Discover Resources && Initiate GET Request on an "\
126             "available resource using default interface.");
127     OC_LOG(INFO, TAG, "Test Case 2 : Discover Resources && Initiate GET Request on an "\
128                  "available resource using batch interface.");
129     OC_LOG(INFO, TAG, "Test Case 3 : Discover Resources && Initiate GET Request on an "\
130                  "available resource using link list interface.");
131     OC_LOG(INFO, TAG, "Test Case 4 : Discover Resources && Initiate GET & PUT Request on an "\
132                  "available resource using default interface.");
133     OC_LOG(INFO, TAG, "Test Case 5 : Discover Resources && Initiate GET & PUT Request on an "\
134                  "available resource using batch interface.");
135     OC_LOG(INFO, TAG, "Test Case 6 : Discover Resources && Initiate GET & PUT Request on an "\
136                  "available resource using link list interface.");
137     OC_LOG(INFO, TAG, "Test Case 7 : Discover Resources && Initiate GET Request on an "\
138                  "unavailable resource using default interface.");
139     OC_LOG(INFO, TAG, "Test Case 8 : Discover Resources && Initiate GET Request on an "\
140                  "unavailable resource using batch interface.");
141     OC_LOG(INFO, TAG, "Test Case 9 : Discover Resources && Initiate GET Request on an "\
142                  "unavailable resource using link list interface.");
143 }
144
145 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
146 {
147     if(clientResponse == NULL)
148     {
149         OC_LOG(INFO, TAG, "The clientResponse is NULL");
150         return   OC_STACK_DELETE_TRANSACTION;
151     }
152     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
153     {
154         OC_LOG_V(INFO, TAG, "Callback Context for PUT query recvd successfully");
155         OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
156     }
157
158     return OC_STACK_KEEP_TRANSACTION;
159 }
160
161 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
162 {
163     OC_LOG_V(INFO, TAG, "StackResult: %s",
164             getResult(clientResponse->result));
165     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
166     {
167         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
168         if(clientResponse->sequenceNumber == 0)
169         {
170             OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
171             OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
172         }
173         else
174         {
175             OC_LOG_V(INFO, TAG, "Callback Context for Get recvd successfully %d",
176                     gNumObserveNotifies);
177             OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
178             gNumObserveNotifies++;
179             if (gNumObserveNotifies == 3)
180             {
181                 if (OCCancel (gObserveDoHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK)
182                 {
183                     OC_LOG(ERROR, TAG, "Observe cancel error");
184                 }
185             }
186         }
187     }
188     if(TEST == TEST_PUT_DEFAULT || TEST == TEST_PUT_BATCH || TEST == TEST_PUT_LINK_LIST)
189     {
190         InitPutRequest(clientResponse);
191     }
192     return OC_STACK_KEEP_TRANSACTION;
193 }
194
195
196 // This is a function called back when a device is discovered
197 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
198         OCClientResponse * clientResponse)
199 {
200     OC_LOG(INFO, TAG,
201             "Entering discoveryReqCB (Application Layer CB)");
202     OC_LOG_V(INFO, TAG, "StackResult: %s",
203             getResult(clientResponse->result));
204
205     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
206     {
207         OC_LOG_V(INFO, TAG, "Callback Context recvd successfully");
208     }
209
210     OC_LOG_V(INFO, TAG,
211             "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
212             clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
213
214     if(TEST == TEST_UNKNOWN_RESOURCE_GET_DEFAULT || TEST == TEST_UNKNOWN_RESOURCE_GET_BATCH ||\
215             TEST == TEST_UNKNOWN_RESOURCE_GET_LINK_LIST)
216     {
217         InitGetRequestToUnavailableResource(clientResponse);
218     }
219     else
220     {
221         InitGetRequest(clientResponse);
222     }
223     return OC_STACK_KEEP_TRANSACTION;
224 }
225
226
227 int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse)
228 {
229     OCStackResult ret;
230     OCCallbackData cbData;
231     std::ostringstream getQuery;
232     getQuery << "coap://" << clientResponse->devAddr.addr << ":" <<
233             clientResponse->devAddr.port << "/SomeUnknownResource";
234     cbData.cb = getReqCB;
235     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
236     cbData.cd = NULL;
237
238     ret = OCDoResource(NULL, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_CONNTYPE, OC_LOW_QOS,
239             &cbData, NULL, 0);
240     if (ret != OC_STACK_OK)
241     {
242         OC_LOG(ERROR, TAG, "OCStack resource error");
243     }
244     return ret;
245 }
246
247
248 int InitObserveRequest(OCClientResponse * clientResponse)
249 {
250     OCStackResult ret;
251     OCCallbackData cbData;
252     OCDoHandle handle;
253     std::ostringstream obsReg;
254     obsReg << "coap://" << clientResponse->devAddr.addr << ":" <<
255             clientResponse->devAddr.addr <<
256             getQueryStrForGetPut(clientResponse->resJSONPayload);
257     cbData.cb = getReqCB;
258     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
259     cbData.cd = NULL;
260     OC_LOG_V(INFO, TAG, "OBSERVE payload from client = %s ", putPayload.c_str());
261
262     ret = OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_CONNTYPE,
263             OC_LOW_QOS, &cbData, NULL, 0);
264     if (ret != OC_STACK_OK)
265     {
266         OC_LOG(ERROR, TAG, "OCStack resource error");
267     }
268     else
269     {
270         gObserveDoHandle = handle;
271     }
272     return ret;
273 }
274
275
276 int InitPutRequest(OCClientResponse * clientResponse)
277 {
278     OCStackResult ret;
279     OCCallbackData cbData;
280     //* Make a PUT query*/
281     std::ostringstream getQuery;
282     getQuery << "coap://" << clientResponse->devAddr.addr << ":" <<
283             clientResponse->devAddr.port <<
284             "/a/room" << queryInterface[TEST].text;
285     cbData.cb = putReqCB;
286     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
287     cbData.cd = NULL;
288     OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
289
290     ret = OCDoResource(NULL, OC_REST_PUT, getQuery.str().c_str(), 0, putPayload.c_str(),
291                         OC_CONNTYPE, OC_LOW_QOS, &cbData, NULL, 0);
292     if (ret != OC_STACK_OK)
293     {
294         OC_LOG(ERROR, TAG, "OCStack resource error");
295     }
296     return ret;
297 }
298
299
300 int InitGetRequest(OCClientResponse * clientResponse)
301 {
302     OCStackResult ret;
303     OCCallbackData cbData;
304
305     //* Make a GET query*/
306     std::ostringstream getQuery;
307     getQuery << "coap://" << clientResponse->devAddr.addr << ":" <<
308             clientResponse->devAddr.port <<
309             "/a/room" << queryInterface[TEST].text;
310
311     std::cout << "Get Query: " << getQuery.str() << std::endl;
312
313     cbData.cb = getReqCB;
314     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
315     cbData.cd = NULL;
316     ret = OCDoResource(NULL, OC_REST_GET,
317             getQuery.str().c_str(), 0, 0, OC_CONNTYPE, OC_LOW_QOS,
318             &cbData, NULL, 0);
319     if (ret != OC_STACK_OK)
320     {
321         OC_LOG(ERROR, TAG, "OCStack resource error");
322     }
323     return ret;
324 }
325
326 int InitDiscovery()
327 {
328     OCStackResult ret;
329     OCCallbackData cbData;
330     /* Start a discovery query*/
331     char szQueryUri[64] = { 0 };
332
333     strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
334
335     cbData.cb = discoveryReqCB;
336     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
337     cbData.cd = NULL;
338     ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, OC_CONNTYPE,
339                         OC_LOW_QOS,
340             &cbData, NULL, 0);
341     if (ret != OC_STACK_OK)
342     {
343         OC_LOG(ERROR, TAG, "OCStack resource error");
344     }
345     return ret;
346 }
347
348 int main(int argc, char* argv[])
349 {
350     int opt;
351
352     while ((opt = getopt(argc, argv, "t:c:")) != -1)
353     {
354         switch (opt)
355         {
356             case 't':
357                 TEST = atoi(optarg);
358                 break;
359             case 'c':
360                 CONNECTIVITY = atoi(optarg);
361                 break;
362             default:
363                 PrintUsage();
364                 return -1;
365         }
366     }
367     if ((TEST <= TEST_INVALID || TEST >= MAX_TESTS) ||
368         (CONNECTIVITY < CT_ADAPTER_DEFAULT || CONNECTIVITY >= MAX_CT))
369     {
370         PrintUsage();
371         return -1;
372     }
373
374     /* Initialize OCStack*/
375     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
376     {
377         OC_LOG(ERROR, TAG, "OCStack init error");
378         return 0;
379     }
380
381     if(CONNECTIVITY == CT_ADAPTER_DEFAULT)
382     {
383         OC_CONNTYPE = CT_DEFAULT;
384     }
385     else if(CONNECTIVITY == CT_IPV4)
386     {
387         OC_CONNTYPE = CT_IP_USE_V4;
388     }
389     else if(CONNECTIVITY == CT_IPV6)
390     {
391         OC_CONNTYPE = CT_IP_USE_V6;
392
393         //TODO: Remove when IPv6 is available.
394         OC_LOG(INFO, TAG, "Ipv6 is currently not supported...");
395         PrintUsage();
396         return -1;
397     }
398     else
399     {
400         OC_LOG(INFO, TAG, "Default Connectivity type selected...");
401         OC_CONNTYPE = CT_ADAPTER_IP;
402     }
403     InitDiscovery();
404
405     // Break from loop with Ctrl+C
406     OC_LOG(INFO, TAG, "Entering occlient main loop...");
407     signal(SIGINT, handleSigInt);
408     while (!gQuitFlag)
409     {
410
411         if (OCProcess() != OC_STACK_OK)
412         {
413             OC_LOG(ERROR, TAG, "OCStack process error");
414             return 0;
415         }
416
417         sleep(2);
418     } OC_LOG(INFO, TAG, "Exiting occlient main loop...");
419
420     if (OCStop() != OC_STACK_OK)
421     {
422         OC_LOG(ERROR, TAG, "OCStack stop error");
423     }
424
425     return 0;
426 }
427
428 std::string getQueryStrForGetPut(const char * responsePayload)
429 {
430
431     std::string jsonPayload(responsePayload);
432
433     return "/a/room";
434 }
435