resource: simpleserverHQ supports security PS
[iotivity.git] / resource / examples / simpleclientHQ.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 // OCClient.cpp : Defines the entry point for the console application.
22 //
23 #include "iotivity_config.h"
24
25 #include <set>
26 #include <string>
27 #include <cstdlib>
28 #include <mutex>
29 #include <condition_variable>
30 #include "OCPlatform.h"
31 #include "OCApi.h"
32
33 #if defined(HAVE_PTHREAD_H)
34 #include <pthread.h>
35 #endif
36 #if defined(HAVE_WINDOWS_H)
37 #include <windows.h>
38 #endif
39
40 #define MAX_SEQUENCE_NUMBER              (0xFFFFFF)
41
42 using namespace OC;
43
44 struct dereference_compare
45 {
46     bool operator()(std::shared_ptr<OCResource> lhs, std::shared_ptr<OCResource> rhs )const
47     {
48         return *lhs < *rhs;
49     }
50 };
51 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_client.dat";
52 typedef std::set<std::shared_ptr<OCResource>, dereference_compare> DiscoveredResourceSet;
53
54 DiscoveredResourceSet discoveredResources;
55 const int SUCCESS_RESPONSE = 0;
56 std::shared_ptr<OCResource> curResource;
57 std::mutex resourceLock;
58 static ObserveType OBSERVE_TYPE_TO_USE = ObserveType::Observe;
59
60 class Light
61 {
62 public:
63
64     bool m_state;
65     int m_power;
66     std::string m_name;
67
68     Light() : m_state(false), m_power(0), m_name("")
69     {
70     }
71 };
72
73 Light mylight;
74
75 int observe_count()
76 {
77     static int oc = 0;
78     return ++oc;
79 }
80
81 void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation& rep,
82                     const int& eCode, const int& sequenceNumber)
83 {
84     if(eCode == SUCCESS_RESPONSE)
85     {
86         std::cout << "OBSERVE RESULT:"<<std::endl;
87         if(sequenceNumber == (int) ObserveAction::ObserveRegister)
88         {
89             std::cout << "\tObserve Registration Confirmed: "<< std::endl;
90         }
91         else if (sequenceNumber == (MAX_SEQUENCE_NUMBER + 1))
92         {
93             std::cout << "\tObserve Cancel Confirmed: "<< std::endl;
94             sleep(10);
95             std::cout << "DONE"<<std::endl;
96             std::exit(0);
97         }
98         else
99         {
100             std::cout << "\tSequenceNumber: "<< sequenceNumber << std::endl;
101         }
102
103         rep.getValue("state", mylight.m_state);
104         rep.getValue("power", mylight.m_power);
105         rep.getValue("name", mylight.m_name);
106
107         std::cout << "\tstate: " << mylight.m_state << std::endl;
108         std::cout << "\tpower: " << mylight.m_power << std::endl;
109         std::cout << "\tname: " << mylight.m_name << std::endl;
110
111         if(observe_count() == 11)
112         {
113             std::cout<<"Cancelling Observe..."<<std::endl;
114             OCStackResult result = curResource->cancelObserve(OC::QualityOfService::HighQos);
115
116             std::cout << "Cancel result: "<< result << " waiting for confirmation ..." <<std::endl;
117         }
118     }
119     else
120     {
121         std::cout << "onObserve Response error: " << eCode << std::endl;
122         std::exit(-1);
123     }
124 }
125
126 void onPost2(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode)
127 {
128     if(eCode == SUCCESS_RESPONSE || eCode == OC_STACK_RESOURCE_CHANGED
129         || eCode == OC_STACK_RESOURCE_CREATED)
130     {
131         std::cout << "POST request was successful" << std::endl;
132
133         if(rep.hasAttribute("createduri"))
134         {
135             std::cout << "\tUri of the created resource: "
136                       << rep.getValue<std::string>("createduri") << std::endl;
137         }
138         else
139         {
140             rep.getValue("state", mylight.m_state);
141             rep.getValue("power", mylight.m_power);
142             rep.getValue("name", mylight.m_name);
143
144             std::cout << "\tstate: " << mylight.m_state << std::endl;
145             std::cout << "\tpower: " << mylight.m_power << std::endl;
146             std::cout << "\tname: " << mylight.m_name << std::endl;
147         }
148
149         if (OBSERVE_TYPE_TO_USE == ObserveType::Observe)
150             std::cout << std::endl << "Observe is used." << std::endl << std::endl;
151         else if (OBSERVE_TYPE_TO_USE == ObserveType::ObserveAll)
152             std::cout << std::endl << "ObserveAll is used." << std::endl << std::endl;
153         sleep(1);
154         curResource->observe(OBSERVE_TYPE_TO_USE, QueryParamsMap(), &onObserve,
155                 OC::QualityOfService::HighQos);
156
157     }
158     else
159     {
160         std::cout << "onPost2 Response error: " << eCode << std::endl;
161         std::exit(-1);
162     }
163 }
164
165 void onPost(const HeaderOptions& /*headerOptions*/,
166         const OCRepresentation& rep, const int eCode)
167 {
168     if(eCode == SUCCESS_RESPONSE || eCode == OC_STACK_RESOURCE_CHANGED
169         || eCode == OC_STACK_RESOURCE_CREATED)
170     {
171         std::cout << "POST request was successful" << std::endl;
172
173         if(rep.hasAttribute("createduri"))
174         {
175             std::cout << "\tUri of the created resource: "
176                       << rep.getValue<std::string>("createduri") << std::endl;
177         }
178         else
179         {
180             rep.getValue("state", mylight.m_state);
181             rep.getValue("power", mylight.m_power);
182             rep.getValue("name", mylight.m_name);
183
184             std::cout << "\tstate: " << mylight.m_state << std::endl;
185             std::cout << "\tpower: " << mylight.m_power << std::endl;
186             std::cout << "\tname: " << mylight.m_name << std::endl;
187         }
188
189         OCRepresentation rep2;
190
191         std::cout << "Posting light representation..."<<std::endl;
192
193         mylight.m_state = true;
194         mylight.m_power = 55;
195
196         rep2.setValue("state", mylight.m_state);
197         rep2.setValue("power", mylight.m_power);
198         sleep(1);
199         curResource->post(rep2, QueryParamsMap(), &onPost2, OC::QualityOfService::HighQos);
200     }
201     else
202     {
203         std::cout << "onPost Response error: " << eCode << std::endl;
204         std::exit(-1);
205     }
206 }
207
208 // Local function to put a different state for this resource
209 void postLightRepresentation(std::shared_ptr<OCResource> resource)
210 {
211     if(resource)
212     {
213         OCRepresentation rep;
214
215         std::cout << "Posting light representation..."<<std::endl;
216
217         mylight.m_state = false;
218         mylight.m_power = 105;
219
220         rep.setValue("state", mylight.m_state);
221         rep.setValue("power", mylight.m_power);
222
223         // Invoke resource's post API with rep, query map and the callback parameter
224         resource->post(rep, QueryParamsMap(), &onPost, OC::QualityOfService::HighQos);
225     }
226 }
227
228 // callback handler on PUT request
229 void onPut(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode)
230 {
231     if(eCode == SUCCESS_RESPONSE || eCode == OC_STACK_RESOURCE_CHANGED)
232     {
233         std::cout << "PUT request was successful" << std::endl;
234
235         rep.getValue("state", mylight.m_state);
236         rep.getValue("power", mylight.m_power);
237         rep.getValue("name", mylight.m_name);
238
239         std::cout << "\tstate: " << mylight.m_state << std::endl;
240         std::cout << "\tpower: " << mylight.m_power << std::endl;
241         std::cout << "\tname: " << mylight.m_name << std::endl;
242         sleep(1);
243         postLightRepresentation(curResource);
244     }
245     else
246     {
247         std::cout << "onPut Response error: " << eCode << std::endl;
248         std::exit(-1);
249     }
250 }
251
252 // Local function to put a different state for this resource
253 void putLightRepresentation(std::shared_ptr<OCResource> resource)
254 {
255     if(resource)
256     {
257         OCRepresentation rep;
258
259         std::cout << "Putting light representation..."<<std::endl;
260
261         mylight.m_state = true;
262         mylight.m_power = 15;
263
264         rep.setValue("state", mylight.m_state);
265         rep.setValue("power", mylight.m_power);
266
267         // Invoke resource's put API with rep, query map and the callback parameter
268         resource->put(rep, QueryParamsMap(), &onPut, OC::QualityOfService::HighQos);
269     }
270 }
271
272 // Callback handler on GET request
273 void onGet(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode)
274 {
275     if(eCode == SUCCESS_RESPONSE)
276     {
277         std::cout << "GET request was successful" << std::endl;
278         std::cout << "Resource URI: " << rep.getUri() << std::endl;
279
280         rep.getValue("state", mylight.m_state);
281         rep.getValue("power", mylight.m_power);
282         rep.getValue("name", mylight.m_name);
283
284         std::cout << "\tstate: " << mylight.m_state << std::endl;
285         std::cout << "\tpower: " << mylight.m_power << std::endl;
286         std::cout << "\tname: " << mylight.m_name << std::endl;
287         sleep(1);
288         putLightRepresentation(curResource);
289     }
290     else
291     {
292         std::cout << "onGET Response error: " << eCode << std::endl;
293         std::exit(-1);
294     }
295 }
296
297 // Local function to get representation of light resource
298 void getLightRepresentation(std::shared_ptr<OCResource> resource)
299 {
300     if(resource)
301     {
302         std::cout << "Getting Light Representation..."<<std::endl;
303         // Invoke resource's get API with the callback parameter
304
305         QueryParamsMap test;
306         resource->get(test, &onGet,OC::QualityOfService::HighQos);
307     }
308 }
309
310 // Callback to found resources
311 void foundResource(std::shared_ptr<OCResource> resource)
312 {
313     std::string resourceURI;
314     std::string hostAddress;
315     try
316     {
317         // Do some operations with resource object.
318         if(resource)
319         {
320             std::lock_guard<std::mutex> lk(resourceLock);
321
322             if(discoveredResources.find(resource) == discoveredResources.end())
323             {
324                 std::cout << "Found resource " << resource->uniqueIdentifier() <<
325                     " for the first time on server with ID: "<< resource->sid()<<std::endl;
326                 discoveredResources.insert(resource);
327             }
328             else
329             {
330                 std::cout<<"Found resource "<< resource->uniqueIdentifier() << " again!"<<std::endl;
331             }
332
333             if(curResource)
334             {
335                 std::cout << "Found another resource, ignoring"<<std::endl;
336                 return;
337             }
338
339             std::cout<<"DISCOVERED Resource:"<<std::endl;
340             // Get the resource URI
341             resourceURI = resource->uri();
342             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
343
344             // Get the resource host address
345             hostAddress = resource->host();
346             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
347
348             // Get the resource types
349             std::cout << "\tList of resource types: " << std::endl;
350             for(auto &resourceTypes : resource->getResourceTypes())
351             {
352                 std::cout << "\t\t" << resourceTypes << std::endl;
353             }
354
355             // Get the resource interfaces
356             std::cout << "\tList of resource interfaces: " << std::endl;
357             for(auto &resourceInterfaces : resource->getResourceInterfaces())
358             {
359                 std::cout << "\t\t" << resourceInterfaces << std::endl;
360             }
361
362             if(resourceURI == "/a/light")
363             {
364                 curResource = resource;
365                 sleep(1);
366                 // Call a local function which will internally invoke get
367                 // API on the resource pointer
368                 getLightRepresentation(resource);
369             }
370         }
371         else
372         {
373             // Resource is invalid
374             std::cout << "Resource is invalid" << std::endl;
375         }
376
377     }
378     catch(std::exception& e)
379     {
380         std::cerr << "Exception in foundResource: "<< e.what() <<std::endl;
381     }
382 }
383
384 void PrintUsage()
385 {
386     std::cout << std::endl;
387     std::cout << "Usage : simpleclientHQ <ObserveType> <ConnectivityType>" << std::endl;
388     std::cout << "   ObserveType : 1 - Observe" << std::endl;
389     std::cout << "   ObserveType : 2 - ObserveAll" << std::endl;
390     std::cout << "   ConnectivityType: Default IP" << std::endl;
391     std::cout << "   ConnectivityType : 0 - IP"<< std::endl;
392 }
393
394
395 static FILE* override_fopen(const char* path, const char* mode)
396 {
397     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
398     {
399         return fopen(SVR_DB_FILE_NAME, mode);
400     }
401     else
402     {
403         return fopen(path, mode);
404     }
405 }
406
407 int main(int argc, char* argv[]) {
408
409     std::ostringstream requestURI;
410
411     OCConnectivityType connectivityType = CT_ADAPTER_IP;
412     try
413     {
414         if (argc == 1)
415         {
416             OBSERVE_TYPE_TO_USE = ObserveType::Observe;
417         }
418         else if (argc ==2 || argc==3)
419         {
420             int value = std::stoi(argv[1]);
421             if (value == 1)
422                 OBSERVE_TYPE_TO_USE = ObserveType::Observe;
423             else if (value == 2)
424                 OBSERVE_TYPE_TO_USE = ObserveType::ObserveAll;
425             else
426                 OBSERVE_TYPE_TO_USE = ObserveType::Observe;
427
428             if(argc == 3)
429             {
430                 std::size_t inputValLen;
431                 int optionSelected = std::stoi(argv[2], &inputValLen);
432
433                 if(inputValLen == strlen(argv[2]))
434                 {
435                     if(optionSelected == 0)
436                     {
437                         std::cout << "Using IP."<< std::endl;
438                         connectivityType = CT_ADAPTER_IP;
439                     }
440                     else
441                     {
442                         std::cout << "Invalid connectivity type selected. Using default IP"
443                             << std::endl;
444                     }
445                 }
446                 else
447                 {
448                     std::cout << "Invalid connectivity type selected. Using default IP"
449                             << std::endl;
450                 }
451             }
452         }
453         else
454         {
455             PrintUsage();
456             return -1;
457         }
458     }
459     catch(std::exception&)
460     {
461         std::cout << "Invalid input argument." << std::endl;
462         PrintUsage();
463         return -1;
464     }
465
466     OCPersistentStorage ps {override_fopen, fread, fwrite, fclose, unlink };
467     // Create PlatformConfig object
468     PlatformConfig cfg {
469         OC::ServiceType::InProc,
470         OC::ModeType::Client,
471         &ps
472     };
473     
474     cfg.QoS = OC::QualityOfService::HighQos;
475
476     OCPlatform::Configure(cfg);
477
478     try
479     {
480         OC_VERIFY(OCPlatform::start() == OC_STACK_OK);
481
482         // Find all resources
483         requestURI << OC_RSRVD_WELL_KNOWN_URI << "?rt=core.light";
484
485         OCPlatform::findResource("", requestURI.str(),
486                 connectivityType, &foundResource, OC::QualityOfService::LowQos);
487         std::cout<< "Finding Resource... " <<std::endl;
488
489         // Find resource is done twice so that we discover the original resources a second time.
490         // These resources will have the same uniqueidentifier (yet be different objects), so that
491         // we can verify/show the duplicate-checking code in foundResource(above);
492         OCPlatform::findResource("", requestURI.str(),
493                 connectivityType, &foundResource, OC::QualityOfService::LowQos);
494         std::cout<< "Finding Resource for second time... " <<std::endl;
495
496         // A condition variable will free the mutex it is given, then do a non-
497         // intensive block until 'notify' is called on it.  In this case, since we
498         // don't ever call cv.notify, this should be a non-processor intensive version
499         // of while(true);
500         std::mutex blocker;
501         std::condition_variable cv;
502         std::unique_lock<std::mutex> lock(blocker);
503         cv.wait(lock);
504
505         // Perform platform clean up.
506         OC_VERIFY(OCPlatform::stop() == OC_STACK_OK);
507     }
508     catch(OCException& e)
509     {
510         oclog() << "Exception in main: "<<e.what();
511     }
512
513     return 0;
514 }
515
516