1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  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,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "sal/config.h"
25 
26 #include <list>
27 #include <vector>
28 
29 #include "boost/noncopyable.hpp"
30 #include "com/sun/star/bridge/XInstanceProvider.hpp"
31 #include "cppuhelper/exc_hlp.hxx"
32 #include "rtl/byteseq.hxx"
33 #include "rtl/ref.hxx"
34 #include "rtl/ustring.hxx"
35 #include "sal/types.h"
36 #include "typelib/typedescription.hxx"
37 #include "uno/dispatcher.hxx"
38 
39 #include "binaryany.hxx"
40 #include "bridge.hxx"
41 #include "currentcontext.hxx"
42 #include "incomingrequest.hxx"
43 #include "specialfunctionids.hxx"
44 
45 namespace binaryurp {
46 
47 namespace {
48 
49 namespace css = com::sun::star;
50 
51 }
52 
IncomingRequest(rtl::Reference<Bridge> const & bridge,rtl::ByteSequence const & tid,rtl::OUString const & oid,css::uno::UnoInterfaceReference const & object,css::uno::TypeDescription const & type,sal_uInt16 functionId,bool synchronous,css::uno::TypeDescription const & member,bool setter,std::vector<BinaryAny> const & inArguments,bool currentContextMode,css::uno::UnoInterfaceReference const & currentContext)53 IncomingRequest::IncomingRequest(
54     rtl::Reference< Bridge > const & bridge, rtl::ByteSequence const & tid,
55     rtl::OUString const & oid, css::uno::UnoInterfaceReference const & object,
56     css::uno::TypeDescription const & type, sal_uInt16 functionId,
57     bool synchronous, css::uno::TypeDescription const & member, bool setter,
58     std::vector< BinaryAny > const & inArguments, bool currentContextMode,
59     css::uno::UnoInterfaceReference const & currentContext):
60     bridge_(bridge), tid_(tid), oid_(oid), object_(object), type_(type),
61     functionId_(functionId), synchronous_(synchronous), member_(member),
62     setter_(setter), inArguments_(inArguments),
63     currentContextMode_(currentContextMode), currentContext_(currentContext)
64 {
65     OSL_ASSERT(bridge.is() && member.is() && member.get()->bComplete);
66 }
67 
~IncomingRequest()68 IncomingRequest::~IncomingRequest() {}
69 
execute() const70 void IncomingRequest::execute() const {
71     BinaryAny ret;
72     std::vector< BinaryAny > outArgs;
73     bool isExc;
74     try {
75         bool resetCc = false;
76         css::uno::UnoInterfaceReference oldCc;
77         if (currentContextMode_) {
78             oldCc = current_context::get();
79             current_context::set(currentContext_);
80             resetCc = true;
81         }
82         try {
83             try {
84                 isExc = !execute_throw(&ret, &outArgs);
85             } catch (std::exception & e) {
86                 throw css::uno::RuntimeException(
87                     (rtl::OUString(
88                         RTL_CONSTASCII_USTRINGPARAM("caught C++ exception: ")) +
89                      rtl::OStringToOUString(
90                          rtl::OString(e.what()), RTL_TEXTENCODING_ASCII_US)),
91                     css::uno::Reference< css::uno::XInterface >());
92                     // best-effort string conversion
93             }
94         } catch (css::uno::RuntimeException &) {
95             css::uno::Any exc(cppu::getCaughtException());
96             ret = bridge_->mapCppToBinaryAny(exc);
97             isExc = true;
98         }
99         if (resetCc) {
100             current_context::set(oldCc);
101         }
102     } catch (css::uno::RuntimeException &) {
103         css::uno::Any exc(cppu::getCaughtException());
104         ret = bridge_->mapCppToBinaryAny(exc);
105         isExc = true;
106     }
107     if (synchronous_) {
108         bridge_->decrementActiveCalls();
109         try {
110             bridge_->getWriter()->queueReply(
111                 tid_, member_, setter_, isExc, ret, outArgs, false);
112             return;
113         } catch (css::uno::RuntimeException & e) {
114             OSL_TRACE(
115                 OSL_LOG_PREFIX "caught UNO runtime exception '%s'",
116                 (rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).
117                  getStr()));
118         } catch (std::exception & e) {
119             OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
120         }
121         bridge_->terminate();
122     } else {
123         if (isExc) {
124             OSL_TRACE(OSL_LOG_PREFIX "oneway method raised exception");
125         }
126         bridge_->decrementCalls();
127     }
128 }
129 
execute_throw(BinaryAny * returnValue,std::vector<BinaryAny> * outArguments) const130 bool IncomingRequest::execute_throw(
131     BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) const
132 {
133     OSL_ASSERT(
134         returnValue != 0 &&
135         returnValue->getType().equals(
136             css::uno::TypeDescription(
137                 cppu::UnoType< cppu::UnoVoidType >::get())) &&
138         outArguments != 0 && outArguments->empty());
139     bool isExc = false;
140     switch (functionId_) {
141     case SPECIAL_FUNCTION_ID_RESERVED:
142         OSL_ASSERT(false); // this cannot happen
143         break;
144     case SPECIAL_FUNCTION_ID_RELEASE:
145         bridge_->releaseStub(oid_, type_);
146         break;
147     case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
148         if (!object_.is()) {
149             css::uno::Reference< css::uno::XInterface > ifc;
150             css::uno::Reference< css::bridge::XInstanceProvider > prov(
151                 bridge_->getProvider());
152             if (prov.is()) {
153                 try {
154                     ifc = prov->getInstance(oid_);
155                 } catch (css::container::NoSuchElementException & e) {
156                     OSL_TRACE(
157                         (OSL_LOG_PREFIX "initial element '%s':"
158                          " NoSuchElementException '%s'"),
159                         (rtl::OUStringToOString(oid_, RTL_TEXTENCODING_UTF8).
160                          getStr()),
161                         (rtl::OUStringToOString(
162                             e.Message, RTL_TEXTENCODING_UTF8).
163                          getStr()));
164                 }
165             }
166             if (ifc.is()) {
167                 css::uno::UnoInterfaceReference unoIfc(
168                     static_cast< uno_Interface * >(
169                         bridge_->getCppToBinaryMapping().mapInterface(
170                             ifc.get(),
171                             (css::uno::TypeDescription(
172                                 cppu::UnoType<
173                                     css::uno::Reference<
174                                         css::uno::XInterface > >::get()).
175                              get()))),
176                     SAL_NO_ACQUIRE);
177                 *returnValue = BinaryAny(
178                     css::uno::TypeDescription(
179                         cppu::UnoType<
180                             css::uno::Reference<
181                                 css::uno::XInterface > >::get()),
182                     &unoIfc.m_pUnoI);
183             }
184             break;
185         }
186         // fall through
187     default:
188         {
189             OSL_ASSERT(object_.is());
190             css::uno::TypeDescription retType;
191             std::list< std::vector< char > > outBufs;
192             std::vector< void * > args;
193             switch (member_.get()->eTypeClass) {
194             case typelib_TypeClass_INTERFACE_ATTRIBUTE:
195                 {
196                     css::uno::TypeDescription t(
197                         reinterpret_cast<
198                             typelib_InterfaceAttributeTypeDescription * >(
199                                 member_.get())->
200                         pAttributeTypeRef);
201                     if (setter_) {
202                         OSL_ASSERT(inArguments_.size() == 1);
203                         args.push_back(inArguments_[0].getValue(t));
204                     } else {
205                         OSL_ASSERT(inArguments_.empty());
206                         retType = t;
207                     }
208                     break;
209                 }
210             case typelib_TypeClass_INTERFACE_METHOD:
211                 {
212                     typelib_InterfaceMethodTypeDescription * mtd =
213                         reinterpret_cast<
214                             typelib_InterfaceMethodTypeDescription * >(
215                                 member_.get());
216                     retType = css::uno::TypeDescription(mtd->pReturnTypeRef);
217                     std::vector< BinaryAny >::const_iterator i(
218                         inArguments_.begin());
219                     for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
220                         void * p;
221                         if (mtd->pParams[j].bIn) {
222                             p = i++->getValue(
223                                 css::uno::TypeDescription(
224                                     mtd->pParams[j].pTypeRef));
225                         } else {
226                             outBufs.push_back(
227                                 std::vector< char >(
228                                     css::uno::TypeDescription(
229                                         mtd->pParams[j].pTypeRef).
230                                     get()->nSize));
231                             p = &outBufs.back()[0];
232                         }
233                         args.push_back(p);
234                         if (mtd->pParams[j].bOut) {
235                             outArguments->push_back(BinaryAny());
236                         }
237                     }
238                     OSL_ASSERT(i == inArguments_.end());
239                     break;
240                 }
241             default:
242                 OSL_ASSERT(false); // this cannot happen
243                 break;
244             }
245             std::vector< char > retBuf(retType.is() ? retType.get()->nSize : 0);
246             uno_Any exc;
247             uno_Any * pexc = &exc;
248             (*object_.get()->pDispatcher)(
249                 object_.get(), member_.get(), retBuf.empty() ? 0 : &retBuf[0],
250                 args.empty() ? 0 : &args[0], &pexc);
251             isExc = pexc != 0;
252             if (isExc) {
253                 *returnValue = BinaryAny(
254                     css::uno::TypeDescription(
255                         cppu::UnoType< css::uno::Any >::get()),
256                     &exc);
257                 uno_any_destruct(&exc, 0);
258             } else {
259                 if (!retBuf.empty()) {
260                     *returnValue = BinaryAny(retType, &retBuf[0]);
261                     uno_destructData(&retBuf[0], retType.get(), 0);
262                 }
263                 if (!outArguments->empty()) {
264                     OSL_ASSERT(
265                         member_.get()->eTypeClass ==
266                         typelib_TypeClass_INTERFACE_METHOD);
267                     typelib_InterfaceMethodTypeDescription * mtd =
268                         reinterpret_cast<
269                             typelib_InterfaceMethodTypeDescription * >(
270                                 member_.get());
271                     std::vector< BinaryAny >::iterator i(outArguments->begin());
272                     std::list< std::vector< char > >::iterator j(
273                         outBufs.begin());
274                     for (sal_Int32 k = 0; k != mtd->nParams; ++k) {
275                         if (mtd->pParams[k].bOut) {
276                             *i++ = BinaryAny(
277                                 css::uno::TypeDescription(
278                                     mtd->pParams[k].pTypeRef),
279                                 args[k]);
280                         }
281                         if (!mtd->pParams[k].bIn) {
282                             uno_type_destructData(
283                                 &(*j++)[0], mtd->pParams[k].pTypeRef, 0);
284                         }
285                     }
286                     OSL_ASSERT(i == outArguments->end());
287                     OSL_ASSERT(j == outBufs.end());
288                 }
289             }
290             break;
291         }
292     }
293     return !isExc;
294 }
295 
296 }
297