Changeset for reviewing RI-CA integration changes.
[platform/upstream/iotivity.git] / resource / examples / threadingsample.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 demonstrates : running one server in main thread, another
23 /// server in a separate thread, and running 2 clients in each thread.
24 ///
25
26
27 #include <memory>
28 #include <iostream>
29 #include <stdexcept>
30 #include <condition_variable>
31 #include <map>
32 #include <vector>
33 #include "OCPlatform.h"
34 #include "OCApi.h"
35 using namespace OC;
36
37 static OCConnectivityType connectivityType = OC_WIFI;
38
39 static std::ostringstream requestURI;
40
41 struct FooResource
42 {
43     bool m_isFoo;
44     int m_barCount;
45     std::string m_uri;
46     std::string m_resourceType;
47     OCResourceHandle m_resourceHandle;
48     OCRepresentation m_rep;
49
50     FooResource(std::string uri): m_isFoo(true), m_barCount (0),
51                                     m_uri(uri), m_resourceType("core.foo")
52     {
53         m_rep.setUri(m_uri);
54         m_rep.setValue("isFoo", m_isFoo);
55         m_rep.setValue("barCount", m_barCount);
56     }
57
58     bool createResource()
59     {
60         std::string resourceInterface = DEFAULT_INTERFACE;
61
62         uint8_t resourceProperty = OC_DISCOVERABLE;
63
64         EntityHandler eh(std::bind(&FooResource::entityHandler, this,
65                                     std::placeholders::_1));
66         OCStackResult result = OCPlatform::registerResource(m_resourceHandle, m_uri,
67                                     m_resourceType, resourceInterface, eh, resourceProperty);
68         if(OC_STACK_OK != result)
69         {
70             std::cout<<"Resource creation unsuccessful"<<std::endl;
71             return false;
72         }
73
74         return true;
75     }
76
77     OCRepresentation get()
78     {
79         m_rep.setValue("isFoo", m_isFoo);
80         m_rep.setValue("barCount", m_barCount);
81
82         return m_rep;
83     }
84
85     void put(OCRepresentation& rep)
86     {
87         rep.getValue("isFoo", m_isFoo);
88         rep.getValue("barCount", m_barCount);
89     }
90
91     OCStackResult sendResponse(std::shared_ptr<OCResourceRequest> pRequest)
92     {
93         auto pResponse = std::make_shared<OC::OCResourceResponse>();
94         pResponse->setRequestHandle(pRequest->getRequestHandle());
95         pResponse->setResourceHandle(pRequest->getResourceHandle());
96         pResponse->setResourceRepresentation(get(), "");
97         pResponse->setErrorCode(200);
98         pResponse->setResponseResult(OC_EH_OK);
99
100         return OCPlatform::sendResponse(pResponse);
101     }
102
103     OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
104     {
105         std::cout<<"\tConsumer Entity Handler:"<<std::endl;
106         OCEntityHandlerResult ehResult = OC_EH_ERROR;
107
108         if(request)
109         {
110             // Note: Most of the handlers are not here, since this is for demoing client/server
111             // co-process existence. See simpleserver for a more complete example.
112             if(request->getRequestHandlerFlag()  == RequestHandlerFlag::RequestFlag)
113             {
114                 std::cout << "\t\trequestFlag : Request"<<std::endl;
115
116                 if(request->getRequestType() == "GET")
117                 {
118                     std::cout<<"\t\t\trequestType : GET"<<std::endl;
119                     if(OC_STACK_OK == sendResponse(request))
120                     {
121                         ehResult = OC_EH_OK;
122                     }
123                 }
124                 else if (request->getRequestType() == "PUT")
125                 {
126                     std::cout<<"\t\t\trequestType : PUT"<<std::endl;
127
128                     OCRepresentation rep = request->getResourceRepresentation();
129                     put(rep);
130                     if(OC_STACK_OK == sendResponse(request))
131                     {
132                         ehResult = OC_EH_OK;
133                     }
134                 }
135                 else
136                 {
137                     std::cout<<"\t\t\trequestType : UNSUPPORTED: " <<
138                                 request->getRequestType()<<std::endl;
139                 }
140             }
141             else
142             {
143                 std::cout <<"\t\trequestFlag : UNSUPPORTED: ";
144
145                 if(request->getRequestHandlerFlag()==RequestHandlerFlag::InitFlag)
146                 {
147                     std::cout<<"InitFlag"<<std::endl;
148                 }
149                 else if(request->getRequestHandlerFlag()== RequestHandlerFlag::ObserverFlag)
150                 {
151                     std::cout<<"ObserverFlag"<<std::endl;
152                 }
153             }
154         }
155         else
156         {
157             std::cout << "Request Invalid!"<<std::endl;
158         }
159
160         return ehResult;
161     }
162 };
163
164 void putResourceInfo(const HeaderOptions& headerOptions,
165         const OCRepresentation rep, const OCRepresentation rep2, const int eCode)
166 {
167    bool m_isFoo = false;
168    int m_barCount = 0;
169    std::cout << "In PutResourceInfo" << std::endl;
170
171    std::cout <<"Clientside Put response to get was: "<<std::endl;
172    std::cout <<"ErrorCode: "<<eCode <<std::endl;
173
174    if(eCode == 0)
175    {
176         std::cout<<"Successful Put.  Attributes sent were: "<<std::endl;
177
178         rep.getValue("isFoo", m_isFoo);
179         rep.getValue("barCount", m_barCount);
180
181         std::cout << "\tisFoo: "<< m_isFoo << std::endl;
182         std::cout << "\tbarCount: "<< m_barCount << std::endl;
183
184         std::cout<<"Actual New values are: "<<std::endl;
185
186         rep.getValue("isFoo", m_isFoo);
187         rep.getValue("barCount", m_barCount);
188
189         std::cout << "\tisFoo: "<< m_isFoo << std::endl;
190         std::cout << "\tbarCount: "<< m_barCount << std::endl;
191    }
192 }
193
194 void getResourceInfo(std::shared_ptr<OCResource> resource, const HeaderOptions& headerOptions,
195             const OCRepresentation rep,
196             const int eCode)
197 {
198     bool m_isFoo = false;
199     int m_barCount = 0;
200     std::cout << "In getResourceInfo" << std::endl;
201
202     std::cout<<"Clientside response to get was: "<<std::endl;
203     std::cout<<"Error Code: "<<eCode<<std::endl;
204
205     if(eCode == 0)
206     {
207         std::cout <<"Successful Get.  Attributes are: "<<std::endl;
208
209         rep.getValue("isFoo", m_isFoo);
210         rep.getValue("barCount", m_barCount);
211
212         std::cout << "\tisFoo: "<< m_isFoo << std::endl;
213         std::cout << "\tbarCount: "<< m_barCount << std::endl;
214
215         std::cout << "Doing a put on q/foo" <<std::endl;
216         OCRepresentation rep2(rep);
217         m_isFoo = false;
218         m_barCount = 211;
219
220         rep2.setValue("isFoo", m_isFoo);
221         rep2.setValue("barCount", m_barCount);
222
223         resource->put(rep2, QueryParamsMap(),
224             PutCallback(std::bind(putResourceInfo, std::placeholders::_1,
225                  rep2, std::placeholders::_2, std::placeholders::_3)));
226     }
227 }
228
229 void printResourceInfo(std::shared_ptr<OCResource> resource)
230 {
231         std::cout << "Found Resource: "<<std::endl;
232         std::cout << "\tHost: "<< resource->host()<<std::endl;
233         std::cout << "\tURI:  "<< resource->uri()<<std::endl;
234
235         // Get the resource types
236         std::cout << "\tList of resource types: " << std::endl;
237         for(auto &resourceTypes : resource->getResourceTypes())
238         {
239             std::cout << "\t\t" << resourceTypes << std::endl;
240         }
241
242         // Get the resource interfaces
243         std::cout << "\tList of resource interfaces: " << std::endl;
244         for(auto &resourceInterfaces : resource->getResourceInterfaces())
245         {
246             std::cout << "\t\t" << resourceInterfaces << std::endl;
247         }
248 }
249
250 void foundResource2(std::shared_ptr<OCResource> resource)
251 {
252     std::cout << "In foundResource2:" << std::endl;
253
254     if(resource && resource->uri() == "/q/foo2")
255     {
256         printResourceInfo(resource);
257
258         std::cout<<"Doing a get on q/foo."<<std::endl;
259
260         resource->get(QueryParamsMap(),
261             GetCallback(std::bind(getResourceInfo, resource,
262             std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
263     }
264     else
265     {
266         std::cout << "foundResource2: Ignoring the resource which doesn't have uri /q/foo2\n";
267     }
268 }
269
270 void foundResource1(std::shared_ptr<OCResource> resource)
271 {
272     std::cout << "In foundResource1:" << std::endl;
273     if(resource && resource->uri() == "/q/foo1")
274     {
275         printResourceInfo(resource);
276     }
277     else
278     {
279         std::cout << "foundResource1: Ignoring the resource which doesn't have uri /q/foo1\n";
280     }
281 }
282
283 void client1()
284 {
285     std::cout << "in client1\n";
286     std::cout<<"result1:" << OCPlatform::findResource("", requestURI.str(),
287             connectivityType, foundResource1)<< std::endl;
288
289     // A condition variable will free the mutex it is given, then do a non-
290     // intensive block until 'notify' is called on it.  In this case, since we
291     // don't ever call cv.notify, this should be a non-processor intensive version
292     // of while(true);
293     std::mutex blocker;
294     std::condition_variable cv;
295     std::unique_lock<std::mutex> lock(blocker);
296     cv.wait(lock);
297 }
298
299 void client2()
300 {
301     std::cout << "in client2\n";
302     std::cout<<"result2:" << OCPlatform::findResource("",
303                 requestURI.str(),
304                 connectivityType, foundResource2)<< std::endl;
305
306     // A condition variable will free the mutex it is given, then do a non-
307     // intensive block until 'notify' is called on it.  In this case, since we
308     // don't ever call cv.notify, this should be a non-processor intensive version
309     // of while(true);
310     std::mutex blocker;
311     std::condition_variable cv;
312     std::unique_lock<std::mutex> lock(blocker);
313     cv.wait(lock);
314 }
315
316 void server()
317 {
318     FooResource fooRes("/q/foo2");
319
320     if(!fooRes.createResource())
321     {
322         return;
323     }
324
325     // A condition variable will free the mutex it is given, then do a non-
326     // intensive block until 'notify' is called on it.  In this case, since we
327     // don't ever call cv.notify, this should be a non-processor intensive version
328     // of while(true);
329     std::mutex blocker;
330     std::condition_variable cv;
331     std::unique_lock<std::mutex> lock(blocker);
332     cv.wait(lock);
333 }
334
335 int main(int argc, char* argv[])
336 {
337
338     if(argc == 2)
339     {
340         try
341         {
342             std::size_t inputValLen;
343             int optionSelected = std::stoi(argv[1], &inputValLen);
344
345             if(inputValLen == strlen(argv[1]))
346             {
347                 if(optionSelected == 0)
348                 {
349                     connectivityType = OC_ETHERNET;
350                 }
351                 else if(optionSelected == 1)
352                 {
353                     connectivityType = OC_WIFI;
354                 }
355                 else
356                 {
357                     std::cout << "Invalid connectivity type selected. Using default WIFI"
358                         << std::endl;
359                 }
360             }
361             else
362             {
363                 std::cout << "Invalid connectivity type selected. Using default WIFI" << std::endl;
364             }
365         }
366         catch(std::exception& e)
367         {
368             std::cout << "Invalid input argument. Using WIFI as connectivity type" << std::endl;
369         }
370     }
371     else
372     {
373         std::cout<< "Usage threadingsample <ConnectivityType(0|1)>" << std::endl;
374         std::cout<<"ConnectivityType: Default WIFI" << std::endl;
375         std::cout << "   ConnectivityType : 0 - ETHERNET" << std::endl;
376         std::cout << "   ConnectivityType : 1 - WIFI" << std::endl;
377     }
378
379     requestURI << OC_WELL_KNOWN_QUERY << "?rt=core.foo";
380
381     PlatformConfig cfg {
382         OC::ServiceType::InProc,
383         OC::ModeType::Both,
384         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
385         0,         // Uses randomly available port
386         OC::QualityOfService::LowQos
387     };
388
389     OCPlatform::Configure(cfg);
390
391     try
392     {
393         // main thread running as server
394         FooResource fooRes("/q/foo1");
395         if(!fooRes.createResource())
396         {
397             return -1;
398         }
399
400         // Start a server in a seperate thread
401         std::thread t(server);
402         t.detach();
403
404         sleep(10);
405
406         // Start each client in a seperate thread
407         std::thread t1(client1);
408         t1.detach();
409
410         // Start each client in a seperate thread
411         std::thread t2(client2);
412         t2.detach();
413
414         // A condition variable will free the mutex it is given, then do a non-
415         // intensive block until 'notify' is called on it.  In this case, since we
416         // don't ever call cv.notify, this should be a non-processor intensive version
417         // of while(true);
418         std::mutex blocker;
419         std::condition_variable cv;
420         std::unique_lock<std::mutex> lock(blocker);
421         cv.wait(lock);
422     }
423     catch(OCException& e)
424     {
425         std::cout<< "Exception in main: "<<e.what()<<std::endl;
426     }
427
428     return 0;
429 }
430