1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
26 #include "com/sun/star/connection/XConnection.hpp"
27 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
28 #include "com/sun/star/uno/XCurrentContext.hpp"
29 #include "cppuhelper/exc_hlp.hxx"
30 #include "osl/mutex.hxx"
31 #include "uno/dispatcher.hxx"
33 #include "binaryany.hxx"
35 #include "currentcontext.hxx"
36 #include "specialfunctionids.hxx"
41 Writer::Item::Item() {}
44 rtl::ByteSequence
const & theTid
, OUString
const & theOid
,
45 css::uno::TypeDescription
const & theType
,
46 css::uno::TypeDescription
const & theMember
,
47 std::vector
< BinaryAny
> const & inArguments
,
48 css::uno::UnoInterfaceReference
const & theCurrentContext
):
49 request(true), tid(theTid
), oid(theOid
), type(theType
), member(theMember
),
50 arguments(inArguments
), currentContext(theCurrentContext
)
54 rtl::ByteSequence
const & theTid
,
55 css::uno::TypeDescription
const & theMember
, bool theSetter
,
56 bool theException
, BinaryAny
const & theReturnValue
,
57 std::vector
< BinaryAny
> const & outArguments
,
58 bool theSetCurrentContextMode
):
59 request(false), tid(theTid
), member(theMember
), setter(theSetter
),
60 arguments(outArguments
), exception(theException
),
61 returnValue(theReturnValue
), setCurrentContextMode(theSetCurrentContextMode
)
64 Writer::Writer(rtl::Reference
< Bridge
> const & bridge
):
65 Thread("binaryurpWriter"), bridge_(bridge
), marshal_(bridge
, state_
),
68 OSL_ASSERT(bridge
.is());
71 void Writer::sendDirectRequest(
72 rtl::ByteSequence
const & tid
, OUString
const & oid
,
73 css::uno::TypeDescription
const & type
,
74 css::uno::TypeDescription
const & member
,
75 std::vector
< BinaryAny
> const & inArguments
)
77 OSL_ASSERT(!unblocked_
.check());
79 tid
, oid
, type
, member
, inArguments
, false,
80 css::uno::UnoInterfaceReference());
83 void Writer::sendDirectReply(
84 rtl::ByteSequence
const & tid
, css::uno::TypeDescription
const & member
,
85 bool exception
, BinaryAny
const & returnValue
,
86 std::vector
< BinaryAny
> const & outArguments
)
88 OSL_ASSERT(!unblocked_
.check());
89 sendReply(tid
, member
, false, exception
, returnValue
,outArguments
);
92 void Writer::queueRequest(
93 rtl::ByteSequence
const & tid
, OUString
const & oid
,
94 css::uno::TypeDescription
const & type
,
95 css::uno::TypeDescription
const & member
,
96 std::vector
< BinaryAny
> const & inArguments
)
98 css::uno::UnoInterfaceReference
cc(current_context::get());
99 osl::MutexGuard
g(mutex_
);
100 queue_
.push_back(Item(tid
, oid
, type
, member
, inArguments
, cc
));
104 void Writer::queueReply(
105 rtl::ByteSequence
const & tid
,
106 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
107 bool exception
, BinaryAny
const & returnValue
,
108 std::vector
< BinaryAny
> const & outArguments
, bool setCurrentContextMode
)
110 osl::MutexGuard
g(mutex_
);
113 tid
, member
, setter
, exception
, returnValue
, outArguments
,
114 setCurrentContextMode
));
118 void Writer::unblock() {
119 // Assumes that osl::Condition::set works as a memory barrier, so that
120 // changes made by preceeding sendDirectRequest/Reply calls are visible to
121 // subsequent sendRequest/Reply calls:
125 void Writer::stop() {
127 osl::MutexGuard
g(mutex_
);
136 void Writer::execute() {
143 osl::MutexGuard
g(mutex_
);
147 OSL_ASSERT(!queue_
.empty());
148 item
= queue_
.front();
150 if (queue_
.empty()) {
156 item
.tid
, item
.oid
, item
.type
, item
.member
, item
.arguments
,
157 (item
.oid
!= "UrpProtocolProperties" &&
159 css::uno::TypeDescription(
160 "com.sun.star.uno.XInterface::release")) &&
161 bridge_
->isCurrentContextMode()),
162 item
.currentContext
);
165 item
.tid
, item
.member
, item
.setter
, item
.exception
,
166 item
.returnValue
, item
.arguments
);
167 if (item
.setCurrentContextMode
) {
168 bridge_
->setCurrentContextMode();
172 } catch (const css::uno::Exception
& e
) {
174 OSL_LOG_PREFIX
"caught UNO exception '%s'",
175 OUStringToOString(e
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
176 } catch (const std::exception
& e
) {
177 OSL_TRACE(OSL_LOG_PREFIX
"caught C++ exception '%s'", e
.what());
179 bridge_
->terminate(false);
182 void Writer::sendRequest(
183 rtl::ByteSequence
const & tid
, OUString
const & oid
,
184 css::uno::TypeDescription
const & type
,
185 css::uno::TypeDescription
const & member
,
186 std::vector
< BinaryAny
> const & inArguments
, bool currentContextMode
,
187 css::uno::UnoInterfaceReference
const & currentContext
)
189 OSL_ASSERT(tid
.getLength() != 0 && !oid
.isEmpty() && member
.is());
190 css::uno::TypeDescription
t(type
);
191 sal_Int32 functionId
= 0;
192 bool forceSynchronous
= false;
193 member
.makeComplete();
194 switch (member
.get()->eTypeClass
) {
195 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
197 typelib_InterfaceAttributeTypeDescription
* atd
=
198 reinterpret_cast< typelib_InterfaceAttributeTypeDescription
* >(
200 OSL_ASSERT(atd
->pInterface
!= 0);
202 t
= css::uno::TypeDescription(&atd
->pInterface
->aBase
);
205 functionId
= atd
->pInterface
->pMapMemberIndexToFunctionIndex
[
206 atd
->aBase
.nPosition
];
207 if (!inArguments
.empty()) { // setter
212 case typelib_TypeClass_INTERFACE_METHOD
:
214 typelib_InterfaceMethodTypeDescription
* mtd
=
215 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
217 OSL_ASSERT(mtd
->pInterface
!= 0);
219 t
= css::uno::TypeDescription(&mtd
->pInterface
->aBase
);
222 functionId
= mtd
->pInterface
->pMapMemberIndexToFunctionIndex
[
223 mtd
->aBase
.nPosition
];
224 forceSynchronous
= mtd
->bOneWay
&&
225 functionId
!= SPECIAL_FUNCTION_ID_RELEASE
;
229 OSL_ASSERT(false); // this cannot happen
232 OSL_ASSERT(functionId
>= 0);
233 if (functionId
> SAL_MAX_UINT16
) {
234 throw css::uno::RuntimeException(
235 "function ID too large for URP",
236 css::uno::Reference
< css::uno::XInterface
>());
238 std::vector
< unsigned char > buf
;
239 bool newType
= !(lastType_
.is() && t
.equals(lastType_
));
240 bool newOid
= oid
!= lastOid_
;
241 bool newTid
= tid
!= lastTid_
;
242 if (newType
|| newOid
|| newTid
|| forceSynchronous
|| functionId
> 0x3FFF)
243 // > 14 bit function ID
247 (0xC0 | (newType
? 0x20 : 0) | (newOid
? 0x10 : 0) |
248 (newTid
? 0x08 : 0) | (functionId
> 0xFF ? 0x04 : 0) |
249 (forceSynchronous
? 0x01 : 0)));
250 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
251 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
252 if (forceSynchronous
) {
253 Marshal::write8(&buf
, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
255 if (functionId
<= 0xFF) {
256 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
258 Marshal::write16(&buf
, static_cast< sal_uInt16
>(functionId
));
261 marshal_
.writeType(&buf
, t
);
264 marshal_
.writeOid(&buf
, oid
);
267 marshal_
.writeTid(&buf
, tid
);
269 } else if (functionId
<= 0x3F) { // <= 6 bit function ID
270 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
271 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
274 &buf
, static_cast< sal_uInt8
>(0x40 | (functionId
>> 8)));
275 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
276 Marshal::write8(&buf
, functionId
& 0xFF);
278 if (currentContextMode
) {
279 css::uno::UnoInterfaceReference
cc(currentContext
);
282 css::uno::TypeDescription(
284 css::uno::Reference
< css::uno::XCurrentContext
> >::get()),
286 css::uno::TypeDescription(
289 css::uno::XCurrentContext
> >::get()),
292 switch (member
.get()->eTypeClass
) {
293 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
294 if (!inArguments
.empty()) { // setter
295 OSL_ASSERT(inArguments
.size() == 1);
298 css::uno::TypeDescription(
300 typelib_InterfaceAttributeTypeDescription
* >(
303 inArguments
.front());
306 case typelib_TypeClass_INTERFACE_METHOD
:
308 typelib_InterfaceMethodTypeDescription
* mtd
=
309 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
311 std::vector
< BinaryAny
>::const_iterator
i(inArguments
.begin());
312 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
313 if (mtd
->pParams
[j
].bIn
) {
316 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
320 OSL_ASSERT(i
== inArguments
.end());
324 OSL_ASSERT(false); // this cannot happen
333 void Writer::sendReply(
334 rtl::ByteSequence
const & tid
,
335 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
336 bool exception
, BinaryAny
const & returnValue
,
337 std::vector
< BinaryAny
> const & outArguments
)
339 OSL_ASSERT(tid
.getLength() != 0 && member
.is() && member
.get()->bComplete
);
340 std::vector
< unsigned char > buf
;
341 bool newTid
= tid
!= lastTid_
;
342 Marshal::write8(&buf
, 0x80 | (exception
? 0x20 : 0) | (newTid
? 0x08 : 0));
343 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
345 marshal_
.writeTid(&buf
, tid
);
350 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()),
353 switch (member
.get()->eTypeClass
) {
354 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
358 css::uno::TypeDescription(
360 typelib_InterfaceAttributeTypeDescription
* >(
366 case typelib_TypeClass_INTERFACE_METHOD
:
368 typelib_InterfaceMethodTypeDescription
* mtd
=
370 typelib_InterfaceMethodTypeDescription
* >(
373 &buf
, css::uno::TypeDescription(mtd
->pReturnTypeRef
),
375 std::vector
< BinaryAny
>::const_iterator
i(
376 outArguments
.begin());
377 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
378 if (mtd
->pParams
[j
].bOut
) {
381 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
385 OSL_ASSERT(i
== outArguments
.end());
389 OSL_ASSERT(false); // this cannot happen
395 bridge_
->decrementCalls();
398 void Writer::sendMessage(std::vector
< unsigned char > const & buffer
) {
399 std::vector
< unsigned char > header
;
400 if (buffer
.size() > SAL_MAX_UINT32
) {
401 throw css::uno::RuntimeException(
402 "message too large for URP",
403 css::uno::Reference
< css::uno::XInterface
>());
405 Marshal::write32(&header
, static_cast< sal_uInt32
>(buffer
.size()));
406 Marshal::write32(&header
, 1);
407 OSL_ASSERT(!buffer
.empty());
408 unsigned char const * p
= &buffer
[0];
409 std::vector
< unsigned char >::size_type n
= buffer
.size();
410 OSL_ASSERT(header
.size() <= SAL_MAX_INT32
&& SAL_MAX_INT32
<= SAL_MAX_SIZE
);
411 sal_Size k
= SAL_MAX_INT32
- header
.size();
413 k
= static_cast< sal_Size
>(n
);
415 css::uno::Sequence
< sal_Int8
> s(
416 static_cast< sal_Int32
>(header
.size() + k
));
417 OSL_ASSERT(!header
.empty());
419 s
.getArray(), &header
[0], static_cast< sal_Size
>(header
.size()));
421 memcpy(s
.getArray() + s
.getLength() - k
, p
, k
);
423 bridge_
->getConnection()->write(s
);
424 } catch (const css::io::IOException
& e
) {
425 css::uno::Any
exc(cppu::getCaughtException());
426 throw css::lang::WrappedTargetRuntimeException(
427 "Binary URP write raised IO exception: " + e
.Message
,
428 css::uno::Reference
< css::uno::XInterface
>(), exc
);
430 n
= static_cast< std::vector
< unsigned char >::size_type
>(n
- k
);
437 k
= static_cast< sal_Size
>(n
);
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */