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