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 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("function ID too large for URP");
243 std::vector
< unsigned char > buf
;
244 bool newType
= !(lastType_
.is() && t
.equals(lastType_
));
245 bool newOid
= oid
!= lastOid_
;
246 bool newTid
= tid
!= lastTid_
;
247 if (newType
|| newOid
|| newTid
|| forceSynchronous
|| functionId
> 0x3FFF)
248 // > 14 bit function ID
252 (0xC0 | (newType
? 0x20 : 0) | (newOid
? 0x10 : 0) |
253 (newTid
? 0x08 : 0) | (functionId
> 0xFF ? 0x04 : 0) |
254 (forceSynchronous
? 0x01 : 0)));
255 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
256 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
257 if (forceSynchronous
) {
258 Marshal::write8(&buf
, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
260 if (functionId
<= 0xFF) {
261 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
263 Marshal::write16(&buf
, static_cast< sal_uInt16
>(functionId
));
266 marshal_
.writeType(&buf
, t
);
269 marshal_
.writeOid(&buf
, oid
);
272 marshal_
.writeTid(&buf
, tid
);
274 } else if (functionId
<= 0x3F) { // <= 6 bit function ID
275 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
276 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
279 &buf
, static_cast< sal_uInt8
>(0x40 | (functionId
>> 8)));
280 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
281 Marshal::write8(&buf
, functionId
& 0xFF);
283 if (currentContextMode
) {
284 css::uno::UnoInterfaceReference
cc(currentContext
);
287 css::uno::TypeDescription(
289 css::uno::Reference
< css::uno::XCurrentContext
> >::get()),
291 css::uno::TypeDescription(
294 css::uno::XCurrentContext
> >::get()),
297 switch (member
.get()->eTypeClass
) {
298 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
299 if (!inArguments
.empty()) { // setter
300 OSL_ASSERT(inArguments
.size() == 1);
303 css::uno::TypeDescription(
305 typelib_InterfaceAttributeTypeDescription
* >(
308 inArguments
.front());
311 case typelib_TypeClass_INTERFACE_METHOD
:
313 typelib_InterfaceMethodTypeDescription
* mtd
=
314 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
316 std::vector
< BinaryAny
>::const_iterator
i(inArguments
.begin());
317 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
318 if (mtd
->pParams
[j
].bIn
) {
321 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
325 OSL_ASSERT(i
== inArguments
.end());
329 OSL_ASSERT(false); // this cannot happen
338 void Writer::sendReply(
339 rtl::ByteSequence
const & tid
,
340 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
341 bool exception
, BinaryAny
const & returnValue
,
342 std::vector
< BinaryAny
> const & outArguments
)
344 OSL_ASSERT(tid
.getLength() != 0 && member
.is() && member
.get()->bComplete
);
345 std::vector
< unsigned char > buf
;
346 bool newTid
= tid
!= lastTid_
;
347 Marshal::write8(&buf
, 0x80 | (exception
? 0x20 : 0) | (newTid
? 0x08 : 0));
348 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
350 marshal_
.writeTid(&buf
, tid
);
355 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()),
358 switch (member
.get()->eTypeClass
) {
359 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
363 css::uno::TypeDescription(
365 typelib_InterfaceAttributeTypeDescription
* >(
371 case typelib_TypeClass_INTERFACE_METHOD
:
373 typelib_InterfaceMethodTypeDescription
* mtd
=
375 typelib_InterfaceMethodTypeDescription
* >(
378 &buf
, css::uno::TypeDescription(mtd
->pReturnTypeRef
),
380 std::vector
< BinaryAny
>::const_iterator
i(
381 outArguments
.begin());
382 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
383 if (mtd
->pParams
[j
].bOut
) {
386 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
390 OSL_ASSERT(i
== outArguments
.end());
394 OSL_ASSERT(false); // this cannot happen
400 bridge_
->decrementCalls();
403 void Writer::sendMessage(std::vector
< unsigned char > const & buffer
) {
404 std::vector
< unsigned char > header
;
405 if (buffer
.size() > SAL_MAX_UINT32
) {
406 throw css::uno::RuntimeException(
407 "message too large for URP");
409 Marshal::write32(&header
, static_cast< sal_uInt32
>(buffer
.size()));
410 Marshal::write32(&header
, 1);
411 OSL_ASSERT(!buffer
.empty());
412 unsigned char const * p
= &buffer
[0];
413 std::vector
< unsigned char >::size_type n
= buffer
.size();
414 OSL_ASSERT(header
.size() <= SAL_MAX_INT32
&& SAL_MAX_INT32
<= SAL_MAX_SIZE
);
415 sal_Size k
= SAL_MAX_INT32
- header
.size();
417 k
= static_cast< sal_Size
>(n
);
419 css::uno::Sequence
< sal_Int8
> s(
420 static_cast< sal_Int32
>(header
.size() + k
));
421 OSL_ASSERT(!header
.empty());
423 s
.getArray(), &header
[0], static_cast< sal_Size
>(header
.size()));
425 memcpy(s
.getArray() + s
.getLength() - k
, p
, k
);
427 bridge_
->getConnection()->write(s
);
428 } catch (const css::io::IOException
& e
) {
429 css::uno::Any
exc(cppu::getCaughtException());
430 throw css::lang::WrappedTargetRuntimeException(
431 "Binary URP write raised IO exception: " + e
.Message
,
432 css::uno::Reference
< css::uno::XInterface
>(), exc
);
434 n
= static_cast< std::vector
< unsigned char >::size_type
>(n
- k
);
441 k
= static_cast< sal_Size
>(n
);
449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */