10aa3ffc9b37c2fa8f0dc5d3ad2068a23983a90a
[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 "iotivity_config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <signal.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_WINDOWS_H
30 #include <windows.h>
31 /** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */
32 #ifdef ERROR
33 #undef ERROR
34 #endif
35 #endif
36 #include <iostream>
37 #include <sstream>
38 #include <getopt.h>
39 #include "ocstack.h"
40 #include "logger.h"
41 #include "occlientbasicops.h"
42 #include "ocpayload.h"
43 #include "payload_logging.h"
44 #include "oic_string.h"
45 #include "common.h"
46
47 #define TAG "occlientbasicops"
48 static int UnicastDiscovery = 0;
49 static int TestCase = 0;
50 static int ConnType = 0;
51 static int DevOwner = 0;
52 static int WithTcp = 0;
53
54 static char DISCOVERY_QUERY[] = "%s/oic/res";
55 OCConnectivityType discoveryReqConnType = CT_ADAPTER_IP;
56 static OCDevAddr endpoint;
57
58 static std::string coapServerResource;
59 static int coapSecureResource;
60 static OCConnectivityType ocConnType;
61
62 //Secure Virtual Resource database for Iotivity Client application
63 //It contains Client's Identity and the PSK credentials
64 //of other devices which the client trusts
65 static char CRED_FILE_DEVOWNER[] = "oic_svr_db_client_devowner.dat";
66 static char CRED_FILE_NONDEVOWNER[] = "oic_svr_db_client_nondevowner.dat";
67 const char * OIC_RSRC_DOXM_URI =  "/oic/sec/doxm";
68 const char * OIC_RSRC_PSTAT_URI = "/oic/sec/pstat";
69
70 int gQuitFlag = 0;
71
72 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
73 void handleSigInt(int signum)
74 {
75     if (signum == SIGINT)
76     {
77         gQuitFlag = 1;
78     }
79 }
80
81 OCPayload* putPayload()
82 {
83     OCRepPayload* payload = OCRepPayloadCreate();
84
85     if(!payload)
86     {
87         std::cout << "Failed to create put payload object"<<std::endl;
88         std::exit(1);
89     }
90
91     OCRepPayloadSetPropInt(payload, "power", 15);
92     OCRepPayloadSetPropBool(payload, "state", true);
93
94     return (OCPayload*) payload;
95 }
96
97 static void PrintUsage()
98 {
99     OIC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
100     OIC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
101     OIC_LOG(INFO, TAG, "-t 1 : Discover Resources");
102     OIC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
103             " Initiate Nonconfirmable Get/Put/Post Requests");
104     OIC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate Confirmable Get/Put/Post Requests");
105     OIC_LOG(INFO, TAG, "-c 0 : Default auto-selection");
106     OIC_LOG(INFO, TAG, "-c 1 : IP Connectivity Type");
107     OIC_LOG(INFO, TAG, "-d 0 : Client as Non Device Owner");
108     OIC_LOG(INFO, TAG, "-d 1 : Client as Device Owner");
109     OIC_LOG(INFO, TAG, "-p 0 : Use UDP protocol");
110     OIC_LOG(INFO, TAG, "-p 1 : Use TCP protocol");
111 }
112
113 OCStackResult InvokeOCDoResource(std::ostringstream &query,
114                                  OCMethod method,
115                                  const OCDevAddr *dest,
116                                  OCQualityOfService qos,
117                                  OCClientResponseHandler cb,
118                                  OCHeaderOption * options, uint8_t numOptions)
119 {
120     OCStackResult ret;
121     OCCallbackData cbData;
122
123     cbData.cb = cb;
124     cbData.context = NULL;
125     cbData.cd = NULL;
126
127     ret = OCDoResource(NULL, method, query.str().c_str(), dest,
128             (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload() : NULL,
129             ocConnType, qos, &cbData, options, numOptions);
130
131     if (ret != OC_STACK_OK)
132     {
133         OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
134     }
135
136     return ret;
137 }
138
139 OCStackApplicationResult putReqCB(void*, OCDoHandle, OCClientResponse * clientResponse)
140 {
141     OIC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully");
142
143     if(clientResponse)
144     {
145         OIC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
146         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
147         OIC_LOG(INFO, TAG, ("=============> Put Response"));
148     }
149     return OC_STACK_DELETE_TRANSACTION;
150 }
151
152 OCStackApplicationResult postReqCB(void *, OCDoHandle, OCClientResponse *clientResponse)
153 {
154     OIC_LOG(INFO, TAG, "Callback Context for POST recvd successfully");
155
156     if(clientResponse)
157     {
158         OIC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
159         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
160         OIC_LOG(INFO, TAG, ("=============> Post Response"));
161     }
162     return OC_STACK_DELETE_TRANSACTION;
163 }
164
165 OCStackApplicationResult getReqCB(void*, OCDoHandle, OCClientResponse * clientResponse)
166 {
167     OIC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
168
169     if(clientResponse)
170     {
171         OIC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
172         OIC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
173         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
174         OIC_LOG(INFO, TAG, ("=============> Get Response"));
175     }
176     return OC_STACK_DELETE_TRANSACTION;
177 }
178
179 // This is a function called back when a device is discovered
180 OCStackApplicationResult discoveryReqCB(void*, OCDoHandle,
181         OCClientResponse * clientResponse)
182 {
183     OIC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
184
185     if (clientResponse)
186     {
187         OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
188         OIC_LOG_V(INFO, TAG,
189                 "Device =============> Discovered @ %s:%d",
190                 clientResponse->devAddr.addr,
191                 clientResponse->devAddr.port);
192
193         if (clientResponse->result == OC_STACK_OK)
194         {
195             OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
196
197             ocConnType = clientResponse->connType;
198             endpoint = clientResponse->devAddr;
199
200             if (parseClientResponse(clientResponse) != -1)
201             {
202                 switch(TestCase)
203                 {
204                     case TEST_NON_CON_OP:
205                         InitGetRequest(OC_LOW_QOS);
206                         InitPutRequest(OC_LOW_QOS);
207                         InitPostRequest(OC_LOW_QOS);
208                         break;
209                     case TEST_CON_OP:
210                         InitGetRequest(OC_HIGH_QOS);
211                         InitPutRequest(OC_HIGH_QOS);
212                         InitPostRequest(OC_HIGH_QOS);
213                         break;
214                 }
215             }
216         }
217     }
218
219     return (UnicastDiscovery) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
220
221 }
222 int InitPutRequest(OCQualityOfService qos)
223 {
224     OIC_LOG_V(INFO, TAG, "Executing %s", __func__);
225     std::ostringstream query;
226     query << coapServerResource;
227     if(WithTcp)
228     {
229         endpoint.adapter = OC_ADAPTER_TCP;
230     }
231     endpoint.flags = (OCTransportFlags)(endpoint.flags|OC_SECURE);
232     return (InvokeOCDoResource(query, OC_REST_PUT, &endpoint,
233             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS), putReqCB, NULL, 0));
234 }
235
236 int InitPostRequest(OCQualityOfService qos)
237 {
238     OCStackResult result;
239
240     OIC_LOG_V(INFO, TAG, "Executing %s", __func__);
241     std::ostringstream query;
242     query << coapServerResource;
243     if(WithTcp)
244     {
245         endpoint.adapter = OC_ADAPTER_TCP;
246     }
247     endpoint.flags = (OCTransportFlags)(endpoint.flags|OC_SECURE);
248
249     // First POST operation (to create an LED instance)
250     result = InvokeOCDoResource(query, OC_REST_POST, &endpoint,
251             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
252             postReqCB, NULL, 0);
253     if (OC_STACK_OK != result)
254     {
255         // Error can happen if for example, network connectivity is down
256         OIC_LOG(INFO, TAG, "First POST call did not succeed");
257     }
258
259     // Second POST operation (to create an LED instance)
260     result = InvokeOCDoResource(query, OC_REST_POST, &endpoint,
261             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
262             postReqCB, NULL, 0);
263     if (OC_STACK_OK != result)
264     {
265         OIC_LOG(INFO, TAG, "Second POST call did not succeed");
266     }
267
268     // This POST operation will update the original resourced /a/led (as long as
269     // the server is set to max 2 /lcd resources)
270     result = InvokeOCDoResource(query, OC_REST_POST, &endpoint,
271             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
272             postReqCB, NULL, 0);
273     if (OC_STACK_OK != result)
274     {
275         OIC_LOG(INFO, TAG, "Third POST call did not succeed");
276     }
277     return result;
278 }
279
280 int InitGetRequest(OCQualityOfService qos)
281 {
282     OIC_LOG_V(INFO, TAG, "Executing %s", __func__);
283     std::ostringstream query;
284     query << coapServerResource;
285     if(WithTcp)
286     {
287         endpoint.adapter = OC_ADAPTER_TCP;
288     }
289     endpoint.flags = (OCTransportFlags)(endpoint.flags|OC_SECURE);
290
291     return (InvokeOCDoResource(query, OC_REST_GET, &endpoint,
292                 ((qos == OC_HIGH_QOS)?  OC_HIGH_QOS:OC_LOW_QOS),
293                 getReqCB, NULL, 0));
294 }
295
296 int InitDiscovery()
297 {
298     OCStackResult ret;
299     OCCallbackData cbData;
300     char queryUri[200];
301     char ipaddr[100] = { '\0' };
302
303     if (UnicastDiscovery)
304     {
305         OIC_LOG(INFO, TAG, "Enter IP address (with optional port) of the Server hosting resource\n");
306         OIC_LOG(INFO, TAG, "IPv4: 192.168.0.15:45454\n");
307         OIC_LOG(INFO, TAG, "IPv6: [fe80::20c:29ff:fe1b:9c5]:45454\n");
308
309         if (fgets(ipaddr, sizeof (ipaddr), stdin))
310         {
311             StripNewLineChar(ipaddr); //Strip newline char from ipaddr
312         }
313         else
314         {
315             OIC_LOG(ERROR, TAG, "!! Bad input for IP address. !!");
316             return OC_STACK_INVALID_PARAM;
317         }
318     }
319     snprintf(queryUri, sizeof (queryUri), DISCOVERY_QUERY, ipaddr);
320
321     cbData.cb = discoveryReqCB;
322     cbData.context = NULL;
323     cbData.cd = NULL;
324
325     /* Start a discovery query*/
326     OIC_LOG_V(INFO, TAG, "Initiating %s Resource Discovery : %s\n",
327         (UnicastDiscovery) ? "Unicast" : "Multicast",
328         queryUri);
329
330     ret = OCDoResource(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,
331                        OC_LOW_QOS, &cbData, NULL, 0);
332     if (ret != OC_STACK_OK)
333     {
334         OIC_LOG(ERROR, TAG, "OCStack resource error");
335     }
336     return ret;
337 }
338
339 FILE* client_fopen_devowner(const char *path, const char *mode)
340 {
341     (void)path;
342     return fopen(CRED_FILE_DEVOWNER, mode);
343 }
344
345 FILE* client_fopen_nondevowner(const char *path, const char *mode)
346 {
347     (void)path;
348     return fopen(CRED_FILE_NONDEVOWNER, mode);
349 }
350 int main(int argc, char* argv[])
351 {
352     int opt;
353     struct timespec timeout;
354     OCPersistentStorage ps;
355
356     while ((opt = getopt(argc, argv, "u:t:c:d:p:")) != -1)
357     {
358         switch(opt)
359         {
360             case 'u':
361                 UnicastDiscovery = atoi(optarg);
362                 break;
363             case 't':
364                 TestCase = atoi(optarg);
365                 break;
366             case 'c':
367                 ConnType = atoi(optarg);
368                 break;
369             case 'd':
370                 DevOwner = atoi(optarg);
371                 break;
372             case 'p':
373             {
374                 WithTcp = atoi(optarg);
375                 if(WithTcp > 1)
376                 {
377                     PrintUsage();
378                     return -1;
379                 }
380             }
381                 break;
382             default:
383                 PrintUsage();
384                 return -1;
385         }
386     }
387
388     if ((UnicastDiscovery != 0 && UnicastDiscovery != 1) ||
389             (TestCase < TEST_DISCOVER_REQ || TestCase >= MAX_TESTS)||
390             (ConnType < CT_ADAPTER_DEFAULT || ConnType >= MAX_CT))
391     {
392         PrintUsage();
393         return -1;
394     }
395
396
397     if(ConnType == CT_ADAPTER_DEFAULT || ConnType ==  CT_IP)
398     {
399         discoveryReqConnType = CT_DEFAULT;
400     }
401     else
402     {
403         OIC_LOG(INFO, TAG, "Using Default Connectivity type");
404         PrintUsage();
405     }
406
407
408     // Initialize Persistent Storage for SVR database
409     if (DevOwner)
410         ps = { client_fopen_devowner, fread, fwrite, fclose, unlink };
411     else
412         ps = { client_fopen_nondevowner, fread, fwrite, fclose, unlink };
413     OCRegisterPersistentStorageHandler(&ps);
414
415     /* Initialize OCStack*/
416     if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
417     {
418         OIC_LOG(ERROR, TAG, "OCStack init error");
419         return 0;
420     }
421
422     InitDiscovery();
423
424     timeout.tv_sec  = 0;
425     timeout.tv_nsec = 100000000L;
426
427     // Break from loop with Ctrl+C
428     OIC_LOG(INFO, TAG, "Entering occlient main loop...");
429     signal(SIGINT, handleSigInt);
430     while (!gQuitFlag)
431     {
432         if (OCProcess() != OC_STACK_OK)
433         {
434             OIC_LOG(ERROR, TAG, "OCStack process error");
435             return 0;
436         }
437
438         nanosleep(&timeout, NULL);
439     }
440     OIC_LOG(INFO, TAG, "Exiting occlient main loop...");
441
442     if (OCStop() != OC_STACK_OK)
443     {
444         OIC_LOG(ERROR, TAG, "OCStack stop error");
445     }
446
447     return 0;
448 }
449
450 int parseClientResponse(OCClientResponse * clientResponse)
451 {
452     OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
453
454     // Initialize all global variables
455     coapServerResource.clear();
456     coapSecureResource = 0;
457
458     while (res)
459     {
460         coapServerResource.assign(res->uri);
461         OIC_LOG_V(INFO, TAG, "Uri -- %s", coapServerResource.c_str());
462         if (0 == strcmp(coapServerResource.c_str(),OIC_RSRC_DOXM_URI))
463         {
464             OIC_LOG(INFO,TAG,"Skip: doxm is secure virtual resource");
465             res = res->next;
466             continue;
467         }
468         if (0 == strcmp(coapServerResource.c_str(),OIC_RSRC_PSTAT_URI))
469         {
470             OIC_LOG(INFO,TAG,"Skip: pstat is secure virtual resource");
471             res = res->next;
472             continue;
473         }
474         if (res->secure)
475         {
476             if(WithTcp)
477             {
478 #ifdef TCP_ADAPTER
479                 OIC_LOG_V(INFO,TAG,"SECUREPORT tcp: %d",res->tcpPort);
480                 endpoint.port = res->tcpPort;
481 #endif
482             }
483             else
484             {
485                 OIC_LOG_V(INFO,TAG,"SECUREPORT udp: %d",res->port);
486                 endpoint.port = res->port;
487             }
488             coapSecureResource = 1;
489         }
490
491         OIC_LOG_V(INFO, TAG, "Secure -- %s", coapSecureResource == 1 ? "YES" : "NO");
492
493         // If we discovered a secure resource, exit from here
494         if (coapSecureResource)
495         {
496             break;
497         }
498
499         res = res->next;
500     }
501
502     return 0;
503 }
504