Merge branch 'master' into resource-manipulation
[platform/upstream/iotivity.git] / resource / examples / simpleclientserver.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 ///
22 /// This sample provides steps to define an interface for a resource
23 /// (properties and methods) and host this resource on the server.
24 /// Additionally, it'll have a client example to discover it as well.
25 ///
26 #include <memory>
27 #include <iostream>
28 #include <stdexcept>
29 #include <condition_variable>
30 #include <map>
31 #include <vector>
32 #include "OCPlatform.h"
33 #include "OCApi.h"
34 using namespace OC;
35
36 static void printUsage()
37 {
38     std::cout<< "    Usage simpleclientserver <0|1>" << std::endl;
39     std::cout<< "    ConnectivityType: Default IP" << std::endl;
40     std::cout << "   ConnectivityType : 0 - IPv4" << std::endl;
41     std::cout << "   ConnectivityType : 1 - IPv6 (Currently Not Supported)" << std::endl;
42 }
43
44 class ClientWorker
45 {
46 private:
47     void putResourceInfo(const HeaderOptions& headerOptions,
48             const OCRepresentation rep, const OCRepresentation rep2, const int eCode)
49     {
50        std::cout << "In PutResourceInfo" << std::endl;
51
52        std::cout <<"Clientside Put response to get was: "<<std::endl;
53        std::cout <<"ErrorCode: "<<eCode <<std::endl;
54
55        if(eCode == 0)
56        {
57             std::cout<<"Successful Put.  Attributes sent were: "<<std::endl;
58
59             rep.getValue("isFoo", m_isFoo);
60             rep.getValue("barCount", m_barCount);
61
62             std::cout << "\tisFoo: "<< m_isFoo << std::endl;
63             std::cout << "\tbarCount: "<< m_barCount << std::endl;
64
65             std::cout<<"Actual New values are: "<<std::endl;
66
67             rep.getValue("isFoo", m_isFoo);
68             rep.getValue("barCount", m_barCount);
69
70             std::cout << "\tisFoo: "<< m_isFoo << std::endl;
71             std::cout << "\tbarCount: "<< m_barCount << std::endl;
72
73             m_cv.notify_all();
74        }
75     }
76
77     void getResourceInfo(const HeaderOptions& headerOptions, const OCRepresentation rep,
78                 const int eCode)
79     {
80         std::cout << "In getResourceInfo" << std::endl;
81
82         std::cout<<"Clientside response to get was: "<<std::endl;
83         std::cout<<"Error Code: "<<eCode<<std::endl;
84
85         if(eCode == 0)
86         {
87             std::cout <<"Successful Get.  Attributes are: "<<std::endl;
88
89             rep.getValue("isFoo", m_isFoo);
90             rep.getValue("barCount", m_barCount);
91
92             std::cout << "\tisFoo: "<< m_isFoo << std::endl;
93             std::cout << "\tbarCount: "<< m_barCount << std::endl;
94
95             std::cout << "Doing a put on q/foo" <<std::endl;
96             OCRepresentation rep2(rep);
97             m_isFoo = false;
98             m_barCount = 211;
99
100             rep2.setValue("isFoo", m_isFoo);
101             rep2.setValue("barCount", m_barCount);
102
103             m_resource->put(rep2, QueryParamsMap(),
104                 PutCallback(std::bind(&ClientWorker::putResourceInfo, this, std::placeholders::_1,
105                      rep2, std::placeholders::_2, std::placeholders::_3)));
106         }
107     }
108
109     void foundResource(std::shared_ptr<OCResource> resource)
110     {
111         std::cout << "In foundResource" << std::endl;
112         if(resource && resource->uri() == "/q/foo")
113         {
114             {
115                 std::lock_guard<std::mutex> lock(m_resourceLock);
116                 if(m_resource)
117                 {
118                     return;
119                 }
120
121                 m_resource = resource;
122             }
123
124             std::cout << "Found Resource: "<<std::endl;
125             std::cout << "\tHost: "<< resource->host()<<std::endl;
126             std::cout << "\tURI:  "<< resource->uri()<<std::endl;
127
128             // Get the resource types
129             std::cout << "\tList of resource types: " << std::endl;
130             for(auto &resourceTypes : resource->getResourceTypes())
131             {
132                 std::cout << "\t\t" << resourceTypes << std::endl;
133             }
134
135             // Get the resource interfaces
136             std::cout << "\tList of resource interfaces: " << std::endl;
137             for(auto &resourceInterfaces : resource->getResourceInterfaces())
138             {
139                 std::cout << "\t\t" << resourceInterfaces << std::endl;
140             }
141
142             std::cout<<"Doing a get on q/foo."<<std::endl;
143
144             resource->get(QueryParamsMap(),
145                 GetCallback(std::bind(&ClientWorker::getResourceInfo, this,
146                 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
147         }
148     }
149
150 public:
151     ClientWorker(OCConnectivityType ct):m_connectivityType{ct}
152     {}
153
154     void start()
155     {
156         std::ostringstream requestURI;
157         requestURI << OC_MULTICAST_DISCOVERY_URI << "?rt=core.foo";
158
159         std::cout<<"Starting Client find:"<<std::endl;
160         FindCallback f (std::bind(&ClientWorker::foundResource, this, std::placeholders::_1));
161         std::cout<<"result:" <<
162         OCPlatform::findResource("", requestURI.str(), CT_DEFAULT, f)
163         << std::endl;
164
165         std::cout<<"Finding Resource..."<<std::endl;
166
167         {
168             std::unique_lock<std::mutex> lk(m_mutex);
169             m_cv.wait(lk);
170         }
171     }
172 private:
173     std::mutex m_mutex;
174     std::mutex m_resourceLock;
175     std::condition_variable m_cv;
176     std::shared_ptr<OCResource> m_resource;
177     OCConnectivityType m_connectivityType;
178     bool m_isFoo;
179     int m_barCount;
180 };
181
182 struct FooResource
183 {
184     bool m_isFoo;
185     int m_barCount;
186     OCResourceHandle m_resourceHandle;
187     OCRepresentation m_rep;
188
189     FooResource(): m_isFoo(true), m_barCount (0)
190     {
191         m_rep.setUri("/q/foo");
192         m_rep.setValue("isFoo", m_isFoo);
193         m_rep.setValue("barCount", m_barCount);
194     }
195
196     bool createResource()
197     {
198         std::string resourceURI = "/q/foo";
199         std::string resourceTypeName = "core.foo";
200         std::string resourceInterface = DEFAULT_INTERFACE;
201
202         uint8_t resourceProperty = OC_DISCOVERABLE;
203
204         EntityHandler eh(std::bind(&FooResource::entityHandler,
205                     this, std::placeholders::_1));
206         OCStackResult result = OCPlatform::registerResource(m_resourceHandle,
207                 resourceURI, resourceTypeName,
208                                     resourceInterface,
209                                     eh, resourceProperty);
210         if(OC_STACK_OK != result)
211         {
212             std::cout<<"Resource creation unsuccessful"<<std::endl;
213             return false;
214         }
215
216         return true;
217     }
218
219     OCRepresentation get()
220     {
221         m_rep.setValue("isFoo", m_isFoo);
222         m_rep.setValue("barCount", m_barCount);
223
224         return m_rep;
225     }
226
227     void put(OCRepresentation& rep)
228     {
229         rep.getValue("isFoo", m_isFoo);
230         rep.getValue("barCount", m_barCount);
231     }
232
233     OCStackResult sendResponse(std::shared_ptr<OCResourceRequest> pRequest)
234     {
235         auto pResponse = std::make_shared<OC::OCResourceResponse>();
236         pResponse->setRequestHandle(pRequest->getRequestHandle());
237         pResponse->setResourceHandle(pRequest->getResourceHandle());
238         pResponse->setResourceRepresentation(get(), "");
239         pResponse->setErrorCode(200);
240         pResponse->setResponseResult(OC_EH_OK);
241
242         return OCPlatform::sendResponse(pResponse);
243     }
244
245     OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
246     {
247         std::cout<<"\tConsumer Entity Handler:"<<std::endl;
248         OCEntityHandlerResult ehResult = OC_EH_ERROR;
249
250         if(request)
251         {
252             // Note: Most of the handlers are not here, since this is for
253             // demoing client/server co-process existence.
254             // See simpleserver for a more complete example.
255             if(request->getRequestHandlerFlag()  == RequestHandlerFlag::RequestFlag)
256             {
257                 std::cout << "\t\trequestFlag : Request"<<std::endl;
258
259                 if(request->getRequestType() == "GET")
260                 {
261                     std::cout<<"\t\t\trequestType : GET"<<std::endl;
262                     if(OC_STACK_OK == sendResponse(request))
263                     {
264                         ehResult = OC_EH_OK;
265                     }
266                 }
267                 else if (request->getRequestType() == "PUT")
268                 {
269                     std::cout<<"\t\t\trequestType : PUT"<<std::endl;
270
271                     OCRepresentation rep = request->getResourceRepresentation();
272                     put(rep);
273                     if(OC_STACK_OK == sendResponse(request))
274                     {
275                         ehResult = OC_EH_OK;
276                     }
277                 }
278                 else
279                 {
280                     std::cout<<"\t\t\trequestType : UNSUPPORTED: "<<
281                             request->getRequestType()<<std::endl;
282                 }
283             }
284             else
285             {
286                 std::cout <<"\t\trequestFlag : UNSUPPORTED: ";
287
288                 if(request->getRequestHandlerFlag()== RequestHandlerFlag::ObserverFlag)
289                 {
290                     std::cout<<"ObserverFlag"<<std::endl;
291                 }
292             }
293         }
294         else
295         {
296             std::cout << "Request Invalid!"<<std::endl;
297         }
298
299         return ehResult;
300     }
301
302 };
303
304 int main(int argc, char* argv[])
305 {
306     OCConnectivityType connectivityType = CT_ADAPTER_IP;
307
308     if(argc == 2)
309     {
310         try
311         {
312             std::size_t inputValLen;
313             int optionSelected = std::stoi(argv[1], &inputValLen);
314
315             if(inputValLen == strlen(argv[1]))
316             {
317                 if(optionSelected == 0)
318                 {
319                     std::cout << "Using IPv4."<< std::endl;
320                     connectivityType = CT_IP_USE_V4;
321                 }
322                 else if(optionSelected == 1)
323                 {
324                     std::cout << "IPv6 is currently not supported."<< std::endl;
325                     printUsage();
326                     return -1;
327                     //TODO: printUsage to be removed when IPv6 is available.
328                     //connectivityType = CT_IP_USE_V6;
329                 }
330                 else
331                 {
332                     std::cout << "Invalid connectivity type selected. Using default IP" << std::endl;
333                 }
334             }
335             else
336             {
337                 std::cout << "Invalid connectivity type selected. Using default IP" << std::endl;
338             }
339         }
340         catch(std::exception& )
341         {
342             std::cout << "Invalid input argument. Using IP as connectivity type" << std::endl;
343         }
344     }
345     else
346     {
347         printUsage();
348     }
349
350     PlatformConfig cfg {
351         OC::ServiceType::InProc,
352         OC::ModeType::Both,
353         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
354         0,         // Uses randomly available port
355         OC::QualityOfService::LowQos
356     };
357
358     OCPlatform::Configure(cfg);
359     FooResource fooRes;
360
361     try
362     {
363
364         if(!fooRes.createResource())
365         {
366             return -1;
367         }
368
369         ClientWorker cw(connectivityType);
370         cw.start();
371     }
372     catch(OCException& e)
373     {
374         std::cout<< "Exception in main: "<<e.what()<<std::endl;
375     }
376
377     return 0;
378 }
379