Repaired a number of issues discovered while doing a code-review
[platform/upstream/iotivity.git] / resource / src / InProcServerWrapper.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 <random>
22 #include <cstring>
23 #include <cstdlib>
24 #include <iostream>
25 #include <algorithm>
26 #include <map>
27 #include <sstream>
28 #include <string>
29
30 #include <InProcServerWrapper.h>
31 #include <InitializeException.h>
32 #include <OCResourceRequest.h>
33 #include <OCResourceResponse.h>
34 #include <ocstack.h>
35 #include <OCApi.h>
36 #include <OCPlatform.h>
37 #include <OCUtilities.h>
38
39 using namespace std;
40 using namespace OC;
41
42 namespace OC
43 {
44     namespace details
45     {
46         std::mutex serverWrapperLock;
47         std::map <OCResourceHandle, OC::EntityHandler>  entityHandlerMap;
48         std::map <OCResourceHandle, std::string> resourceUriMap;
49         EntityHandler defaultDeviceEntityHandler = 0;
50     }
51 }
52
53 void formResourceRequest(OCEntityHandlerFlag flag,
54                          OCEntityHandlerRequest * entityHandlerRequest,
55                          std::shared_ptr<OCResourceRequest> pRequest)
56 {
57     if(pRequest && entityHandlerRequest)
58     {
59         pRequest->setRequestHandle(entityHandlerRequest->requestHandle);
60         pRequest->setResourceHandle(entityHandlerRequest->resource);
61     }
62
63     if(flag & OC_INIT_FLAG)
64     {
65         pRequest->setRequestHandlerFlag(OC::RequestHandlerFlag::InitFlag);
66     }
67
68     if(flag & OC_REQUEST_FLAG)
69     {
70         pRequest->setRequestHandlerFlag(OC::RequestHandlerFlag::RequestFlag);
71
72         if(entityHandlerRequest)
73         {
74             if(entityHandlerRequest->query)
75             {
76                 std::string querystr(reinterpret_cast<char*>(entityHandlerRequest->query));
77
78                 OC::Utilities::QueryParamsKeyVal qp = OC::Utilities::getQueryParams(querystr);
79
80                 if(qp.size() > 0)
81                 {
82                     pRequest->setQueryParams(qp);
83                 }
84             }
85             if(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions != 0)
86             {
87                 //Set the header options here.
88                 uint16_t optionID;
89                 std::string optionData;
90                 HeaderOptions headerOptions;
91
92                 for(int i = 0;
93                     i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions;
94                     i++)
95                 {
96                     optionID = entityHandlerRequest->rcvdVendorSpecificHeaderOptions[i].optionID;
97                     optionData = reinterpret_cast<const char*>
98                              (entityHandlerRequest->rcvdVendorSpecificHeaderOptions[i].optionData);
99                     HeaderOption::OCHeaderOption headerOption(optionID, optionData);
100                     headerOptions.push_back(headerOption);
101                 }
102                 pRequest->setHeaderOptions(headerOptions);
103             }
104
105             if(OC_REST_GET == entityHandlerRequest->method)
106             {
107                 pRequest->setRequestType(OC::PlatformCommands::GET);
108             }
109             else if(OC_REST_PUT == entityHandlerRequest->method)
110             {
111                 pRequest->setRequestType(OC::PlatformCommands::PUT);
112                 pRequest->setPayload(std::string(reinterpret_cast<const char*>
113                                             (entityHandlerRequest->reqJSONPayload)));
114             }
115             else if(OC_REST_POST == entityHandlerRequest->method)
116             {
117                 pRequest->setRequestType(OC::PlatformCommands::POST);
118                 pRequest->setPayload(std::string(reinterpret_cast<const char*>
119                                             (entityHandlerRequest->reqJSONPayload)));
120             }
121             else if(OC_REST_DELETE == entityHandlerRequest->method)
122             {
123                 pRequest->setRequestType(OC::PlatformCommands::DELETE);
124             }
125         }
126     }
127
128     if(flag & OC_OBSERVE_FLAG)
129     {
130         pRequest->setRequestHandlerFlag(
131                    OC::RequestHandlerFlag::RequestFlag | OC::RequestHandlerFlag::ObserverFlag);
132
133         if(entityHandlerRequest)
134         {
135             OC::ObservationInfo observationInfo;
136             observationInfo.action = (OC::ObserveAction) entityHandlerRequest->obsInfo.action;
137             observationInfo.obsId = entityHandlerRequest->obsInfo.obsId;
138             pRequest->setObservationInfo(observationInfo);
139         }
140     }
141 }
142
143 OCEntityHandlerResult DefaultEntityHandlerWrapper(OCEntityHandlerFlag flag,
144                                                   OCEntityHandlerRequest * entityHandlerRequest,
145                                                   char* uri)
146 {
147     OCEntityHandlerResult result = OC_EH_ERROR;
148
149     OC::oclog() << "In Default device entity handler wrapper";
150
151     if(NULL == entityHandlerRequest)
152     {
153         oclog() << "Entity handler request is NULL.";
154         return OC_EH_ERROR;
155     }
156
157     auto pRequest = std::make_shared<OC::OCResourceRequest>();
158
159     formResourceRequest(flag, entityHandlerRequest, pRequest);
160
161     pRequest->setResourceUri(std::string(uri));
162
163     EntityHandler defHandler;
164     {
165         std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
166         defHandler = OC::details::defaultDeviceEntityHandler;
167     }
168
169     if(defHandler)
170     {
171         result = defHandler(pRequest);
172     }
173     else
174     {
175         oclog() << "Default device entity handler was not set.";
176         return OC_EH_ERROR;
177     }
178
179     return result;
180 }
181
182
183 OCEntityHandlerResult EntityHandlerWrapper(OCEntityHandlerFlag flag,
184                                            OCEntityHandlerRequest * entityHandlerRequest)
185 {
186     OCEntityHandlerResult result = OC_EH_ERROR;
187
188     oclog() << "\nIn entity handler wrapper: " << endl;
189
190     if(NULL == entityHandlerRequest)
191     {
192         oclog() << "Entity handler request is NULL."  << endl;
193         return OC_EH_ERROR;
194     }
195
196     auto pRequest = std::make_shared<OC::OCResourceRequest>();
197
198     formResourceRequest(flag, entityHandlerRequest, pRequest);
199
200     std::map <OCResourceHandle, std::string>::iterator resourceUriEntry;
201     std::map <OCResourceHandle, std::string>::iterator resourceUriEnd;
202     {
203         std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
204         resourceUriEntry = OC::details::resourceUriMap.find(entityHandlerRequest->resource);
205         resourceUriEnd = OC::details::resourceUriMap.end();
206     }
207     // Finding the corresponding URI for a resource handle and set the URI in the request
208     if(resourceUriEntry != resourceUriEnd)
209     {
210         pRequest->setResourceUri(resourceUriEntry->second);
211     }
212     else
213     {
214         oclog() << "Resource handle not found; Resource URI not set in request";
215         return OC_EH_ERROR;
216     }
217
218     std::map <OCResourceHandle, OC::EntityHandler>::iterator entityHandlerEntry;
219     std::map <OCResourceHandle, OC::EntityHandler>::iterator entityHandlerEnd;
220     {
221         // Finding the corresponding CPP Application entityHandler for a given resource
222         std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
223         entityHandlerEntry = OC::details::entityHandlerMap.find(entityHandlerRequest->resource);
224         entityHandlerEnd = OC::details::entityHandlerMap.end();
225     }
226
227     if(entityHandlerEntry != entityHandlerEnd)
228     {
229         // Call CPP Application Entity Handler
230         if(entityHandlerEntry->second)
231         {
232             result = entityHandlerEntry->second(pRequest);
233         }
234         else
235         {
236             oclog() << "C stack should not call again for parent resource\n";
237             return OC_EH_ERROR;
238         }
239     }
240     else
241     {
242         oclog() << "No entity handler found."  << endl;
243         return OC_EH_ERROR;
244     }
245
246     return result;
247 }
248
249 namespace OC
250 {
251     InProcServerWrapper::InProcServerWrapper(
252         std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
253      : m_csdkLock(csdkLock)
254     {
255         OCMode initType;
256
257         if(cfg.mode == ModeType::Server)
258         {
259             initType = OC_SERVER;
260         }
261         else if (cfg.mode == ModeType::Both)
262         {
263             initType = OC_CLIENT_SERVER;
264         }
265         else
266         {
267             throw InitializeException(OC::InitException::NOT_CONFIGURED_AS_SERVER,
268                                       OC_STACK_INVALID_PARAM);
269         }
270
271         OCStackResult result = OCInit(cfg.ipAddress.c_str(), cfg.port, initType);
272
273         if(OC_STACK_OK != result)
274         {
275             throw InitializeException(OC::InitException::STACK_INIT_ERROR, result);
276         }
277
278         m_threadRun = true;
279         m_processThread = std::thread(&InProcServerWrapper::processFunc, this);
280     }
281
282     void InProcServerWrapper::processFunc()
283     {
284         auto cLock = m_csdkLock.lock();
285         while(cLock && m_threadRun)
286         {
287             OCStackResult result;
288
289             {
290                 std::lock_guard<std::recursive_mutex> lock(*cLock);
291                 result = OCProcess();
292             }
293
294             // ...the value of variable result is simply ignored for now.
295             if(OC_STACK_ERROR == result)
296              ;
297
298             std::this_thread::sleep_for(std::chrono::milliseconds(10));
299         }
300     }
301
302     OCStackResult InProcServerWrapper::registerDeviceInfo(const OCDeviceInfo deviceInfo)
303     {
304         auto cLock = m_csdkLock.lock();
305         OCStackResult result = OC_STACK_ERROR;
306         if(cLock)
307         {
308             std::lock_guard<std::recursive_mutex> lock(*cLock);
309             result = OCSetDeviceInfo(deviceInfo);
310         }
311         return result;
312     }
313
314     OCStackResult InProcServerWrapper::registerResource(
315                     OCResourceHandle& resourceHandle,
316                     std::string& resourceURI,
317                     const std::string& resourceTypeName,
318                     const std::string& resourceInterface,
319                     EntityHandler& eHandler,
320                     uint8_t resourceProperties)
321
322     {
323         OCStackResult result = OC_STACK_ERROR;
324
325         auto cLock = m_csdkLock.lock();
326
327         if(cLock)
328         {
329             std::lock_guard<std::recursive_mutex> lock(*cLock);
330
331             if(NULL != eHandler)
332             {
333                 result = OCCreateResource(&resourceHandle, // OCResourceHandle *handle
334                             resourceTypeName.c_str(), // const char * resourceTypeName
335                             resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix this
336                             resourceURI.c_str(), // const char * uri
337                             EntityHandlerWrapper, // OCEntityHandler entityHandler
338                             resourceProperties // uint8_t resourceProperties
339                             );
340             }
341             else
342             {
343                 result = OCCreateResource(&resourceHandle, // OCResourceHandle *handle
344                             resourceTypeName.c_str(), // const char * resourceTypeName
345                             resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix this
346                             resourceURI.c_str(), // const char * uri
347                             NULL, // OCEntityHandler entityHandler
348                             resourceProperties // uint8_t resourceProperties
349                             );
350             }
351
352             if(result != OC_STACK_OK)
353             {
354                 resourceHandle = (OCResourceHandle) 0;
355             }
356             else
357             {
358                 std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
359                 OC::details::entityHandlerMap[resourceHandle] = eHandler;
360                 OC::details::resourceUriMap[resourceHandle] = resourceURI;
361             }
362         }
363         else
364         {
365             result = OC_STACK_ERROR;
366         }
367
368         return result;
369     }
370
371     OCStackResult InProcServerWrapper::registerResourceWithHost(
372                     OCResourceHandle& resourceHandle,
373                     std::string& resourceHOST,
374                     std::string& resourceURI,
375                     const std::string& resourceTypeName,
376                     const std::string& resourceInterface,
377                     EntityHandler& eHandler,
378                     uint8_t resourceProperties)
379
380     {
381         OCStackResult result = OC_STACK_ERROR;
382
383         auto cLock = m_csdkLock.lock();
384
385         if (cLock)
386         {
387             std::lock_guard < std::recursive_mutex > lock(*cLock);
388
389             if (NULL != eHandler)
390             {
391                 result = OCCreateResourceWithHost(&resourceHandle, // OCResourceHandle *handle
392                         resourceTypeName.c_str(), // const char * resourceTypeName
393                         resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix
394                         resourceHOST.c_str(), // const char * host
395                         (resourceHOST + resourceURI).c_str(), // const char * uri
396                         EntityHandlerWrapper, // OCEntityHandler entityHandler
397                         resourceProperties // uint8_t resourceProperties
398                         );
399             }
400             else
401             {
402                 result = OCCreateResourceWithHost(&resourceHandle, // OCResourceHandle *handle
403                         resourceTypeName.c_str(), // const char * resourceTypeName
404                         resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix
405                         resourceHOST.c_str(), // const char * host
406                         (resourceHOST + resourceURI).c_str(), // const char * uri
407                         nullptr, // OCEntityHandler entityHandler
408                         resourceProperties // uint8_t resourceProperties
409                         );
410             }
411
412             if (result != OC_STACK_OK)
413             {
414                 resourceHandle = nullptr;
415             }
416             else
417             {
418                 std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
419                 OC::details::entityHandlerMap[resourceHandle] = eHandler;
420                 OC::details::resourceUriMap[resourceHandle] = resourceURI;
421             }
422         }
423         else
424         {
425             result = OC_STACK_ERROR;
426         }
427
428         return result;
429     }
430
431     OCStackResult InProcServerWrapper::setDefaultDeviceEntityHandler
432                                         (EntityHandler entityHandler)
433     {
434         OCStackResult result = OC_STACK_ERROR;
435
436         {
437             std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
438             OC::details::defaultDeviceEntityHandler = entityHandler;
439         }
440
441         if(entityHandler)
442         {
443             result = OCSetDefaultDeviceEntityHandler(DefaultEntityHandlerWrapper);
444         }
445         else
446         {
447             // If Null passed we unset
448             result = OCSetDefaultDeviceEntityHandler(NULL);
449         }
450
451         return result;
452     }
453
454     OCStackResult InProcServerWrapper::unregisterResource(const OCResourceHandle& resourceHandle)
455     {
456         auto cLock = m_csdkLock.lock();
457         OCStackResult result = OC_STACK_ERROR;
458
459         if(cLock)
460         {
461             std::lock_guard<std::recursive_mutex> lock(*cLock);
462             result = OCDeleteResource(resourceHandle);
463
464             if(result == OC_STACK_OK)
465             {
466                 std::lock_guard<std::mutex> lock(OC::details::serverWrapperLock);
467                 OC::details::resourceUriMap.erase(resourceHandle);
468             }
469             else
470             {
471                 throw OCException(OC::Exception::RESOURCE_UNREG_FAILED, result);
472             }
473         }
474         else
475         {
476             result = OC_STACK_ERROR;
477         }
478
479         return result;
480     }
481
482     OCStackResult InProcServerWrapper::bindTypeToResource(const OCResourceHandle& resourceHandle,
483                      const std::string& resourceTypeName)
484     {
485         auto cLock = m_csdkLock.lock();
486         OCStackResult result;
487         if(cLock)
488         {
489             std::lock_guard<std::recursive_mutex> lock(*cLock);
490             result = OCBindResourceTypeToResource(resourceHandle, resourceTypeName.c_str());
491         }
492         else
493         {
494             result = OC_STACK_ERROR;
495         }
496
497         if (result != OC_STACK_OK)
498         {
499             throw OCException(OC::Exception::BIND_TYPE_FAILED, result);
500         }
501         return result;
502     }
503
504     OCStackResult InProcServerWrapper::bindInterfaceToResource(
505                      const OCResourceHandle& resourceHandle,
506                      const std::string& resourceInterfaceName)
507     {
508         auto cLock = m_csdkLock.lock();
509         OCStackResult result;
510         if(cLock)
511         {
512             std::lock_guard<std::recursive_mutex> lock(*cLock);
513             result = OCBindResourceInterfaceToResource(resourceHandle,
514                         resourceInterfaceName.c_str());
515         }
516         else
517         {
518             result = OC_STACK_ERROR;
519         }
520
521         if (result != OC_STACK_OK)
522         {
523             throw OCException(OC::Exception::BIND_INTERFACE_FAILED, result);
524         }
525         return result;
526     }
527
528     OCStackResult InProcServerWrapper::startPresence(const unsigned int seconds)
529     {
530         auto cLock = m_csdkLock.lock();
531         OCStackResult result = OC_STACK_ERROR;
532         if(cLock)
533         {
534             std::lock_guard<std::recursive_mutex> lock(*cLock);
535             result = OCStartPresence(seconds);
536         }
537
538         if(result != OC_STACK_OK)
539         {
540             throw OCException(OC::Exception::START_PRESENCE_FAILED, result);
541         }
542         return result;
543     }
544
545     OCStackResult InProcServerWrapper::stopPresence()
546     {
547         auto cLock = m_csdkLock.lock();
548         OCStackResult result = OC_STACK_ERROR;
549         if(cLock)
550         {
551             std::lock_guard<std::recursive_mutex> lock(*cLock);
552             result = OCStopPresence();
553         }
554
555         if(result != OC_STACK_OK)
556         {
557             throw OCException(OC::Exception::END_PRESENCE_FAILED, result);
558         }
559         return result;
560     }
561
562     OCStackResult InProcServerWrapper::sendResponse(
563         const std::shared_ptr<OCResourceResponse> pResponse)
564     {
565         auto cLock = m_csdkLock.lock();
566         OCStackResult result = OC_STACK_ERROR;
567
568         if(!pResponse)
569         {
570             result = OC_STACK_MALFORMED_RESPONSE;
571             throw OCException(OC::Exception::STR_NULL_RESPONSE, OC_STACK_MALFORMED_RESPONSE);
572         }
573         else
574         {
575             OCEntityHandlerResponse response;
576             std::string payLoad;
577             HeaderOptions serverHeaderOptions;
578
579             payLoad = pResponse->getPayload();
580             serverHeaderOptions = pResponse->getHeaderOptions();
581
582             response.requestHandle = pResponse->getRequestHandle();
583             response.resourceHandle = pResponse->getResourceHandle();
584             response.ehResult = pResponse->getResponseResult();
585             response.payload = (unsigned char*) payLoad.c_str();
586             response.payloadSize = payLoad.length() + 1;
587             response.persistentBufferFlag = 0;
588
589             response.numSendVendorSpecificHeaderOptions = serverHeaderOptions.size();
590             int i = 0;
591             for (auto it=serverHeaderOptions.begin(); it != serverHeaderOptions.end(); ++it)
592             {
593                 response.sendVendorSpecificHeaderOptions[i].protocolID = OC_COAP_ID;
594                 response.sendVendorSpecificHeaderOptions[i].optionID =
595                     static_cast<uint16_t>(it->getOptionID());
596                 response.sendVendorSpecificHeaderOptions[i].optionLength =
597                     (it->getOptionData()).length() + 1;
598                 memcpy(response.sendVendorSpecificHeaderOptions[i].optionData,
599                     (it->getOptionData()).c_str(),
600                     (it->getOptionData()).length() + 1);
601                 i++;
602             }
603
604             if(OC_EH_RESOURCE_CREATED == response.ehResult)
605             {
606                 std::string createdUri = pResponse->getNewResourceUri();
607                 strncpy(reinterpret_cast<char*>(response.resourceUri),
608                         createdUri.c_str(),
609                         createdUri.length() + 1);
610             }
611
612             if(cLock)
613             {
614                 std::lock_guard<std::recursive_mutex> lock(*cLock);
615                 result = OCDoResponse(&response);
616             }
617             else
618             {
619                 result = OC_STACK_ERROR;
620             }
621
622             if(result != OC_STACK_OK)
623             {
624                 oclog() << "Error sending response\n";
625             }
626             return result;
627         }
628     }
629
630     InProcServerWrapper::~InProcServerWrapper()
631     {
632         if(m_processThread.joinable())
633         {
634             m_threadRun = false;
635             m_processThread.join();
636         }
637
638         OCStop();
639     }
640 }