xref: /aoo41x/main/binaryurp/source/writer.cxx (revision 37adc4f0)
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 <exception>
27 #include <vector>
28 
29 #include "com/sun/star/connection/XConnection.hpp"
30 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
31 #include "com/sun/star/uno/XCurrentContext.hpp"
32 #include "cppuhelper/exc_hlp.hxx"
33 #include "osl/mutex.hxx"
34 #include "rtl/memory.h"
35 #include "uno/dispatcher.hxx"
36 
37 #include "binaryany.hxx"
38 #include "bridge.hxx"
39 #include "currentcontext.hxx"
40 #include "specialfunctionids.hxx"
41 #include "writer.hxx"
42 
43 namespace binaryurp {
44 
45 namespace {
46 
47 namespace css = com::sun::star;
48 
49 bool isProtocolPropertyMessage(rtl::OUString const & oid) {
50     return oid.equalsAsciiL(
51         RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties"));
52 }
53 
54 }
55 
56 Writer::Item::Item() {}
57 
58 Writer::Item::Item(
59     rtl::ByteSequence const & theTid, rtl::OUString const & theOid,
60     css::uno::TypeDescription const & theType,
61     css::uno::TypeDescription const & theMember,
62     std::vector< BinaryAny > const & inArguments,
63     css::uno::UnoInterfaceReference const & theCurrentContext):
64     request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
65     arguments(inArguments), currentContext(theCurrentContext)
66 {}
67 
68 Writer::Item::Item(
69     rtl::ByteSequence const & theTid,
70     css::uno::TypeDescription const & theMember, bool theSetter,
71     bool theException, BinaryAny const & theReturnValue,
72     std::vector< BinaryAny > const & outArguments,
73     bool theSetCurrentContextMode):
74     request(false), tid(theTid), member(theMember), setter(theSetter),
75     arguments(outArguments), exception(theException),
76     returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
77 {}
78 
79 Writer::Writer(rtl::Reference< Bridge > const  & bridge):
80     bridge_(bridge), marshal_(bridge, state_), stop_(false)
81 {
82     OSL_ASSERT(bridge.is());
83     acquire();
84 }
85 
86 void Writer::sendDirectRequest(
87     rtl::ByteSequence const & tid, rtl::OUString const & oid,
88     css::uno::TypeDescription const & type,
89     css::uno::TypeDescription const & member,
90     std::vector< BinaryAny > const & inArguments)
91 {
92     OSL_ASSERT(!unblocked_.check());
93     sendRequest(
94         tid, oid, type, member, inArguments, false,
95         css::uno::UnoInterfaceReference());
96 }
97 
98 void Writer::sendDirectReply(
99     rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
100     bool exception, BinaryAny const & returnValue,
101     std::vector< BinaryAny > const & outArguments)
102 {
103     OSL_ASSERT(!unblocked_.check());
104     sendReply(tid, member, false, exception, returnValue,outArguments);
105 }
106 
107 void Writer::queueRequest(
108     rtl::ByteSequence const & tid, rtl::OUString const & oid,
109     css::uno::TypeDescription const & type,
110     css::uno::TypeDescription const & member,
111     std::vector< BinaryAny > const & inArguments)
112 {
113     css::uno::UnoInterfaceReference cc(current_context::get());
114     osl::MutexGuard g(mutex_);
115     queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
116     items_.set();
117 }
118 
119 void Writer::queueReply(
120     rtl::ByteSequence const & tid,
121     com::sun::star::uno::TypeDescription const & member, bool setter,
122     bool exception, BinaryAny const & returnValue,
123     std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
124 {
125     osl::MutexGuard g(mutex_);
126     queue_.push_back(
127         Item(
128             tid, member, setter, exception, returnValue, outArguments,
129             setCurrentContextMode));
130     items_.set();
131 }
132 
133 void Writer::unblock() {
134     // Assumes that osl::Condition::set works as a memory barrier, so that
135     // changes made by preceeding sendDirectRequest/Reply calls are visible to
136     // subsequent sendRequest/Reply calls:
137     unblocked_.set();
138 }
139 
140 void Writer::stop() {
141     {
142         osl::MutexGuard g(mutex_);
143         stop_ = true;
144     }
145     unblocked_.set();
146     items_.set();
147 }
148 
149 Writer::~Writer() {}
150 
151 void Writer::run() {
152     setName("binaryurpWriter");
153     try {
154         unblocked_.wait();
155         for (;;) {
156             items_.wait();
157             Item item;
158             {
159                 osl::MutexGuard g(mutex_);
160                 if (stop_) {
161                     return;
162                 }
163                 OSL_ASSERT(!queue_.empty());
164                 item = queue_.front();
165                 queue_.pop_front();
166                 if (queue_.empty()) {
167                     items_.reset();
168                 }
169             }
170             if (item.request) {
171                 sendRequest(
172                     item.tid, item.oid, item.type, item.member, item.arguments,
173                     (!item.oid.equalsAsciiL(
174                         RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")) &&
175                      !item.member.equals(
176                          css::uno::TypeDescription(
177                              rtl::OUString(
178                                  RTL_CONSTASCII_USTRINGPARAM(
179                                      "com.sun.star.uno.XInterface::"
180                                      "release")))) &&
181                      bridge_->isCurrentContextMode()),
182                     item.currentContext);
183             } else {
184                 sendReply(
185                     item.tid, item.member, item.setter, item.exception,
186                     item.returnValue, item.arguments);
187                 if (item.setCurrentContextMode) {
188                     bridge_->setCurrentContextMode();
189                 }
190             }
191         }
192     } catch (css::uno::Exception & e) {
193         OSL_TRACE(
194             OSL_LOG_PREFIX "caught UNO exception '%s'",
195             rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
196     } catch (std::exception & e) {
197         OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
198     }
199     bridge_->terminate();
200 }
201 
202 void Writer::onTerminated() {
203     release();
204 }
205 
206 void Writer::sendRequest(
207     rtl::ByteSequence const & tid, rtl::OUString const & oid,
208     css::uno::TypeDescription const & type,
209     css::uno::TypeDescription const & member,
210     std::vector< BinaryAny > const & inArguments, bool currentContextMode,
211     css::uno::UnoInterfaceReference const & currentContext)
212 {
213     OSL_ASSERT(tid.getLength() != 0 && oid.getLength() != 0 && member.is());
214     css::uno::TypeDescription t(type);
215     sal_Int32 functionId = 0;
216     bool forceSynchronous = false;
217     member.makeComplete();
218     switch (member.get()->eTypeClass) {
219     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
220         {
221             typelib_InterfaceAttributeTypeDescription * atd =
222                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
223                     member.get());
224             OSL_ASSERT(atd->pInterface != 0);
225             if (!t.is()) {
226                 t = css::uno::TypeDescription(&atd->pInterface->aBase);
227             }
228             t.makeComplete();
229             functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
230                 atd->aBase.nPosition];
231             if (!inArguments.empty()) { // setter
232                 ++functionId;
233             }
234             break;
235         }
236     case typelib_TypeClass_INTERFACE_METHOD:
237         {
238             typelib_InterfaceMethodTypeDescription * mtd =
239                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
240                     member.get());
241             OSL_ASSERT(mtd->pInterface != 0);
242             if (!t.is()) {
243                 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
244             }
245             t.makeComplete();
246             functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
247                 mtd->aBase.nPosition];
248             forceSynchronous = mtd->bOneWay &&
249                 functionId != SPECIAL_FUNCTION_ID_RELEASE;
250             break;
251         }
252     default:
253         OSL_ASSERT(false); // this cannot happen
254         break;
255     }
256     OSL_ASSERT(functionId >= 0);
257     if (functionId > SAL_MAX_UINT16) {
258         throw css::uno::RuntimeException(
259             rtl::OUString(
260                 RTL_CONSTASCII_USTRINGPARAM("function ID too large for URP")),
261             css::uno::Reference< css::uno::XInterface >());
262     }
263     std::vector< unsigned char > buf;
264     bool newType = !(lastType_.is() && t.equals(lastType_));
265     bool newOid = oid != lastOid_;
266     bool newTid = tid != lastTid_;
267     if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
268         // > 14 bit function ID
269     {
270         Marshal::write8(
271             &buf,
272             (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
273              (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
274              (forceSynchronous ? 0x01 : 0)));
275             // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
276             // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
277         if (forceSynchronous) {
278             Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
279         }
280         if (functionId <= 0xFF) {
281             Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
282         } else {
283             Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
284         }
285         if (newType) {
286             marshal_.writeType(&buf, t);
287         }
288         if (newOid) {
289             marshal_.writeOid(&buf, oid);
290         }
291         if (newTid) {
292             marshal_.writeTid(&buf, tid);
293         }
294     } else if (functionId <= 0x3F) { // <= 6 bit function ID
295         Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
296             // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
297     } else {
298         Marshal::write8(
299             &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
300             // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
301         Marshal::write8(&buf, functionId & 0xFF);
302     }
303     if (currentContextMode) {
304         css::uno::UnoInterfaceReference cc(currentContext);
305         marshal_.writeValue(
306             &buf,
307             css::uno::TypeDescription(
308                 cppu::UnoType<
309                     css::uno::Reference< css::uno::XCurrentContext > >::get()),
310             BinaryAny(
311                 css::uno::TypeDescription(
312                     cppu::UnoType<
313                         css::uno::Reference<
314                             css::uno::XCurrentContext > >::get()),
315                 &cc.m_pUnoI));
316     }
317     switch (member.get()->eTypeClass) {
318     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
319         if (!inArguments.empty()) { // setter
320             OSL_ASSERT(inArguments.size() == 1);
321             marshal_.writeValue(
322                 &buf,
323                 css::uno::TypeDescription(
324                     reinterpret_cast<
325                         typelib_InterfaceAttributeTypeDescription * >(
326                             member.get())->
327                     pAttributeTypeRef),
328                 inArguments.front());
329         }
330         break;
331     case typelib_TypeClass_INTERFACE_METHOD:
332         {
333             typelib_InterfaceMethodTypeDescription * mtd =
334                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
335                     member.get());
336             std::vector< BinaryAny >::const_iterator i(inArguments.begin());
337             for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
338                 if (mtd->pParams[j].bIn) {
339                     marshal_.writeValue(
340                         &buf,
341                         css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
342                         *i++);
343                 }
344             }
345             OSL_ASSERT(i == inArguments.end());
346             break;
347         }
348     default:
349         OSL_ASSERT(false); // this cannot happen
350         break;
351     }
352     sendMessage(buf);
353     lastType_ = t;
354     lastOid_ = oid;
355     lastTid_ = tid;
356 }
357 
358 void Writer::sendReply(
359     rtl::ByteSequence const & tid,
360     com::sun::star::uno::TypeDescription const & member, bool setter,
361     bool exception, BinaryAny const & returnValue,
362     std::vector< BinaryAny > const & outArguments)
363 {
364     OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
365     std::vector< unsigned char > buf;
366     bool newTid = tid != lastTid_;
367     Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
368         // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
369     if (newTid) {
370         marshal_.writeTid(&buf, tid);
371     }
372     if (exception) {
373         marshal_.writeValue(
374             &buf,
375             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
376             returnValue);
377     } else {
378         switch (member.get()->eTypeClass) {
379         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
380             if (!setter) {
381                 marshal_.writeValue(
382                     &buf,
383                     css::uno::TypeDescription(
384                         reinterpret_cast<
385                             typelib_InterfaceAttributeTypeDescription * >(
386                                 member.get())->
387                         pAttributeTypeRef),
388                     returnValue);
389             }
390             break;
391         case typelib_TypeClass_INTERFACE_METHOD:
392             {
393                 typelib_InterfaceMethodTypeDescription * mtd =
394                     reinterpret_cast<
395                         typelib_InterfaceMethodTypeDescription * >(
396                             member.get());
397                 marshal_.writeValue(
398                     &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
399                     returnValue);
400                 std::vector< BinaryAny >::const_iterator i(
401                     outArguments.begin());
402                 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
403                     if (mtd->pParams[j].bOut) {
404                         marshal_.writeValue(
405                             &buf,
406                             css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
407                             *i++);
408                     }
409                 }
410                 OSL_ASSERT(i == outArguments.end());
411                 break;
412             }
413         default:
414             OSL_ASSERT(false); // this cannot happen
415             break;
416         }
417     }
418     sendMessage(buf);
419     lastTid_ = tid;
420     bridge_->decrementCalls();
421 }
422 
423 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
424     std::vector< unsigned char > header;
425     if (buffer.size() > SAL_MAX_UINT32) {
426         throw css::uno::RuntimeException(
427             rtl::OUString(
428                 RTL_CONSTASCII_USTRINGPARAM("message too large for URP")),
429             css::uno::Reference< css::uno::XInterface >());
430     }
431     Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
432     Marshal::write32(&header, 1);
433     OSL_ASSERT(!buffer.empty());
434     unsigned char const * p = &buffer[0];
435     std::vector< unsigned char >::size_type n = buffer.size();
436     OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
437     sal_Size k = SAL_MAX_INT32 - header.size();
438     if (n < k) {
439         k = static_cast< sal_Size >(n);
440     }
441     css::uno::Sequence< sal_Int8 > s(
442         static_cast< sal_Int32 >(header.size() + k));
443     OSL_ASSERT(!header.empty());
444     rtl_copyMemory(
445         s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
446     for (;;) {
447         rtl_copyMemory(s.getArray() + s.getLength() - k, p, k);
448         try {
449             bridge_->getConnection()->write(s);
450         } catch (css::io::IOException & e) {
451             css::uno::Any exc(cppu::getCaughtException());
452             throw css::lang::WrappedTargetRuntimeException(
453                 (rtl::OUString(
454                     RTL_CONSTASCII_USTRINGPARAM(
455                         "Binary URP write raised IO exception: ")) +
456                  e.Message),
457                 css::uno::Reference< css::uno::XInterface >(), exc);
458         }
459         n = static_cast< std::vector< unsigned char >::size_type >(n - k);
460         if (n == 0) {
461             break;
462         }
463         p += k;
464         k = SAL_MAX_INT32;
465         if (n < k) {
466             k = static_cast< sal_Size >(n);
467         }
468         s.realloc(k);
469     }
470 }
471 
472 }
473