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);
183 void Writer::sendRequest(
184 rtl::ByteSequence
const & tid
, OUString
const & oid
,
185 css::uno::TypeDescription
const & type
,
186 css::uno::TypeDescription
const & member
,
187 std::vector
< BinaryAny
> const & inArguments
, bool currentContextMode
,
188 css::uno::UnoInterfaceReference
const & currentContext
)
190 OSL_ASSERT(tid
.getLength() != 0 && !oid
.isEmpty() && member
.is());
191 css::uno::TypeDescription
t(type
);
192 sal_Int32 functionId
= 0;
193 bool forceSynchronous
= false;
194 member
.makeComplete();
195 switch (member
.get()->eTypeClass
) {
196 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
198 typelib_InterfaceAttributeTypeDescription
* atd
=
199 reinterpret_cast< typelib_InterfaceAttributeTypeDescription
* >(
201 OSL_ASSERT(atd
->pInterface
!= 0);
203 t
= css::uno::TypeDescription(&atd
->pInterface
->aBase
);
206 functionId
= atd
->pInterface
->pMapMemberIndexToFunctionIndex
[
207 atd
->aBase
.nPosition
];
208 if (!inArguments
.empty()) { // setter
213 case typelib_TypeClass_INTERFACE_METHOD
:
215 typelib_InterfaceMethodTypeDescription
* mtd
=
216 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
218 OSL_ASSERT(mtd
->pInterface
!= 0);
220 t
= css::uno::TypeDescription(&mtd
->pInterface
->aBase
);
223 functionId
= mtd
->pInterface
->pMapMemberIndexToFunctionIndex
[
224 mtd
->aBase
.nPosition
];
225 forceSynchronous
= mtd
->bOneWay
&&
226 functionId
!= SPECIAL_FUNCTION_ID_RELEASE
;
230 OSL_ASSERT(false); // this cannot happen
233 OSL_ASSERT(functionId
>= 0);
234 if (functionId
> SAL_MAX_UINT16
) {
235 throw css::uno::RuntimeException(
236 "function ID too large for URP",
237 css::uno::Reference
< css::uno::XInterface
>());
239 std::vector
< unsigned char > buf
;
240 bool newType
= !(lastType_
.is() && t
.equals(lastType_
));
241 bool newOid
= oid
!= lastOid_
;
242 bool newTid
= tid
!= lastTid_
;
243 if (newType
|| newOid
|| newTid
|| forceSynchronous
|| functionId
> 0x3FFF)
244 // > 14 bit function ID
248 (0xC0 | (newType
? 0x20 : 0) | (newOid
? 0x10 : 0) |
249 (newTid
? 0x08 : 0) | (functionId
> 0xFF ? 0x04 : 0) |
250 (forceSynchronous
? 0x01 : 0)));
251 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
252 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
253 if (forceSynchronous
) {
254 Marshal::write8(&buf
, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
256 if (functionId
<= 0xFF) {
257 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
259 Marshal::write16(&buf
, static_cast< sal_uInt16
>(functionId
));
262 marshal_
.writeType(&buf
, t
);
265 marshal_
.writeOid(&buf
, oid
);
268 marshal_
.writeTid(&buf
, tid
);
270 } else if (functionId
<= 0x3F) { // <= 6 bit function ID
271 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
272 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
275 &buf
, static_cast< sal_uInt8
>(0x40 | (functionId
>> 8)));
276 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
277 Marshal::write8(&buf
, functionId
& 0xFF);
279 if (currentContextMode
) {
280 css::uno::UnoInterfaceReference
cc(currentContext
);
283 css::uno::TypeDescription(
285 css::uno::Reference
< css::uno::XCurrentContext
> >::get()),
287 css::uno::TypeDescription(
290 css::uno::XCurrentContext
> >::get()),
293 switch (member
.get()->eTypeClass
) {
294 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
295 if (!inArguments
.empty()) { // setter
296 OSL_ASSERT(inArguments
.size() == 1);
299 css::uno::TypeDescription(
301 typelib_InterfaceAttributeTypeDescription
* >(
304 inArguments
.front());
307 case typelib_TypeClass_INTERFACE_METHOD
:
309 typelib_InterfaceMethodTypeDescription
* mtd
=
310 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
312 std::vector
< BinaryAny
>::const_iterator
i(inArguments
.begin());
313 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
314 if (mtd
->pParams
[j
].bIn
) {
317 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
321 OSL_ASSERT(i
== inArguments
.end());
325 OSL_ASSERT(false); // this cannot happen
334 void Writer::sendReply(
335 rtl::ByteSequence
const & tid
,
336 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
337 bool exception
, BinaryAny
const & returnValue
,
338 std::vector
< BinaryAny
> const & outArguments
)
340 OSL_ASSERT(tid
.getLength() != 0 && member
.is() && member
.get()->bComplete
);
341 std::vector
< unsigned char > buf
;
342 bool newTid
= tid
!= lastTid_
;
343 Marshal::write8(&buf
, 0x80 | (exception
? 0x20 : 0) | (newTid
? 0x08 : 0));
344 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
346 marshal_
.writeTid(&buf
, tid
);
351 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()),
354 switch (member
.get()->eTypeClass
) {
355 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
359 css::uno::TypeDescription(
361 typelib_InterfaceAttributeTypeDescription
* >(
367 case typelib_TypeClass_INTERFACE_METHOD
:
369 typelib_InterfaceMethodTypeDescription
* mtd
=
371 typelib_InterfaceMethodTypeDescription
* >(
374 &buf
, css::uno::TypeDescription(mtd
->pReturnTypeRef
),
376 std::vector
< BinaryAny
>::const_iterator
i(
377 outArguments
.begin());
378 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
379 if (mtd
->pParams
[j
].bOut
) {
382 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
386 OSL_ASSERT(i
== outArguments
.end());
390 OSL_ASSERT(false); // this cannot happen
396 bridge_
->decrementCalls();
399 void Writer::sendMessage(std::vector
< unsigned char > const & buffer
) {
400 std::vector
< unsigned char > header
;
401 if (buffer
.size() > SAL_MAX_UINT32
) {
402 throw css::uno::RuntimeException(
403 "message too large for URP",
404 css::uno::Reference
< css::uno::XInterface
>());
406 Marshal::write32(&header
, static_cast< sal_uInt32
>(buffer
.size()));
407 Marshal::write32(&header
, 1);
408 OSL_ASSERT(!buffer
.empty());
409 unsigned char const * p
= &buffer
[0];
410 std::vector
< unsigned char >::size_type n
= buffer
.size();
411 OSL_ASSERT(header
.size() <= SAL_MAX_INT32
&& SAL_MAX_INT32
<= SAL_MAX_SIZE
);
412 sal_Size k
= SAL_MAX_INT32
- header
.size();
414 k
= static_cast< sal_Size
>(n
);
416 css::uno::Sequence
< sal_Int8
> s(
417 static_cast< sal_Int32
>(header
.size() + k
));
418 OSL_ASSERT(!header
.empty());
420 s
.getArray(), &header
[0], static_cast< sal_Size
>(header
.size()));
422 memcpy(s
.getArray() + s
.getLength() - k
, p
, k
);
424 bridge_
->getConnection()->write(s
);
425 } catch (const css::io::IOException
& e
) {
426 css::uno::Any
exc(cppu::getCaughtException());
427 throw css::lang::WrappedTargetRuntimeException(
428 "Binary URP write raised IO exception: " + e
.Message
,
429 css::uno::Reference
< css::uno::XInterface
>(), exc
);
431 n
= static_cast< std::vector
< unsigned char >::size_type
>(n
- k
);
438 k
= static_cast< sal_Size
>(n
);
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */