Added commentary to the public API referring to new functionality of
[platform/upstream/iotivity.git] / 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 std::map <OCResourceHandle, OC::EntityHandler>  entityHandlerMap;
43 std::map <OCResourceHandle, std::string> resourceUriMap;
44 EntityHandler defaultDeviceEntityHandler = 0;
45
46 void formResourceRequest(OCEntityHandlerFlag flag,
47                          OCEntityHandlerRequest * entityHandlerRequest,
48                          std::shared_ptr<OCResourceRequest> pRequest)
49 {
50     if(flag & OC_INIT_FLAG)
51     {
52         pRequest->setRequestHandlerFlag(OC::RequestHandlerFlag::InitFlag);
53     }
54
55     if(flag & OC_REQUEST_FLAG)
56     {
57         pRequest->setRequestHandlerFlag(OC::RequestHandlerFlag::RequestFlag);
58
59         if(entityHandlerRequest)
60         {
61             if(entityHandlerRequest->query)
62             {
63                 std::string querystr(reinterpret_cast<char*>(entityHandlerRequest->query));
64
65                 OC::Utilities::QueryParamsKeyVal qp = OC::Utilities::getQueryParams(querystr);
66
67                 if(qp.size() > 0)
68                 {
69                     pRequest->setQueryParams(qp);
70                 }
71             }
72             if(entityHandlerRequest->numRcvdVendorSpecificHeaderOptions != 0)
73             {
74                 //Set the header options here.
75                 uint16_t optionID;
76                 std::string optionData;
77                 HeaderOptions headerOptions;
78
79                 for(int i = 0; i < MAX_HEADER_OPTIONS; i++)
80                 {
81                     optionID = entityHandlerRequest->rcvdVendorSpecificHeaderOptions[i].optionID;
82                     optionData = reinterpret_cast<const char*>
83                              (entityHandlerRequest->rcvdVendorSpecificHeaderOptions[i].optionData);
84                     HeaderOption::OCHeaderOption headerOption(optionID, optionData);
85                     headerOptions.push_back(headerOption);
86                 }
87                 pRequest->setHeaderOptions(headerOptions);
88             }
89
90             if(OC_REST_GET == entityHandlerRequest->method)
91             {
92                 // TODO Why strings : "GET"??
93                 pRequest->setRequestType("GET");
94             }
95             else if(OC_REST_PUT == entityHandlerRequest->method)
96             {
97                 pRequest->setRequestType("PUT");
98                 pRequest->setPayload(std::string(reinterpret_cast<const char*>
99                                             (entityHandlerRequest->reqJSONPayload)));
100             }
101             else if(OC_REST_POST == entityHandlerRequest->method)
102             {
103                 pRequest->setRequestType("POST");
104                 pRequest->setPayload(std::string(reinterpret_cast<const char*>
105                                             (entityHandlerRequest->reqJSONPayload)));
106             }
107             else if(OC_REST_DELETE == entityHandlerRequest->method)
108             {
109                 pRequest->setRequestType("DELETE");
110             }
111         }
112     }
113
114     if(flag & OC_OBSERVE_FLAG)
115     {
116         pRequest->setRequestHandlerFlag(
117                    OC::RequestHandlerFlag::RequestFlag | OC::RequestHandlerFlag::ObserverFlag);
118         if(entityHandlerRequest->obsInfo)
119         {
120             OC::ObservationInfo observationInfo;
121             observationInfo.action = (OC::ObserveAction) entityHandlerRequest->obsInfo->action;
122             observationInfo.obsId = entityHandlerRequest->obsInfo->obsId;
123             pRequest->setObservationInfo(observationInfo);
124         }
125     }
126 }
127
128 void processResourceResponse(OCEntityHandlerFlag flag,
129                              OCEntityHandlerRequest * entityHandlerRequest,
130                              std::shared_ptr<OCResourceResponse> pResponse)
131 {
132     if(flag & OC_REQUEST_FLAG)
133     {
134         // TODO we could use const reference
135         std::string payLoad;
136         HeaderOptions serverHeaderOptions;
137
138         if(pResponse)
139         {
140             payLoad = pResponse->getPayload();
141             serverHeaderOptions = pResponse->getHeaderOptions();
142         }
143         else
144         {
145             throw OCException("Response is NULL", OC_STACK_MALFORMED_RESPONSE);
146         }
147
148         if (payLoad.size() < entityHandlerRequest->resJSONPayloadLen)
149         {
150             int i = 0;
151             entityHandlerRequest->numSendVendorSpecificHeaderOptions =
152                         serverHeaderOptions.size();
153             for (auto it=serverHeaderOptions.begin(); it != serverHeaderOptions.end(); ++it)
154             {
155                 entityHandlerRequest->sendVendorSpecificHeaderOptions[i].protocolID = OC_COAP_ID;
156                 entityHandlerRequest->sendVendorSpecificHeaderOptions[i].optionID =
157                         static_cast<uint16_t>(it->getOptionID());
158                 entityHandlerRequest->sendVendorSpecificHeaderOptions[i].optionLength =
159                         (it->getOptionData()).length() + 1;
160                 memcpy(entityHandlerRequest->sendVendorSpecificHeaderOptions[i].optionData,
161                         (it->getOptionData()).c_str(),
162                         (it->getOptionData()).length() + 1);
163                 i++;
164             }
165
166             strncpy((char*)entityHandlerRequest->resJSONPayload,
167                         payLoad.c_str(),
168                         entityHandlerRequest->resJSONPayloadLen);
169         }
170         else
171         {
172             throw OCException("Payload overflow", OC_STACK_MALFORMED_RESPONSE);
173         }
174     }
175
176 }
177
178 OCEntityHandlerResult DefaultEntityHandlerWrapper(OCEntityHandlerFlag flag,
179                                                   OCEntityHandlerRequest * entityHandlerRequest,
180                                                   char* uri)
181 {
182     OCEntityHandlerResult result = OC_EH_ERROR;
183
184     OC::oclog() << "In Default device entity handler wrapper";
185
186     if(NULL == entityHandlerRequest)
187     {
188         oclog() << "Entity handler request is NULL.";
189         return OC_EH_ERROR;
190     }
191
192     auto pRequest = std::make_shared<OC::OCResourceRequest>();
193     auto pResponse = std::make_shared<OC::OCResourceResponse>();
194
195     formResourceRequest(flag, entityHandlerRequest, pRequest);
196
197     pRequest->setResourceUri(std::string(uri));
198
199     if(defaultDeviceEntityHandler)
200     {
201         result = defaultDeviceEntityHandler(pRequest, pResponse);
202     }
203     else
204     {
205         oclog() << "Default device entity handler was not set.";
206         return OC_EH_ERROR;
207     }
208
209     processResourceResponse(flag, entityHandlerRequest, pResponse);
210
211     return result;
212 }
213
214
215 OCEntityHandlerResult EntityHandlerWrapper(OCEntityHandlerFlag flag,
216                                            OCEntityHandlerRequest * entityHandlerRequest)
217 {
218     OCEntityHandlerResult result = OC_EH_ERROR;
219
220     oclog() << "\nIn entity handler wrapper: " << endl;
221
222     if(NULL == entityHandlerRequest)
223     {
224         oclog() << "Entity handler request is NULL."  << endl;
225         return OC_EH_ERROR;
226     }
227
228     auto pRequest = std::make_shared<OC::OCResourceRequest>();
229     auto pResponse = std::make_shared<OC::OCResourceResponse>();
230
231     formResourceRequest(flag, entityHandlerRequest, pRequest);
232
233     // Finding the corresponding URI for a resource handle and set the URI in the request
234     auto resourceUriEntry = resourceUriMap.find(entityHandlerRequest->resource);
235     if(resourceUriEntry != resourceUriMap.end())
236     {
237         pRequest->setResourceUri(resourceUriEntry->second);
238     }
239     else
240     {
241         oclog() << "Resource handle not found; Resource URI not set in request";
242         return OC_EH_ERROR;
243     }
244
245     // Finding the corresponding CPP Application entityHandler for a given resource
246     auto entityHandlerEntry = entityHandlerMap.find(entityHandlerRequest->resource);
247
248     if(entityHandlerEntry != entityHandlerMap.end())
249     {
250         // Call CPP Application Entity Handler
251         if(entityHandlerEntry->second)
252         {
253             result = entityHandlerEntry->second(pRequest, pResponse);
254
255             if(OC_EH_RESOURCE_CREATED == result)
256             {
257                 std::string createdUri = pResponse->getNewResourceUri();
258                 strncpy(reinterpret_cast<char*>(entityHandlerRequest->newResourceUri),
259                         createdUri.c_str(),
260                         createdUri.length() + 1);
261             }
262         }
263         else
264         {
265             oclog() << "C stack should not call again for parent resource\n";
266             return OC_EH_ERROR;
267         }
268     }
269     else
270     {
271         oclog() << "No entity handler found."  << endl;
272         return OC_EH_ERROR;
273     }
274
275     processResourceResponse(flag, entityHandlerRequest, pResponse);
276
277     return result;
278 }
279
280 namespace OC
281 {
282     InProcServerWrapper::InProcServerWrapper(OC::OCPlatform& owner,
283         std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
284      : IServerWrapper(owner),
285        m_csdkLock(csdkLock)
286     {
287         OCMode initType;
288
289         if(cfg.mode == ModeType::Server)
290         {
291             initType = OC_SERVER;
292         }
293         else if (cfg.mode == ModeType::Both)
294         {
295             initType = OC_CLIENT_SERVER;
296         }
297         else
298         {
299             throw InitializeException("Cannot construct a Server when configured as a client",
300                                       OC_STACK_INVALID_PARAM);
301         }
302
303         OCStackResult result = OCInit(cfg.ipAddress.c_str(), cfg.port, initType);
304
305         if(OC_STACK_OK != result)
306         {
307             throw InitializeException("Error Initializing Stack", result);
308         }
309
310         m_threadRun = true;
311         m_processThread = std::thread(&InProcServerWrapper::processFunc, this);
312     }
313
314     void InProcServerWrapper::processFunc()
315     {
316         auto cLock = m_csdkLock.lock();
317         while(cLock && m_threadRun)
318         {
319             OCStackResult result;
320
321             {
322                 std::lock_guard<std::recursive_mutex> lock(*cLock);
323                 result = OCProcess();
324             }
325
326             // ...the value of variable result is simply ignored for now.
327             if(OC_STACK_ERROR == result)
328              ;
329
330             std::this_thread::sleep_for(std::chrono::milliseconds(10));
331         }
332     }
333
334     OCStackResult InProcServerWrapper::registerResource(
335                     OCResourceHandle& resourceHandle,
336                     std::string& resourceURI,
337                     const std::string& resourceTypeName,
338                     const std::string& resourceInterface,
339                     EntityHandler& eHandler,
340                     uint8_t resourceProperties)
341
342     {
343         OCStackResult result = OC_STACK_ERROR;
344
345         auto cLock = m_csdkLock.lock();
346
347         if(cLock)
348         {
349             std::lock_guard<std::recursive_mutex> lock(*cLock);
350
351             if(NULL != eHandler)
352             {
353                 result = OCCreateResource(&resourceHandle, // OCResourceHandle *handle
354                             resourceTypeName.c_str(), // const char * resourceTypeName
355                             resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix this
356                             resourceURI.c_str(), // const char * uri
357                             EntityHandlerWrapper, // OCEntityHandler entityHandler
358                             resourceProperties // uint8_t resourceProperties
359                             );
360             }
361             else
362             {
363                 result = OCCreateResource(&resourceHandle, // OCResourceHandle *handle
364                             resourceTypeName.c_str(), // const char * resourceTypeName
365                             resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix this
366                             resourceURI.c_str(), // const char * uri
367                             NULL, // OCEntityHandler entityHandler
368                             resourceProperties // uint8_t resourceProperties
369                             );
370             }
371
372             if(result != OC_STACK_OK)
373             {
374                 resourceHandle = (OCResourceHandle) 0;
375             }
376             else
377             {
378                 entityHandlerMap[resourceHandle] = eHandler;
379                 resourceUriMap[resourceHandle] = resourceURI;
380             }
381         }
382         else
383         {
384             result = OC_STACK_ERROR;
385         }
386
387         return result;
388     }
389
390     OCStackResult InProcServerWrapper::setDefaultDeviceEntityHandler
391                                         (EntityHandler entityHandler)
392     {
393         OCStackResult result = OC_STACK_ERROR;
394
395         defaultDeviceEntityHandler = entityHandler;
396
397         if(entityHandler)
398         {
399             result = OCSetDefaultDeviceEntityHandler(DefaultEntityHandlerWrapper);
400         }
401         else
402         {
403             // If Null passed we unset
404             result = OCSetDefaultDeviceEntityHandler(NULL);
405         }
406
407         return result;
408     }
409
410     OCStackResult InProcServerWrapper::unregisterResource(const OCResourceHandle& resourceHandle)
411     {
412         auto cLock = m_csdkLock.lock();
413         OCStackResult result = OC_STACK_ERROR;
414
415         if(cLock)
416         {
417             std::lock_guard<std::recursive_mutex> lock(*cLock);
418             result = OCDeleteResource(resourceHandle);
419
420             if(result == OC_STACK_OK)
421             {
422                 resourceUriMap.erase(resourceHandle);
423             }
424             else
425             {
426                 throw OCException("Unregistering resource failed", result);
427             }
428         }
429         else
430         {
431             result = OC_STACK_ERROR;
432         }
433
434         return result;
435     }
436
437     OCStackResult InProcServerWrapper::bindTypeToResource(const OCResourceHandle& resourceHandle,
438                      const std::string& resourceTypeName)
439     {
440         auto cLock = m_csdkLock.lock();
441         OCStackResult result;
442         if(cLock)
443         {
444             std::lock_guard<std::recursive_mutex> lock(*cLock);
445             result = OCBindResourceTypeToResource(resourceHandle, resourceTypeName.c_str());
446         }
447         else
448         {
449             result = OC_STACK_ERROR;
450         }
451
452         if (result != OC_STACK_OK)
453         {
454             throw OCException("Bind Type to resource failed", result);
455         }
456         return result;
457     }
458
459     OCStackResult InProcServerWrapper::bindInterfaceToResource(
460                      const OCResourceHandle& resourceHandle,
461                      const std::string& resourceInterfaceName)
462     {
463         auto cLock = m_csdkLock.lock();
464         OCStackResult result;
465         if(cLock)
466         {
467             std::lock_guard<std::recursive_mutex> lock(*cLock);
468             result = OCBindResourceInterfaceToResource(resourceHandle,
469                         resourceInterfaceName.c_str());
470         }
471         else
472         {
473             result = OC_STACK_ERROR;
474         }
475
476         if (result != OC_STACK_OK)
477         {
478             throw OCException("Bind Interface to resource failed", result);
479         }
480         return result;
481     }
482
483     OCStackResult InProcServerWrapper::startPresence(const unsigned int seconds)
484     {
485         auto cLock = m_csdkLock.lock();
486         OCStackResult result = OC_STACK_ERROR;
487         if(cLock)
488         {
489             std::lock_guard<std::recursive_mutex> lock(*cLock);
490             result = OCStartPresence(seconds);
491         }
492
493         if(result != OC_STACK_OK)
494         {
495             throw OCException("startPresence failed", result);
496         }
497         return result;
498     }
499
500     OCStackResult InProcServerWrapper::stopPresence()
501     {
502         auto cLock = m_csdkLock.lock();
503         OCStackResult result = OC_STACK_ERROR;
504         if(cLock)
505         {
506             std::lock_guard<std::recursive_mutex> lock(*cLock);
507             result = OCStopPresence();
508         }
509
510         if(result != OC_STACK_OK)
511         {
512             throw OCException("stopPresence failed", result);
513         }
514         return result;
515     }
516
517     InProcServerWrapper::~InProcServerWrapper()
518     {
519         if(m_processThread.joinable())
520         {
521             m_threadRun = false;
522             m_processThread.join();
523         }
524
525         OCStop();
526     }
527 }