Merge branch 'master' into resource-manipulation
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / secure / occlientbasicops.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 "occlientbasicops.h"
31 #include "cJSON.h"
32 #include "common.h"
33
34 #define TAG "occlientbasicops"
35 static int UNICAST_DISCOVERY = 0;
36 static int TEST_CASE = 0;
37 static int CONN_TYPE = 0;
38
39 static int IPV4_ADDR_SIZE = 16;
40 static char UNICAST_DISCOVERY_QUERY[] = "coap://%s:6298/oic/res";
41 static char MULTICAST_DISCOVERY_QUERY[] = "/oic/res";
42 OCConnectivityType discoveryReqConnType = CT_ADAPTER_IP;
43
44 static std::string putPayload = "{\"oic\":[{\"rep\":{\"state\":\"off\",\"power\":10}}]}";
45 static std::string coapServerIP;
46 static std::string coapServerPort;
47 static std::string coapServerResource;
48 static int coapSecureResource;
49 static OCConnectivityType ocConnType;
50
51
52 //Secure Virtual Resource database for Iotivity Client application
53 //It contains Client's Identity and the PSK credentials
54 //of other devices which the client trusts
55 static char CRED_FILE[] = "oic_svr_db_client.json";
56
57
58 int gQuitFlag = 0;
59
60 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
61 void handleSigInt(int signum)
62 {
63     if (signum == SIGINT)
64     {
65         gQuitFlag = 1;
66     }
67 }
68
69 static void PrintUsage()
70 {
71     OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1|2>");
72     OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
73     OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
74     OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
75             " Initiate Nonconfirmable Get/Put/Post Requests");
76     OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate Confirmable Get/Put/Post Requests");
77     OC_LOG(INFO, TAG, "-c 0 : Default IPv4 and IPv6 auto-selection");
78     OC_LOG(INFO, TAG, "-c 1 : IPv4 Connectivity Type");
79     OC_LOG(INFO, TAG, "-c 2 : IPv6 Connectivity Type (IPv6 not currently supported)");
80 }
81
82 OCStackResult InvokeOCDoResource(std::ostringstream &query,
83         OCMethod method, OCQualityOfService qos,
84         OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
85 {
86     OCStackResult ret;
87     OCCallbackData cbData;
88
89     cbData.cb = cb;
90     cbData.context = NULL;
91     cbData.cd = NULL;
92
93     ret = OCDoResource(NULL, method, query.str().c_str(), 0,
94             (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload.c_str() : NULL,
95             ocConnType, qos, &cbData, options, numOptions);
96
97     if (ret != OC_STACK_OK)
98     {
99         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
100     }
101
102     return ret;
103 }
104
105 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
106 {
107     OC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully");
108
109     if(clientResponse)
110     {
111         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
112         OC_LOG_V(INFO, TAG, "JSON = %s =============> Put Response", clientResponse->resJSONPayload);
113     }
114     return OC_STACK_DELETE_TRANSACTION;
115 }
116
117 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle, OCClientResponse *clientResponse)
118 {
119     OC_LOG(INFO, TAG, "Callback Context for POST recvd successfully");
120
121     if(clientResponse)
122     {
123         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
124         OC_LOG_V(INFO, TAG, "JSON = %s =============> Post Response",
125                 clientResponse->resJSONPayload);
126     }
127     return OC_STACK_DELETE_TRANSACTION;
128 }
129
130 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
131 {
132     OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
133
134     if(clientResponse)
135     {
136         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
137         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
138         OC_LOG_V(INFO, TAG, "JSON = %s =============> Get Response",
139                 clientResponse->resJSONPayload);
140     }
141     return OC_STACK_DELETE_TRANSACTION;
142 }
143
144 // This is a function called back when a device is discovered
145 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
146         OCClientResponse * clientResponse)
147 {
148     OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
149
150     if (clientResponse)
151     {
152         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
153         OC_LOG_V(INFO, TAG,
154                 "Device =============> Discovered %s @ %s:%d",
155                 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
156
157         ocConnType = clientResponse->connType;
158
159         if (parseClientResponse(clientResponse) != -1)
160         {
161             switch(TEST_CASE)
162             {
163                 case TEST_NON_CON_OP:
164                     InitGetRequest(OC_LOW_QOS);
165                     InitPutRequest(OC_LOW_QOS);
166                     //InitPostRequest(OC_LOW_QOS);
167                     break;
168                 case TEST_CON_OP:
169                     InitGetRequest(OC_HIGH_QOS);
170                     InitPutRequest(OC_HIGH_QOS);
171                     //InitPostRequest(OC_HIGH_QOS);
172                     break;
173             }
174         }
175     }
176
177     return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
178
179 }
180
181 int InitPutRequest(OCQualityOfService qos)
182 {
183     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
184     std::ostringstream query;
185     query << (coapSecureResource ? "coaps://" : "coap://") << coapServerIP
186         << ":" << coapServerPort  << coapServerResource;
187     return (InvokeOCDoResource(query, OC_REST_PUT,
188             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS), putReqCB, NULL, 0));
189 }
190
191 int InitPostRequest(OCQualityOfService qos)
192 {
193     OCStackResult result;
194     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
195     std::ostringstream query;
196     query << (coapSecureResource ? "coaps://" : "coap://") << coapServerIP
197         << ":" << coapServerPort << coapServerResource;
198
199     // First POST operation (to create an LED instance)
200     result = InvokeOCDoResource(query, OC_REST_POST,
201             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
202             postReqCB, NULL, 0);
203     if (OC_STACK_OK != result)
204     {
205         // Error can happen if for example, network connectivity is down
206         OC_LOG(INFO, TAG, "First POST call did not succeed");
207     }
208
209     // Second POST operation (to create an LED instance)
210     result = InvokeOCDoResource(query, OC_REST_POST,
211             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
212             postReqCB, NULL, 0);
213     if (OC_STACK_OK != result)
214     {
215         OC_LOG(INFO, TAG, "Second POST call did not succeed");
216     }
217
218     // This POST operation will update the original resourced /a/led
219     return (InvokeOCDoResource(query, OC_REST_POST,
220                 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
221                 postReqCB, NULL, 0));
222 }
223
224 int InitGetRequest(OCQualityOfService qos)
225 {
226     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
227     std::ostringstream query;
228     query << (coapSecureResource ? "coaps://" : "coap://") << coapServerIP
229         << ":" << coapServerPort << coapServerResource;
230
231     return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)?
232             OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
233 }
234
235 int InitDiscovery()
236 {
237     OCStackResult ret;
238     OCMethod method;
239     OCCallbackData cbData;
240     char szQueryUri[MAX_URI_LENGTH] = { 0 };
241
242     if (UNICAST_DISCOVERY)
243     {
244         char ipv4addr[IPV4_ADDR_SIZE];
245         printf("Enter IPv4 address of the Server hosting secure resource (Ex: 11.12.13.14)\n");
246         if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
247         {
248             //Strip newline char from ipv4addr
249             StripNewLineChar(ipv4addr);
250             snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
251         }
252         else
253         {
254             OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
255             return OC_STACK_INVALID_PARAM;
256         }
257         method = OC_REST_GET;
258     }
259     else
260     {
261         //Send discovery request on Wifi and Ethernet interface
262         discoveryReqConnType = CT_DEFAULT;
263         strcpy(szQueryUri, MULTICAST_DISCOVERY_QUERY);
264         method = OC_REST_DISCOVER;
265     }
266
267     cbData.cb = discoveryReqCB;
268     cbData.context = NULL;
269     cbData.cd = NULL;
270
271     /* Start a discovery query*/
272     OC_LOG_V(INFO, TAG, "Initiating %s Resource Discovery : %s\n",
273         (UNICAST_DISCOVERY) ? "Unicast" : "Multicast",
274         szQueryUri);
275
276     ret = OCDoResource(NULL, method, szQueryUri, 0, 0,
277             discoveryReqConnType, OC_LOW_QOS,
278             &cbData, NULL, 0);
279     if (ret != OC_STACK_OK)
280     {
281         OC_LOG(ERROR, TAG, "OCStack resource error");
282     }
283     return ret;
284 }
285
286 FILE* client_fopen(const char *path, const char *mode)
287 {
288     (void)path;
289     return fopen(CRED_FILE, mode);
290 }
291
292 int main(int argc, char* argv[])
293 {
294     int opt;
295     struct timespec timeout;
296
297     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
298     {
299         switch(opt)
300         {
301             case 'u':
302                 UNICAST_DISCOVERY = atoi(optarg);
303                 break;
304             case 't':
305                 TEST_CASE = atoi(optarg);
306                 break;
307             case 'c':
308                 CONN_TYPE = atoi(optarg);
309                 break;
310             default:
311                 PrintUsage();
312                 return -1;
313         }
314     }
315
316     if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
317             (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS)||
318             (CONN_TYPE < CT_ADAPTER_DEFAULT || CONN_TYPE >= MAX_CT))
319     {
320         PrintUsage();
321         return -1;
322     }
323
324
325     if(CONN_TYPE == CT_ADAPTER_DEFAULT)
326     {
327         discoveryReqConnType = CT_DEFAULT;
328     }
329     else if(CONN_TYPE == CT_IPV4)
330     {
331         discoveryReqConnType = CT_IP_USE_V4;
332     }
333     else if(CONN_TYPE == CT_IPV6)
334     {
335         //TODO: Remove when IPv6 is available.
336         //discoveryReqConnType = CT_IP_USE_V6;
337         OC_LOG(ERROR, TAG, "IPv6 is currently not supported !!!!");
338         PrintUsage();
339         return -1;
340     }
341     else
342     {
343         printf("Using Default Connectivity type\n\n");
344         PrintUsage();
345     }
346
347
348     // Initialize Persistent Storage for SVR database
349     OCPersistentStorage ps = {};
350     ps.open = client_fopen;
351     ps.read = fread;
352     ps.write = fwrite;
353     ps.close = fclose;
354     ps.unlink = unlink;
355     OCRegisterPersistentStorageHandler(&ps);
356
357     /* Initialize OCStack*/
358     if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
359     {
360         OC_LOG(ERROR, TAG, "OCStack init error");
361         return 0;
362     }
363
364     InitDiscovery();
365
366     timeout.tv_sec  = 0;
367     timeout.tv_nsec = 100000000L;
368
369     // Break from loop with Ctrl+C
370     OC_LOG(INFO, TAG, "Entering occlient main loop...");
371     signal(SIGINT, handleSigInt);
372     while (!gQuitFlag)
373     {
374         if (OCProcess() != OC_STACK_OK)
375         {
376             OC_LOG(ERROR, TAG, "OCStack process error");
377             return 0;
378         }
379
380         nanosleep(&timeout, NULL);
381     }
382     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
383
384     if (OCStop() != OC_STACK_OK)
385     {
386         OC_LOG(ERROR, TAG, "OCStack stop error");
387     }
388
389     return 0;
390 }
391
392 std::string getPortTBServer(OCClientResponse * clientResponse)
393 {
394     if(!clientResponse) return "";
395     std::ostringstream ss;
396     ss << clientResponse->devAddr.port;
397     return ss.str();
398 }
399
400 int parseClientResponse(OCClientResponse * clientResponse)
401 {
402     int port = -1;
403     cJSON * root = NULL;
404     cJSON * oc = NULL;
405
406     // Initialize all global variables
407     coapServerResource.clear();
408     coapServerPort.clear();
409     coapServerIP.clear();
410     coapSecureResource = 0;
411
412     root = cJSON_Parse((char *)(clientResponse->resJSONPayload));
413     if (!root)
414     {
415         return -1;
416     }
417
418     oc = cJSON_GetObjectItem(root,"oic");
419     if (!oc)
420     {
421         return -1;
422     }
423
424     if (oc->type == cJSON_Array)
425     {
426         int numRsrcs =  cJSON_GetArraySize(oc);
427         for(int i = 0; i < numRsrcs; i++)
428         {
429             cJSON * resource = cJSON_GetArrayItem(oc, i);
430             if (cJSON_GetObjectItem(resource, "href"))
431             {
432                 coapServerResource.assign(cJSON_GetObjectItem(resource, "href")->valuestring);
433             }
434             else
435             {
436                 coapServerResource = "";
437             }
438             OC_LOG_V(INFO, TAG, "Uri -- %s", coapServerResource.c_str());
439
440             cJSON * prop = cJSON_GetObjectItem(resource,"prop");
441             if (prop)
442             {
443                 cJSON * policy = cJSON_GetObjectItem(prop,"p");
444                 if (policy)
445                 {
446                     // If this is a secure resource, the info about the port at which the
447                     // resource is hosted on server is embedded inside discovery JSON response
448                     if (cJSON_GetObjectItem(policy, "sec"))
449                     {
450                         if ((cJSON_GetObjectItem(policy, "sec")->valueint) == 1)
451                         {
452                             coapSecureResource = 1;
453                         }
454                     }
455                     OC_LOG_V(INFO, TAG, "Secure -- %s", coapSecureResource == 1 ? "YES" : "NO");
456                     if (cJSON_GetObjectItem(policy, "port"))
457                     {
458                         port = cJSON_GetObjectItem(policy, "port")->valueint;
459                         OC_LOG_V(INFO, TAG, "Hosting Server Port (embedded inside JSON) -- %u", port);
460
461                         std::ostringstream ss;
462                         ss << port;
463                         coapServerPort = ss.str();
464                     }
465                 }
466             }
467
468             // If we discovered a secure resource, exit from here
469             if (coapSecureResource)
470             {
471                 break;
472             }
473         }
474     }
475     cJSON_Delete(root);
476
477     coapServerIP = clientResponse->devAddr.addr;
478     if (port == -1)
479     {
480         coapServerPort = getPortTBServer(clientResponse);
481         OC_LOG_V(INFO, TAG, "Hosting Server Port -- %s", coapServerPort.c_str());
482     }
483     return 0;
484 }
485