[IOT-3296] Disable CertificateRequest at MFG OTM
[iotivity.git] / resource / examples / simpleclient.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 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_PTHREAD_H
28 #include <pthread.h>
29 #endif
30 #ifdef HAVE_WINDOWS_H
31 #include <Windows.h>
32 #endif
33 #include <string>
34 #include <map>
35 #include <cstdlib>
36 #include <mutex>
37 #include <condition_variable>
38 #include "OCPlatform.h"
39 #include "OCApi.h"
40
41 using namespace OC;
42
43 #define CA_OPTION_CONTENT_VERSION 2053
44 #define COAP_OPTION_CONTENT_FORMAT 12
45 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_client.dat";
46 typedef std::map<OCResourceIdentifier, std::shared_ptr<OCResource>> DiscoveredResourceMap;
47
48 DiscoveredResourceMap discoveredResources;
49 std::shared_ptr<OCResource> curResource;
50 static ObserveType OBSERVE_TYPE_TO_USE = ObserveType::Observe;
51 static OCConnectivityType TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_IP;
52 std::mutex curResourceLock;
53
54 class Light
55 {
56 public:
57
58     bool m_state;
59     int m_power;
60     std::string m_name;
61
62     Light() : m_state(false), m_power(0), m_name("")
63     {
64     }
65 };
66
67 Light mylight;
68
69 int observe_count()
70 {
71     static int oc = 0;
72     return ++oc;
73 }
74
75 void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation& rep,
76                     const int& eCode, const int& sequenceNumber)
77 {
78     try
79     {
80         if(eCode == OC_STACK_OK && sequenceNumber <= MAX_SEQUENCE_NUMBER)
81         {
82             if(sequenceNumber == OC_OBSERVE_REGISTER)
83             {
84                 std::cout << "Observe registration action is successful" << std::endl;
85             }
86
87             std::cout << "OBSERVE RESULT:"<<std::endl;
88             std::cout << "\tSequenceNumber: "<< sequenceNumber << std::endl;
89             rep.getValue("state", mylight.m_state);
90             rep.getValue("power", mylight.m_power);
91             rep.getValue("name", mylight.m_name);
92
93             std::cout << "\tstate: " << mylight.m_state << std::endl;
94             std::cout << "\tpower: " << mylight.m_power << std::endl;
95             std::cout << "\tname: " << mylight.m_name << std::endl;
96
97             if(observe_count() == 11)
98             {
99                 std::cout<<"Cancelling Observe..."<<std::endl;
100                 OCStackResult result = curResource->cancelObserve();
101
102                 std::cout << "Cancel result: "<< result <<std::endl;
103                 sleep(10);
104                 std::cout << "DONE"<<std::endl;
105                 std::exit(0);
106             }
107         }
108         else
109         {
110             if(eCode == OC_STACK_OK)
111             {
112                 std::cout << "No observe option header is returned in the response." << std::endl;
113                 std::cout << "For a registration request, it means the registration failed"
114                         << std::endl;
115                 std::cout << "For a cancelation request, it means the cancelation was successful"
116                         << std::endl;
117             }
118             else
119             {
120                 std::cout << "onObserve Response error: " << eCode << std::endl;
121                 std::exit(-1);
122             }
123         }
124     }
125     catch(std::exception& e)
126     {
127         std::cout << "Exception: " << e.what() << " in onObserve" << std::endl;
128     }
129
130 }
131
132 void onPost2(const HeaderOptions& /*headerOptions*/,
133         const OCRepresentation& rep, const int eCode)
134 {
135     try
136     {
137         if(eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CREATED
138                 || eCode == OC_STACK_RESOURCE_CHANGED)
139         {
140             std::cout << "POST request was successful" << std::endl;
141
142             if(rep.hasAttribute("createduri"))
143             {
144                 std::cout << "\tUri of the created resource: "
145                     << rep.getValue<std::string>("createduri") << std::endl;
146             }
147             else
148             {
149                 rep.getValue("state", mylight.m_state);
150                 rep.getValue("power", mylight.m_power);
151                 rep.getValue("name", mylight.m_name);
152
153                 std::cout << "\tstate: " << mylight.m_state << std::endl;
154                 std::cout << "\tpower: " << mylight.m_power << std::endl;
155                 std::cout << "\tname: " << mylight.m_name << std::endl;
156             }
157
158             if (OBSERVE_TYPE_TO_USE == ObserveType::Observe)
159                 std::cout << std::endl << "Observe is used." << std::endl << std::endl;
160             else if (OBSERVE_TYPE_TO_USE == ObserveType::ObserveAll)
161                 std::cout << std::endl << "ObserveAll is used." << std::endl << std::endl;
162
163             curResource->observe(OBSERVE_TYPE_TO_USE, QueryParamsMap(), &onObserve);
164
165         }
166         else
167         {
168             std::cout << "onPost2 Response error: " << eCode << std::endl;
169             std::exit(-1);
170         }
171     }
172     catch(std::exception& e)
173     {
174         std::cout << "Exception: " << e.what() << " in onPost2" << std::endl;
175     }
176
177 }
178
179 void onPost(const HeaderOptions& /*headerOptions*/,
180         const OCRepresentation& rep, const int eCode)
181 {
182     try
183     {
184         if(eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CREATED
185                 || eCode == OC_STACK_RESOURCE_CHANGED)
186         {
187             std::cout << "POST request was successful" << std::endl;
188
189             if(rep.hasAttribute("createduri"))
190             {
191                 std::cout << "\tUri of the created resource: "
192                     << rep.getValue<std::string>("createduri") << std::endl;
193             }
194             else
195             {
196                 rep.getValue("state", mylight.m_state);
197                 rep.getValue("power", mylight.m_power);
198                 rep.getValue("name", mylight.m_name);
199
200                 std::cout << "\tstate: " << mylight.m_state << std::endl;
201                 std::cout << "\tpower: " << mylight.m_power << std::endl;
202                 std::cout << "\tname: " << mylight.m_name << std::endl;
203             }
204
205             OCRepresentation rep2;
206
207             std::cout << "Posting light representation..."<<std::endl;
208
209             mylight.m_state = true;
210             mylight.m_power = 55;
211
212             rep2.setValue("state", mylight.m_state);
213             rep2.setValue("power", mylight.m_power);
214
215             curResource->post(rep2, QueryParamsMap(), &onPost2);
216         }
217         else
218         {
219             std::cout << "onPost Response error: " << eCode << std::endl;
220             std::exit(-1);
221         }
222     }
223     catch(std::exception& e)
224     {
225         std::cout << "Exception: " << e.what() << " in onPost" << std::endl;
226     }
227 }
228
229 // Local function to put a different state for this resource
230 void postLightRepresentation(std::shared_ptr<OCResource> resource)
231 {
232     if(resource)
233     {
234         OCRepresentation rep;
235
236         std::cout << "Posting light representation..."<<std::endl;
237
238         mylight.m_state = false;
239         mylight.m_power = 105;
240
241         rep.setValue("state", mylight.m_state);
242         rep.setValue("power", mylight.m_power);
243
244         // Invoke resource's post API with rep, query map and the callback parameter
245         resource->post(rep, QueryParamsMap(), &onPost);
246     }
247 }
248
249 // callback handler on PUT request
250 void onPut(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode)
251 {
252     try
253     {
254         if (eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CHANGED)
255         {
256             std::cout << "PUT request was successful" << std::endl;
257
258             rep.getValue("state", mylight.m_state);
259             rep.getValue("power", mylight.m_power);
260             rep.getValue("name", mylight.m_name);
261
262             std::cout << "\tstate: " << mylight.m_state << std::endl;
263             std::cout << "\tpower: " << mylight.m_power << std::endl;
264             std::cout << "\tname: " << mylight.m_name << std::endl;
265
266             postLightRepresentation(curResource);
267         }
268         else
269         {
270             std::cout << "onPut Response error: " << eCode << std::endl;
271             std::exit(-1);
272         }
273     }
274     catch(std::exception& e)
275     {
276         std::cout << "Exception: " << e.what() << " in onPut" << std::endl;
277     }
278 }
279
280 // Local function to put a different state for this resource
281 void putLightRepresentation(std::shared_ptr<OCResource> resource)
282 {
283     if(resource)
284     {
285         OCRepresentation rep;
286
287         std::cout << "Putting light representation..."<<std::endl;
288
289         mylight.m_state = true;
290         mylight.m_power = 15;
291
292         rep.setValue("state", mylight.m_state);
293         rep.setValue("power", mylight.m_power);
294
295         // Invoke resource's put API with rep, query map and the callback parameter
296         resource->put(rep, QueryParamsMap(), &onPut);
297     }
298 }
299
300 // Callback handler on GET request
301 void onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
302 {
303     try
304     {
305         if(eCode == OC_STACK_OK)
306         {
307             std::cout << "GET request was successful" << std::endl;
308             std::cout << "Resource URI: " << rep.getUri() << std::endl;
309
310             // Get resource header options
311             if ( headerOptions.size() == 0)
312             {
313                 std::cout << "No header option exists" << std::endl;
314             }
315             else
316             {
317                 for (auto it = headerOptions.begin(); it != headerOptions.end(); ++it)
318                 {
319                     if (it->getOptionID() == COAP_OPTION_CONTENT_FORMAT)
320                     {
321                         size_t dataLength = it->getOptionData().length();
322                         char* optionData = new char[dataLength];
323                         strncpy(optionData, it->getOptionData().c_str(), dataLength);
324                         int format = optionData[0] * 256 + optionData[1];
325                         std::cout << "Server format in GET response:" << format << std::endl;
326                         delete[] optionData;
327                     }
328                     if (it->getOptionID() == CA_OPTION_CONTENT_VERSION)
329                     {
330                         size_t dataLength = it->getOptionData().length();
331                         char* optionData = new char[dataLength];
332                         strncpy(optionData, it->getOptionData().c_str(), dataLength);
333                         int version = optionData[0] * 256;
334                         std::cout << "Server version in GET response:" << version << std::endl;
335                         delete[] optionData;
336                     }
337                 }
338             }
339             rep.getValue("state", mylight.m_state);
340             rep.getValue("power", mylight.m_power);
341             rep.getValue("name", mylight.m_name);
342
343             std::cout << "\tstate: " << mylight.m_state << std::endl;
344             std::cout << "\tpower: " << mylight.m_power << std::endl;
345             std::cout << "\tname: " << mylight.m_name << std::endl;
346
347             putLightRepresentation(curResource);
348         }
349         else
350         {
351             std::cout << "onGET Response error: " << eCode << std::endl;
352             std::exit(-1);
353         }
354     }
355     catch(std::exception& e)
356     {
357         std::cout << "Exception: " << e.what() << " in onGet" << std::endl;
358     }
359 }
360
361 // Local function to get representation of light resource
362 void getLightRepresentation(std::shared_ptr<OCResource> resource)
363 {
364     if(resource)
365     {
366         std::cout << "Getting Light Representation..."<<std::endl;
367         // Invoke resource's get API with the callback parameter
368
369         QueryParamsMap test;
370         resource->get(test, &onGet);
371     }
372 }
373
374 // Callback to found resources
375 void foundResource(std::shared_ptr<OCResource> resource)
376 {
377     std::cout << "In foundResource\n";
378     std::string resourceURI;
379     std::string hostAddress;
380     try
381     {
382         {
383             std::lock_guard<std::mutex> lock(curResourceLock);
384             if(discoveredResources.find(resource->uniqueIdentifier()) == discoveredResources.end())
385             {
386                 std::cout << "Found resource " << resource->uniqueIdentifier() <<
387                     " for the first time on server with ID: "<< resource->sid()<<std::endl;
388                 discoveredResources[resource->uniqueIdentifier()] = resource;
389             }
390             else
391             {
392                 std::cout<<"Found resource "<< resource->uniqueIdentifier() << " again!"<<std::endl;
393             }
394
395             if(curResource)
396             {
397                 std::cout << "Found another resource, ignoring"<<std::endl;
398                 return;
399             }
400         }
401
402         // Do some operations with resource object.
403         if(resource)
404         {
405             std::cout<<"DISCOVERED Resource:"<<std::endl;
406             // Get the resource URI
407             resourceURI = resource->uri();
408             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
409
410             // Get the resource host address
411             hostAddress = resource->host();
412             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
413
414             // Get the resource types
415             std::cout << "\tList of resource types: " << std::endl;
416             for(auto &resourceTypes : resource->getResourceTypes())
417             {
418                 std::cout << "\t\t" << resourceTypes << std::endl;
419             }
420
421             // Get the resource interfaces
422             std::cout << "\tList of resource interfaces: " << std::endl;
423             for(auto &resourceInterfaces : resource->getResourceInterfaces())
424             {
425                 std::cout << "\t\t" << resourceInterfaces << std::endl;
426             }
427
428             // Get Resource current host
429             std::cout << "\tHost of resource: " << std::endl;
430             std::cout << "\t\t" << resource->host() << std::endl;
431
432             // Get Resource Endpoint Infomation
433             std::cout << "\tList of resource endpoints: " << std::endl;
434             for(auto &resourceEndpoints : resource->getAllHosts())
435             {
436                 std::cout << "\t\t" << resourceEndpoints << std::endl;
437             }
438
439             // If resource is found from ip based adapter.
440             if (std::string::npos != resource->host().find("coap://") ||
441                 std::string::npos != resource->host().find("coaps://") ||
442                 std::string::npos != resource->host().find("coap+tcp://") ||
443                 std::string::npos != resource->host().find("coaps+tcp://"))
444             {
445                 for(auto &resourceEndpoints : resource->getAllHosts())
446                 {
447                     if (resourceEndpoints.compare(resource->host()) != 0 &&
448                         std::string::npos == resourceEndpoints.find("coap+rfcomm"))
449                     {
450                         std::string newHost = resourceEndpoints;
451
452                         if (std::string::npos != newHost.find("tcp"))
453                         {
454                             TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_TCP;
455                         }
456                         else
457                         {
458                             TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_IP;
459                         }
460                         // Change Resource host if another host exists
461                         std::cout << "\tChange host of resource endpoints" << std::endl;
462                         std::cout << "\t\t" << "Current host is "
463                                   << resource->setHost(newHost) << std::endl;
464                         break;
465                     }
466                 }
467             }
468
469             if(resourceURI == "/a/light")
470             {
471                 HeaderOptions headerOptions = resource->getServerHeaderOptions();
472                 if (headerOptions.size() == 0)
473                 {
474                     std::cout << "No header option exists" << std::endl;
475                 }
476                 else
477                 {
478                     for (auto it = headerOptions.begin(); it != headerOptions.end(); ++it)
479                     {
480                         if (it->getOptionID() == COAP_OPTION_CONTENT_FORMAT)
481                         {
482                             size_t dataLength = it->getOptionData().length();
483                             char* optionData = new char[dataLength];
484                             strncpy(optionData, it->getOptionData().c_str(), dataLength);
485                             int format = optionData[0] * 256 + optionData[1];
486                             std::cout << "Server format in Discovery response:" << format
487                                     << std::endl;
488                             delete[] optionData;
489                         }
490                         if (it->getOptionID() == CA_OPTION_CONTENT_VERSION)
491                         {
492                             size_t dataLength = it->getOptionData().length();
493                             char* optionData = new char[dataLength];
494                             strncpy(optionData, it->getOptionData().c_str(), dataLength);
495                             int version = optionData[0] * 256;
496                             std::cout << "Server version in Discovery response:" << version
497                                     << std::endl;
498                             delete[] optionData;
499                         }
500                     }
501                 }
502
503                 if (resource->connectivityType() & TRANSPORT_TYPE_TO_USE)
504                 {
505                     curResource = resource;
506                     // Get the resource host address
507                     std::cout << "\tAddress of selected resource: " << resource->host() << std::endl;
508
509                     // Call a local function which will internally invoke get API on the resource pointer
510                     getLightRepresentation(resource);
511                 }
512             }
513         }
514         else
515         {
516             // Resource is invalid
517             std::cout << "Resource is invalid" << std::endl;
518         }
519
520     }
521     catch(std::exception& e)
522     {
523         std::cerr << "Exception in foundResource: "<< e.what() << std::endl;
524     }
525 }
526
527 void printUsage()
528 {
529     std::cout << std::endl;
530     std::cout << "---------------------------------------------------------------------\n";
531     std::cout << "Usage : simpleclient <ObserveType> <TransportType>" << std::endl;
532     std::cout << "   ObserveType : 1 - Observe" << std::endl;
533     std::cout << "   ObserveType : 2 - ObserveAll" << std::endl;
534     std::cout << "   TransportType : 1 - IP" << std::endl;
535     std::cout << "   TransportType : 2 - TCP" << std::endl;
536     std::cout << "---------------------------------------------------------------------\n\n";
537 }
538
539 void checkObserverValue(int value)
540 {
541     if (value == 1)
542     {
543         OBSERVE_TYPE_TO_USE = ObserveType::Observe;
544         std::cout << "<===Setting ObserveType to Observe===>\n\n";
545     }
546     else if (value == 2)
547     {
548         OBSERVE_TYPE_TO_USE = ObserveType::ObserveAll;
549         std::cout << "<===Setting ObserveType to ObserveAll===>\n\n";
550     }
551     else
552     {
553         std::cout << "<===Invalid ObserveType selected."
554                   <<" Setting ObserveType to Observe===>\n\n";
555     }
556 }
557
558 void checkTransportValue(int value)
559 {
560     if (1 == value)
561     {
562         TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_IP;
563         std::cout << "<===Setting TransportType to IP===>\n\n";
564     }
565     else if (2 == value)
566     {
567         TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_TCP;
568         std::cout << "<===Setting TransportType to TCP===>\n\n";
569     }
570     else
571     {
572         std::cout << "<===Invalid TransportType selected."
573                   <<" Setting TransportType to IP===>\n\n";
574     }
575 }
576
577 static FILE* client_open(const char* path, const char* mode)
578 {
579     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
580     {
581         return fopen(SVR_DB_FILE_NAME, mode);
582     }
583     else
584     {
585         return fopen(path, mode);
586     }
587 }
588
589 int main(int argc, char* argv[]) {
590
591     std::ostringstream requestURI;
592     OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
593     try
594     {
595         printUsage();
596         if (argc == 1)
597         {
598             std::cout << "<===Setting ObserveType to Observe and ConnectivityType to IP===>\n\n";
599         }
600         else if (argc == 2)
601         {
602             checkObserverValue(std::stoi(argv[1]));
603         }
604         else if (argc == 3)
605         {
606             checkObserverValue(std::stoi(argv[1]));
607             checkTransportValue(std::stoi(argv[2]));
608         }
609         else
610         {
611             std::cout << "<===Invalid number of command line arguments===>\n\n";
612             return -1;
613         }
614     }
615     catch(std::exception& )
616     {
617         std::cout << "<===Invalid input arguments===>\n\n";
618         return -1;
619     }
620
621     // Create PlatformConfig object
622     PlatformConfig cfg {
623         OC::ServiceType::InProc,
624         OC::ModeType::Both,
625         &ps
626     };
627
628     cfg.transportType = static_cast<OCTransportAdapter>(OCTransportAdapter::OC_ADAPTER_IP | 
629                                                         OCTransportAdapter::OC_ADAPTER_TCP);
630     cfg.QoS = OC::QualityOfService::HighQos;
631
632     OCPlatform::Configure(cfg);
633     try
634     {
635         OC_VERIFY(OCPlatform::start() == OC_STACK_OK);
636
637         // makes it so that all boolean values are printed as 'true/false' in this stream
638         std::cout.setf(std::ios::boolalpha);
639         // Find all resources
640         requestURI << OC_RSRVD_WELL_KNOWN_URI;// << "?rt=core.light";
641
642         OCPlatform::findResource("", requestURI.str(),
643                 CT_DEFAULT, &foundResource);
644         std::cout<< "Finding Resource... " <<std::endl;
645
646         // Find resource is done twice so that we discover the original resources a second time.
647         // These resources will have the same uniqueidentifier (yet be different objects), so that
648         // we can verify/show the duplicate-checking code in foundResource(above);
649         OCPlatform::findResource("", requestURI.str(),
650                 CT_DEFAULT, &foundResource);
651         std::cout<< "Finding Resource for second time..." << std::endl;
652
653         // A condition variable will free the mutex it is given, then do a non-
654         // intensive block until 'notify' is called on it.  In this case, since we
655         // don't ever call cv.notify, this should be a non-processor intensive version
656         // of while(true);
657         std::mutex blocker;
658         std::condition_variable cv;
659         std::unique_lock<std::mutex> lock(blocker);
660         cv.wait(lock);
661
662         // Perform platform clean up.
663         OC_VERIFY(OCPlatform::stop() == OC_STACK_OK);
664
665     }catch(OCException& e)
666     {
667         oclog() << "Exception in main: "<<e.what();
668     }
669
670     return 0;
671 }
672
673