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>
30 #include <com/sun/star/connection/XConnection.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
33 #include <com/sun/star/uno/XCurrentContext.hpp>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <sal/log.hxx>
36 #include <uno/dispatcher.hxx>
38 #include "binaryany.hxx"
40 #include "currentcontext.hxx"
41 #include "specialfunctionids.hxx"
50 , setCurrentContextMode(false)
54 rtl::ByteSequence theTid
, OUString theOid
,
55 css::uno::TypeDescription theType
,
56 css::uno::TypeDescription theMember
,
57 std::vector
< BinaryAny
>&& inArguments
,
58 css::uno::UnoInterfaceReference theCurrentContext
):
59 tid(std::move(theTid
)), oid(std::move(theOid
)), type(std::move(theType
)), member(std::move(theMember
)),
60 currentContext(std::move(theCurrentContext
)), arguments(std::move(inArguments
)),
61 request(true), setter(false), exception(false), setCurrentContextMode(false)
65 rtl::ByteSequence theTid
,
66 css::uno::TypeDescription theMember
, bool theSetter
,
67 bool theException
, BinaryAny theReturnValue
,
68 std::vector
< BinaryAny
>&& outArguments
,
69 bool theSetCurrentContextMode
):
70 tid(std::move(theTid
)), member(std::move(theMember
)),
71 returnValue(std::move(theReturnValue
)), arguments(std::move(outArguments
)),
72 request(false), setter(theSetter
),
73 exception(theException
), setCurrentContextMode(theSetCurrentContextMode
)
76 Writer::Writer(rtl::Reference
< Bridge
> const & bridge
):
77 Thread("binaryurpWriter"), bridge_(bridge
), marshal_(bridge
, state_
),
83 void Writer::sendDirectRequest(
84 rtl::ByteSequence
const & tid
, OUString
const & oid
,
85 css::uno::TypeDescription
const & type
,
86 css::uno::TypeDescription
const & member
,
87 std::vector
< BinaryAny
> const & inArguments
)
89 assert(!unblocked_
.check());
91 tid
, oid
, type
, member
, inArguments
, false,
92 css::uno::UnoInterfaceReference());
95 void Writer::sendDirectReply(
96 rtl::ByteSequence
const & tid
, css::uno::TypeDescription
const & member
,
97 bool exception
, BinaryAny
const & returnValue
,
98 std::vector
< BinaryAny
> const & outArguments
)
100 assert(!unblocked_
.check());
101 sendReply(tid
, member
, false, exception
, returnValue
,outArguments
);
104 void Writer::queueRequest(
105 rtl::ByteSequence
const & tid
, OUString
const & oid
,
106 css::uno::TypeDescription
const & type
,
107 css::uno::TypeDescription
const & member
,
108 std::vector
< BinaryAny
>&& inArguments
)
110 css::uno::UnoInterfaceReference
cc(current_context::get());
111 std::lock_guard
g(mutex_
);
112 queue_
.emplace_back(tid
, oid
, type
, member
, std::move(inArguments
), cc
);
116 void Writer::queueReply(
117 rtl::ByteSequence
const & tid
,
118 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
119 bool exception
, BinaryAny
const & returnValue
,
120 std::vector
< BinaryAny
>&& outArguments
, bool setCurrentContextMode
)
122 std::lock_guard
g(mutex_
);
124 tid
, member
, setter
, exception
, returnValue
, std::move(outArguments
),
125 setCurrentContextMode
);
129 void Writer::unblock() {
130 // Assumes that osl::Condition::set works as a memory barrier, so that
131 // changes made by preceding sendDirectRequest/Reply calls are visible to
132 // subsequent sendRequest/Reply calls:
136 void Writer::stop() {
138 std::lock_guard
g(mutex_
);
147 void Writer::execute() {
154 std::lock_guard
g(mutex_
);
158 assert(!queue_
.empty());
159 item
= queue_
.front();
161 if (queue_
.empty()) {
167 item
.tid
, item
.oid
, item
.type
, item
.member
, item
.arguments
,
168 (item
.oid
!= "UrpProtocolProperties" &&
170 css::uno::TypeDescription(
171 "com.sun.star.uno.XInterface::release")) &&
172 bridge_
->isCurrentContextMode()),
173 item
.currentContext
);
176 item
.tid
, item
.member
, item
.setter
, item
.exception
,
177 item
.returnValue
, item
.arguments
);
178 if (item
.setCurrentContextMode
) {
179 bridge_
->setCurrentContextMode();
183 } catch (const css::uno::Exception
& e
) {
184 SAL_INFO("binaryurp", "caught " << e
);
185 } catch (const std::exception
& e
) {
186 SAL_INFO("binaryurp", "caught C++ exception " << e
.what());
188 bridge_
->terminate(false);
192 void Writer::sendRequest(
193 rtl::ByteSequence
const & tid
, OUString
const & oid
,
194 css::uno::TypeDescription
const & type
,
195 css::uno::TypeDescription
const & member
,
196 std::vector
< BinaryAny
> const & inArguments
, bool currentContextMode
,
197 css::uno::UnoInterfaceReference
const & currentContext
)
199 assert(tid
.getLength() != 0);
200 assert(!oid
.isEmpty());
202 css::uno::TypeDescription
t(type
);
203 sal_Int32 functionId
= 0;
204 bool bForceSynchronous
= false;
205 member
.makeComplete();
206 switch (member
.get()->eTypeClass
) {
207 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
209 typelib_InterfaceAttributeTypeDescription
* atd
=
210 reinterpret_cast< typelib_InterfaceAttributeTypeDescription
* >(
212 assert(atd
->pInterface
!= nullptr);
214 t
= css::uno::TypeDescription(&atd
->pInterface
->aBase
);
217 functionId
= atd
->pInterface
->pMapMemberIndexToFunctionIndex
[
218 atd
->aBase
.nPosition
];
219 if (!inArguments
.empty()) { // setter
224 case typelib_TypeClass_INTERFACE_METHOD
:
226 typelib_InterfaceMethodTypeDescription
* mtd
=
227 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
229 assert(mtd
->pInterface
!= nullptr);
231 t
= css::uno::TypeDescription(&mtd
->pInterface
->aBase
);
234 functionId
= mtd
->pInterface
->pMapMemberIndexToFunctionIndex
[
235 mtd
->aBase
.nPosition
];
236 bForceSynchronous
= mtd
->bOneWay
&&
237 functionId
!= SPECIAL_FUNCTION_ID_RELEASE
;
241 assert(false); // this cannot happen
244 assert(functionId
>= 0);
245 if (functionId
> SAL_MAX_UINT16
) {
246 throw css::uno::RuntimeException("function ID too large for URP");
248 std::vector
< unsigned char > buf
;
249 bool newType
= !(lastType_
.is() && t
.equals(lastType_
));
250 bool newOid
= oid
!= lastOid_
;
251 bool newTid
= tid
!= lastTid_
;
252 if (newType
|| newOid
|| newTid
|| bForceSynchronous
|| functionId
> 0x3FFF)
253 // > 14 bit function ID
257 (0xC0 | (newType
? 0x20 : 0) | (newOid
? 0x10 : 0) |
258 (newTid
? 0x08 : 0) | (functionId
> 0xFF ? 0x04 : 0) |
259 (bForceSynchronous
? 0x01 : 0)));
260 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
261 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
262 if (bForceSynchronous
) {
263 Marshal::write8(&buf
, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
265 if (functionId
<= 0xFF) {
266 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
268 Marshal::write16(&buf
, static_cast< sal_uInt16
>(functionId
));
271 marshal_
.writeType(&buf
, t
);
274 marshal_
.writeOid(&buf
, oid
);
277 marshal_
.writeTid(&buf
, tid
);
279 } else if (functionId
<= 0x3F) { // <= 6 bit function ID
280 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
281 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
284 &buf
, static_cast< sal_uInt8
>(0x40 | (functionId
>> 8)));
285 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
286 Marshal::write8(&buf
, functionId
& 0xFF);
288 if (currentContextMode
) {
289 css::uno::UnoInterfaceReference
cc(currentContext
);
292 css::uno::TypeDescription(
294 css::uno::Reference
< css::uno::XCurrentContext
> >::get()),
296 css::uno::TypeDescription(
299 css::uno::XCurrentContext
> >::get()),
302 switch (member
.get()->eTypeClass
) {
303 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
304 if (!inArguments
.empty()) { // setter
305 assert(inArguments
.size() == 1);
308 css::uno::TypeDescription(
310 typelib_InterfaceAttributeTypeDescription
* >(
313 inArguments
.front());
316 case typelib_TypeClass_INTERFACE_METHOD
:
318 typelib_InterfaceMethodTypeDescription
* mtd
=
319 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
321 std::vector
< BinaryAny
>::const_iterator
i(inArguments
.begin());
322 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
323 if (mtd
->pParams
[j
].bIn
) {
326 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
330 assert(i
== inArguments
.end());
334 assert(false); // this cannot happen
343 void Writer::sendReply(
344 rtl::ByteSequence
const & tid
,
345 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
346 bool exception
, BinaryAny
const & returnValue
,
347 std::vector
< BinaryAny
> const & outArguments
)
349 assert(tid
.getLength() != 0);
351 assert(member
.get()->bComplete
);
352 std::vector
< unsigned char > buf
;
353 bool newTid
= tid
!= lastTid_
;
354 Marshal::write8(&buf
, 0x80 | (exception
? 0x20 : 0) | (newTid
? 0x08 : 0));
355 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
357 marshal_
.writeTid(&buf
, tid
);
362 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()),
365 switch (member
.get()->eTypeClass
) {
366 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
370 css::uno::TypeDescription(
372 typelib_InterfaceAttributeTypeDescription
* >(
378 case typelib_TypeClass_INTERFACE_METHOD
:
380 typelib_InterfaceMethodTypeDescription
* mtd
=
382 typelib_InterfaceMethodTypeDescription
* >(
385 &buf
, css::uno::TypeDescription(mtd
->pReturnTypeRef
),
387 std::vector
< BinaryAny
>::const_iterator
i(
388 outArguments
.begin());
389 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
390 if (mtd
->pParams
[j
].bOut
) {
393 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
397 assert(i
== outArguments
.end());
401 assert(false); // this cannot happen
407 bridge_
->decrementCalls();
410 void Writer::sendMessage(std::vector
< unsigned char > const & buffer
) {
411 std::vector
< unsigned char > header
;
412 if (buffer
.size() > SAL_MAX_UINT32
) {
413 throw css::uno::RuntimeException(
414 "message too large for URP");
416 Marshal::write32(&header
, static_cast< sal_uInt32
>(buffer
.size()));
417 Marshal::write32(&header
, 1);
418 assert(!buffer
.empty());
419 unsigned char const * p
= buffer
.data();
420 std::vector
< unsigned char >::size_type n
= buffer
.size();
421 assert(header
.size() <= SAL_MAX_INT32
);
422 /*static_*/assert(SAL_MAX_INT32
<= std::numeric_limits
<std::size_t>::max());
423 std::size_t k
= SAL_MAX_INT32
- header
.size();
427 css::uno::Sequence
<sal_Int8
> s(header
.size() + k
);
428 assert(!header
.empty());
429 std::memcpy(s
.getArray(), header
.data(), header
.size());
431 std::memcpy(s
.getArray() + s
.getLength() - k
, p
, k
);
433 bridge_
->getConnection()->write(s
);
434 } catch (const css::io::IOException
& e
) {
435 css::uno::Any
exc(cppu::getCaughtException());
436 throw css::lang::WrappedTargetRuntimeException(
437 "Binary URP write raised IO exception: " + e
.Message
,
438 css::uno::Reference
< css::uno::XInterface
>(), exc
);
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */