TLS support
[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 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_WINDOWS_H
29 #include <windows.h>
30 /** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */
31 #ifdef ERROR
32 #undef ERROR
33 #endif
34 #endif
35 #include <iostream>
36 #include <sstream>
37 #include <getopt.h>
38 #include "platform_features.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
223 int InitPutRequest(OCQualityOfService qos)
224 {
225     OIC_LOG_V(INFO, TAG, "Executing %s", __func__);
226     std::ostringstream query;
227     query << coapServerResource;
228     if(WithTcp)
229     {
230         endpoint.adapter = OC_ADAPTER_TCP;
231     }
232     endpoint.flags = (OCTransportFlags)(endpoint.flags|OC_SECURE);
233     return (InvokeOCDoResource(query, OC_REST_PUT, &endpoint,
234             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS), putReqCB, NULL, 0));
235 }
236
237 int InitPostRequest(OCQualityOfService qos)
238 {
239     OCStackResult result;
240
241     OIC_LOG_V(INFO, TAG, "Executing %s", __func__);
242     std::ostringstream query;
243     query << coapServerResource;
244     endpoint.flags = (OCTransportFlags)(endpoint.flags|OC_SECURE);
245
246     // First POST operation (to create an LED instance)
247     result = InvokeOCDoResource(query, OC_REST_POST, &endpoint,
248             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
249             postReqCB, NULL, 0);
250     if (OC_STACK_OK != result)
251     {
252         // Error can happen if for example, network connectivity is down
253         OIC_LOG(INFO, TAG, "First POST call did not succeed");
254     }
255
256     // Second POST operation (to create an LED instance)
257     result = InvokeOCDoResource(query, OC_REST_POST, &endpoint,
258             ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
259             postReqCB, NULL, 0);
260     if (OC_STACK_OK != result)
261     {
262         OIC_LOG(INFO, TAG, "Second POST call did not succeed");
263     }
264
265     // This POST operation will update the original resourced /a/led
266     return (InvokeOCDoResource(query, OC_REST_POST, &endpoint,
267                 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
268                 postReqCB, NULL, 0));
269 }
270
271 int InitGetRequest(OCQualityOfService qos)
272 {
273     OIC_LOG_V(INFO, TAG, "Executing %s", __func__);
274     std::ostringstream query;
275     query << coapServerResource;
276     endpoint.flags = (OCTransportFlags)(endpoint.flags|OC_SECURE);
277
278     return (InvokeOCDoResource(query, OC_REST_GET, &endpoint,
279                 ((qos == OC_HIGH_QOS)?  OC_HIGH_QOS:OC_LOW_QOS),
280                 getReqCB, NULL, 0));
281 }
282
283 int InitDiscovery()
284 {
285     OCStackResult ret;
286     OCCallbackData cbData;
287     char queryUri[200];
288     char ipaddr[100] = { '\0' };
289
290     if (UnicastDiscovery)
291     {
292         OIC_LOG(INFO, TAG, "Enter IP address (with optional port) of the Server hosting resource\n");
293         OIC_LOG(INFO, TAG, "IPv4: 192.168.0.15:45454\n");
294         OIC_LOG(INFO, TAG, "IPv6: [fe80::20c:29ff:fe1b:9c5]:45454\n");
295
296         if (fgets(ipaddr, sizeof (ipaddr), stdin))
297         {
298             StripNewLineChar(ipaddr); //Strip newline char from ipaddr
299         }
300         else
301         {
302             OIC_LOG(ERROR, TAG, "!! Bad input for IP address. !!");
303             return OC_STACK_INVALID_PARAM;
304         }
305     }
306     snprintf(queryUri, sizeof (queryUri), DISCOVERY_QUERY, ipaddr);
307
308     cbData.cb = discoveryReqCB;
309     cbData.context = NULL;
310     cbData.cd = NULL;
311
312     /* Start a discovery query*/
313     OIC_LOG_V(INFO, TAG, "Initiating %s Resource Discovery : %s\n",
314         (UnicastDiscovery) ? "Unicast" : "Multicast",
315         queryUri);
316
317     ret = OCDoResource(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,
318                        OC_LOW_QOS, &cbData, NULL, 0);
319     if (ret != OC_STACK_OK)
320     {
321         OIC_LOG(ERROR, TAG, "OCStack resource error");
322     }
323     return ret;
324 }
325
326 FILE* client_fopen_devowner(const char *path, const char *mode)
327 {
328     (void)path;
329     return fopen(CRED_FILE_DEVOWNER, mode);
330 }
331
332 FILE* client_fopen_nondevowner(const char *path, const char *mode)
333 {
334     (void)path;
335     return fopen(CRED_FILE_NONDEVOWNER, mode);
336 }
337 int main(int argc, char* argv[])
338 {
339     int opt;
340     struct timespec timeout;
341     OCPersistentStorage ps;
342
343     while ((opt = getopt(argc, argv, "u:t:c:d:p:")) != -1)
344     {
345         switch(opt)
346         {
347             case 'u':
348                 UnicastDiscovery = atoi(optarg);
349                 break;
350             case 't':
351                 TestCase = atoi(optarg);
352                 break;
353             case 'c':
354                 ConnType = atoi(optarg);
355                 break;
356             case 'd':
357                 DevOwner = atoi(optarg);
358                 break;
359             case 'p':
360             {
361                 WithTcp = atoi(optarg);
362                 if(WithTcp > 1)
363                 {
364                     PrintUsage();
365                     return -1;
366                 }
367             }
368                 break;
369             default:
370                 PrintUsage();
371                 return -1;
372         }
373     }
374
375     if ((UnicastDiscovery != 0 && UnicastDiscovery != 1) ||
376             (TestCase < TEST_DISCOVER_REQ || TestCase >= MAX_TESTS)||
377             (ConnType < CT_ADAPTER_DEFAULT || ConnType >= MAX_CT))
378     {
379         PrintUsage();
380         return -1;
381     }
382
383
384     if(ConnType == CT_ADAPTER_DEFAULT || ConnType ==  CT_IP)
385     {
386         discoveryReqConnType = CT_DEFAULT;
387     }
388     else
389     {
390         OIC_LOG(INFO, TAG, "Using Default Connectivity type");
391         PrintUsage();
392     }
393
394
395     // Initialize Persistent Storage for SVR database
396     if (DevOwner)
397         ps = { client_fopen_devowner, fread, fwrite, fclose, unlink };
398     else
399         ps = { client_fopen_nondevowner, fread, fwrite, fclose, unlink };
400     OCRegisterPersistentStorageHandler(&ps);
401
402     /* Initialize OCStack*/
403     if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
404     {
405         OIC_LOG(ERROR, TAG, "OCStack init error");
406         return 0;
407     }
408
409     InitDiscovery();
410
411     timeout.tv_sec  = 0;
412     timeout.tv_nsec = 100000000L;
413
414     // Break from loop with Ctrl+C
415     OIC_LOG(INFO, TAG, "Entering occlient main loop...");
416     signal(SIGINT, handleSigInt);
417     while (!gQuitFlag)
418     {
419         if (OCProcess() != OC_STACK_OK)
420         {
421             OIC_LOG(ERROR, TAG, "OCStack process error");
422             return 0;
423         }
424
425         nanosleep(&timeout, NULL);
426     }
427     OIC_LOG(INFO, TAG, "Exiting occlient main loop...");
428
429     if (OCStop() != OC_STACK_OK)
430     {
431         OIC_LOG(ERROR, TAG, "OCStack stop error");
432     }
433
434     return 0;
435 }
436
437 int parseClientResponse(OCClientResponse * clientResponse)
438 {
439     OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
440
441     // Initialize all global variables
442     coapServerResource.clear();
443     coapSecureResource = 0;
444
445     while (res)
446     {
447         coapServerResource.assign(res->uri);
448         OIC_LOG_V(INFO, TAG, "Uri -- %s", coapServerResource.c_str());
449         if (0 == strcmp(coapServerResource.c_str(),OIC_RSRC_DOXM_URI))
450         {
451             OIC_LOG(INFO,TAG,"Skip: doxm is secure virtual resource");
452             res = res->next;
453             continue;
454         }
455         if (0 == strcmp(coapServerResource.c_str(),OIC_RSRC_PSTAT_URI))
456         {
457             OIC_LOG(INFO,TAG,"Skip: pstat is secure virtual resource");
458             res = res->next;
459             continue;
460         }
461         if (res->secure)
462         {
463             if(WithTcp)
464             {
465 #ifdef TCP_ADAPTER
466                 OIC_LOG_V(INFO,TAG,"SECUREPORT tcp: %d",res->tcpPort);
467                 endpoint.port = res->tcpPort;
468 #endif
469             }
470             else
471             {
472                 OIC_LOG_V(INFO,TAG,"SECUREPORT udp: %d",res->port);
473                 endpoint.port = res->port;
474             }
475             coapSecureResource = 1;
476         }
477
478         OIC_LOG_V(INFO, TAG, "Secure -- %s", coapSecureResource == 1 ? "YES" : "NO");
479
480         // If we discovered a secure resource, exit from here
481         if (coapSecureResource)
482         {
483             break;
484         }
485
486         res = res->next;
487     }
488
489     return 0;
490 }
491