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"
45 , setCurrentContextMode(false)
49 rtl::ByteSequence
const & theTid
, OUString
const & theOid
,
50 css::uno::TypeDescription
const & theType
,
51 css::uno::TypeDescription
const & theMember
,
52 std::vector
< BinaryAny
> const & inArguments
,
53 css::uno::UnoInterfaceReference
const & theCurrentContext
):
54 request(true), tid(theTid
), oid(theOid
), type(theType
), member(theMember
),
55 setter(false), arguments(inArguments
), exception(false),
56 currentContext(theCurrentContext
), setCurrentContextMode(false)
60 rtl::ByteSequence
const & theTid
,
61 css::uno::TypeDescription
const & theMember
, bool theSetter
,
62 bool theException
, BinaryAny
const & theReturnValue
,
63 std::vector
< BinaryAny
> const & outArguments
,
64 bool theSetCurrentContextMode
):
65 request(false), tid(theTid
), member(theMember
), setter(theSetter
),
66 arguments(outArguments
), exception(theException
),
67 returnValue(theReturnValue
), setCurrentContextMode(theSetCurrentContextMode
)
70 Writer::Writer(rtl::Reference
< Bridge
> const & bridge
):
71 Thread("binaryurpWriter"), bridge_(bridge
), marshal_(bridge
, state_
),
74 OSL_ASSERT(bridge
.is());
77 void Writer::sendDirectRequest(
78 rtl::ByteSequence
const & tid
, OUString
const & oid
,
79 css::uno::TypeDescription
const & type
,
80 css::uno::TypeDescription
const & member
,
81 std::vector
< BinaryAny
> const & inArguments
)
83 OSL_ASSERT(!unblocked_
.check());
85 tid
, oid
, type
, member
, inArguments
, false,
86 css::uno::UnoInterfaceReference());
89 void Writer::sendDirectReply(
90 rtl::ByteSequence
const & tid
, css::uno::TypeDescription
const & member
,
91 bool exception
, BinaryAny
const & returnValue
,
92 std::vector
< BinaryAny
> const & outArguments
)
94 OSL_ASSERT(!unblocked_
.check());
95 sendReply(tid
, member
, false, exception
, returnValue
,outArguments
);
98 void Writer::queueRequest(
99 rtl::ByteSequence
const & tid
, OUString
const & oid
,
100 css::uno::TypeDescription
const & type
,
101 css::uno::TypeDescription
const & member
,
102 std::vector
< BinaryAny
> const & inArguments
)
104 css::uno::UnoInterfaceReference
cc(current_context::get());
105 osl::MutexGuard
g(mutex_
);
106 queue_
.push_back(Item(tid
, oid
, type
, member
, inArguments
, cc
));
110 void Writer::queueReply(
111 rtl::ByteSequence
const & tid
,
112 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
113 bool exception
, BinaryAny
const & returnValue
,
114 std::vector
< BinaryAny
> const & outArguments
, bool setCurrentContextMode
)
116 osl::MutexGuard
g(mutex_
);
119 tid
, member
, setter
, exception
, returnValue
, outArguments
,
120 setCurrentContextMode
));
124 void Writer::unblock() {
125 // Assumes that osl::Condition::set works as a memory barrier, so that
126 // changes made by preceding sendDirectRequest/Reply calls are visible to
127 // subsequent sendRequest/Reply calls:
131 void Writer::stop() {
133 osl::MutexGuard
g(mutex_
);
142 void Writer::execute() {
149 osl::MutexGuard
g(mutex_
);
153 OSL_ASSERT(!queue_
.empty());
154 item
= queue_
.front();
156 if (queue_
.empty()) {
162 item
.tid
, item
.oid
, item
.type
, item
.member
, item
.arguments
,
163 (item
.oid
!= "UrpProtocolProperties" &&
165 css::uno::TypeDescription(
166 "com.sun.star.uno.XInterface::release")) &&
167 bridge_
->isCurrentContextMode()),
168 item
.currentContext
);
171 item
.tid
, item
.member
, item
.setter
, item
.exception
,
172 item
.returnValue
, item
.arguments
);
173 if (item
.setCurrentContextMode
) {
174 bridge_
->setCurrentContextMode();
178 } catch (const css::uno::Exception
& e
) {
180 "caught UNO exception '%s'",
181 OUStringToOString(e
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
182 } catch (const std::exception
& e
) {
183 OSL_TRACE("caught C++ exception '%s'", e
.what());
185 bridge_
->terminate(false);
189 void Writer::sendRequest(
190 rtl::ByteSequence
const & tid
, OUString
const & oid
,
191 css::uno::TypeDescription
const & type
,
192 css::uno::TypeDescription
const & member
,
193 std::vector
< BinaryAny
> const & inArguments
, bool currentContextMode
,
194 css::uno::UnoInterfaceReference
const & currentContext
)
196 OSL_ASSERT(tid
.getLength() != 0 && !oid
.isEmpty() && member
.is());
197 css::uno::TypeDescription
t(type
);
198 sal_Int32 functionId
= 0;
199 bool forceSynchronous
= false;
200 member
.makeComplete();
201 switch (member
.get()->eTypeClass
) {
202 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
204 typelib_InterfaceAttributeTypeDescription
* atd
=
205 reinterpret_cast< typelib_InterfaceAttributeTypeDescription
* >(
207 OSL_ASSERT(atd
->pInterface
!= 0);
209 t
= css::uno::TypeDescription(&atd
->pInterface
->aBase
);
212 functionId
= atd
->pInterface
->pMapMemberIndexToFunctionIndex
[
213 atd
->aBase
.nPosition
];
214 if (!inArguments
.empty()) { // setter
219 case typelib_TypeClass_INTERFACE_METHOD
:
221 typelib_InterfaceMethodTypeDescription
* mtd
=
222 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
224 OSL_ASSERT(mtd
->pInterface
!= 0);
226 t
= css::uno::TypeDescription(&mtd
->pInterface
->aBase
);
229 functionId
= mtd
->pInterface
->pMapMemberIndexToFunctionIndex
[
230 mtd
->aBase
.nPosition
];
231 forceSynchronous
= mtd
->bOneWay
&&
232 functionId
!= SPECIAL_FUNCTION_ID_RELEASE
;
236 OSL_ASSERT(false); // this cannot happen
239 OSL_ASSERT(functionId
>= 0);
240 if (functionId
> SAL_MAX_UINT16
) {
241 throw css::uno::RuntimeException(
242 "function ID too large for URP",
243 css::uno::Reference
< css::uno::XInterface
>());
245 std::vector
< unsigned char > buf
;
246 bool newType
= !(lastType_
.is() && t
.equals(lastType_
));
247 bool newOid
= oid
!= lastOid_
;
248 bool newTid
= tid
!= lastTid_
;
249 if (newType
|| newOid
|| newTid
|| forceSynchronous
|| functionId
> 0x3FFF)
250 // > 14 bit function ID
254 (0xC0 | (newType
? 0x20 : 0) | (newOid
? 0x10 : 0) |
255 (newTid
? 0x08 : 0) | (functionId
> 0xFF ? 0x04 : 0) |
256 (forceSynchronous
? 0x01 : 0)));
257 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
258 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
259 if (forceSynchronous
) {
260 Marshal::write8(&buf
, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
262 if (functionId
<= 0xFF) {
263 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
265 Marshal::write16(&buf
, static_cast< sal_uInt16
>(functionId
));
268 marshal_
.writeType(&buf
, t
);
271 marshal_
.writeOid(&buf
, oid
);
274 marshal_
.writeTid(&buf
, tid
);
276 } else if (functionId
<= 0x3F) { // <= 6 bit function ID
277 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
278 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
281 &buf
, static_cast< sal_uInt8
>(0x40 | (functionId
>> 8)));
282 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
283 Marshal::write8(&buf
, functionId
& 0xFF);
285 if (currentContextMode
) {
286 css::uno::UnoInterfaceReference
cc(currentContext
);
289 css::uno::TypeDescription(
291 css::uno::Reference
< css::uno::XCurrentContext
> >::get()),
293 css::uno::TypeDescription(
296 css::uno::XCurrentContext
> >::get()),
299 switch (member
.get()->eTypeClass
) {
300 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
301 if (!inArguments
.empty()) { // setter
302 OSL_ASSERT(inArguments
.size() == 1);
305 css::uno::TypeDescription(
307 typelib_InterfaceAttributeTypeDescription
* >(
310 inArguments
.front());
313 case typelib_TypeClass_INTERFACE_METHOD
:
315 typelib_InterfaceMethodTypeDescription
* mtd
=
316 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
318 std::vector
< BinaryAny
>::const_iterator
i(inArguments
.begin());
319 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
320 if (mtd
->pParams
[j
].bIn
) {
323 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
327 OSL_ASSERT(i
== inArguments
.end());
331 OSL_ASSERT(false); // this cannot happen
340 void Writer::sendReply(
341 rtl::ByteSequence
const & tid
,
342 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
343 bool exception
, BinaryAny
const & returnValue
,
344 std::vector
< BinaryAny
> const & outArguments
)
346 OSL_ASSERT(tid
.getLength() != 0 && member
.is() && member
.get()->bComplete
);
347 std::vector
< unsigned char > buf
;
348 bool newTid
= tid
!= lastTid_
;
349 Marshal::write8(&buf
, 0x80 | (exception
? 0x20 : 0) | (newTid
? 0x08 : 0));
350 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
352 marshal_
.writeTid(&buf
, tid
);
357 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()),
360 switch (member
.get()->eTypeClass
) {
361 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
365 css::uno::TypeDescription(
367 typelib_InterfaceAttributeTypeDescription
* >(
373 case typelib_TypeClass_INTERFACE_METHOD
:
375 typelib_InterfaceMethodTypeDescription
* mtd
=
377 typelib_InterfaceMethodTypeDescription
* >(
380 &buf
, css::uno::TypeDescription(mtd
->pReturnTypeRef
),
382 std::vector
< BinaryAny
>::const_iterator
i(
383 outArguments
.begin());
384 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
385 if (mtd
->pParams
[j
].bOut
) {
388 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
392 OSL_ASSERT(i
== outArguments
.end());
396 OSL_ASSERT(false); // this cannot happen
402 bridge_
->decrementCalls();
405 void Writer::sendMessage(std::vector
< unsigned char > const & buffer
) {
406 std::vector
< unsigned char > header
;
407 if (buffer
.size() > SAL_MAX_UINT32
) {
408 throw css::uno::RuntimeException(
409 "message too large for URP",
410 css::uno::Reference
< css::uno::XInterface
>());
412 Marshal::write32(&header
, static_cast< sal_uInt32
>(buffer
.size()));
413 Marshal::write32(&header
, 1);
414 OSL_ASSERT(!buffer
.empty());
415 unsigned char const * p
= &buffer
[0];
416 std::vector
< unsigned char >::size_type n
= buffer
.size();
417 OSL_ASSERT(header
.size() <= SAL_MAX_INT32
&& SAL_MAX_INT32
<= SAL_MAX_SIZE
);
418 sal_Size k
= SAL_MAX_INT32
- header
.size();
420 k
= static_cast< sal_Size
>(n
);
422 css::uno::Sequence
< sal_Int8
> s(
423 static_cast< sal_Int32
>(header
.size() + k
));
424 OSL_ASSERT(!header
.empty());
426 s
.getArray(), &header
[0], static_cast< sal_Size
>(header
.size()));
428 memcpy(s
.getArray() + s
.getLength() - k
, p
, k
);
430 bridge_
->getConnection()->write(s
);
431 } catch (const css::io::IOException
& e
) {
432 css::uno::Any
exc(cppu::getCaughtException());
433 throw css::lang::WrappedTargetRuntimeException(
434 "Binary URP write raised IO exception: " + e
.Message
,
435 css::uno::Reference
< css::uno::XInterface
>(), exc
);
437 n
= static_cast< std::vector
< unsigned char >::size_type
>(n
- k
);
444 k
= static_cast< sal_Size
>(n
);
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */