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>
29 #include <com/sun/star/connection/XConnection.hpp>
30 #include <com/sun/star/io/IOException.hpp>
31 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
32 #include <com/sun/star/uno/XCurrentContext.hpp>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <osl/mutex.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
const & theTid
, OUString
const & theOid
,
55 css::uno::TypeDescription
const & theType
,
56 css::uno::TypeDescription
const & theMember
,
57 std::vector
< BinaryAny
> const & inArguments
,
58 css::uno::UnoInterfaceReference
const & theCurrentContext
):
59 request(true), tid(theTid
), oid(theOid
), type(theType
), member(theMember
),
60 setter(false), arguments(inArguments
), exception(false),
61 currentContext(theCurrentContext
), setCurrentContextMode(false)
65 rtl::ByteSequence
const & theTid
,
66 css::uno::TypeDescription
const & theMember
, bool theSetter
,
67 bool theException
, BinaryAny
const & theReturnValue
,
68 std::vector
< BinaryAny
> const & outArguments
,
69 bool theSetCurrentContextMode
):
70 request(false), tid(theTid
), member(theMember
), setter(theSetter
),
71 arguments(outArguments
), exception(theException
),
72 returnValue(theReturnValue
), setCurrentContextMode(theSetCurrentContextMode
)
75 Writer::Writer(rtl::Reference
< Bridge
> const & bridge
):
76 Thread("binaryurpWriter"), bridge_(bridge
), marshal_(bridge
, state_
),
82 void Writer::sendDirectRequest(
83 rtl::ByteSequence
const & tid
, OUString
const & oid
,
84 css::uno::TypeDescription
const & type
,
85 css::uno::TypeDescription
const & member
,
86 std::vector
< BinaryAny
> const & inArguments
)
88 assert(!unblocked_
.check());
90 tid
, oid
, type
, member
, inArguments
, false,
91 css::uno::UnoInterfaceReference());
94 void Writer::sendDirectReply(
95 rtl::ByteSequence
const & tid
, css::uno::TypeDescription
const & member
,
96 bool exception
, BinaryAny
const & returnValue
,
97 std::vector
< BinaryAny
> const & outArguments
)
99 assert(!unblocked_
.check());
100 sendReply(tid
, member
, false, exception
, returnValue
,outArguments
);
103 void Writer::queueRequest(
104 rtl::ByteSequence
const & tid
, OUString
const & oid
,
105 css::uno::TypeDescription
const & type
,
106 css::uno::TypeDescription
const & member
,
107 std::vector
< BinaryAny
> const & inArguments
)
109 css::uno::UnoInterfaceReference
cc(current_context::get());
110 osl::MutexGuard
g(mutex_
);
111 queue_
.emplace_back(tid
, oid
, type
, member
, inArguments
, cc
);
115 void Writer::queueReply(
116 rtl::ByteSequence
const & tid
,
117 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
118 bool exception
, BinaryAny
const & returnValue
,
119 std::vector
< BinaryAny
> const & outArguments
, bool setCurrentContextMode
)
121 osl::MutexGuard
g(mutex_
);
123 tid
, member
, setter
, exception
, returnValue
, outArguments
,
124 setCurrentContextMode
);
128 void Writer::unblock() {
129 // Assumes that osl::Condition::set works as a memory barrier, so that
130 // changes made by preceding sendDirectRequest/Reply calls are visible to
131 // subsequent sendRequest/Reply calls:
135 void Writer::stop() {
137 osl::MutexGuard
g(mutex_
);
146 void Writer::execute() {
153 osl::MutexGuard
g(mutex_
);
157 assert(!queue_
.empty());
158 item
= queue_
.front();
160 if (queue_
.empty()) {
166 item
.tid
, item
.oid
, item
.type
, item
.member
, item
.arguments
,
167 (item
.oid
!= "UrpProtocolProperties" &&
169 css::uno::TypeDescription(
170 "com.sun.star.uno.XInterface::release")) &&
171 bridge_
->isCurrentContextMode()),
172 item
.currentContext
);
175 item
.tid
, item
.member
, item
.setter
, item
.exception
,
176 item
.returnValue
, item
.arguments
);
177 if (item
.setCurrentContextMode
) {
178 bridge_
->setCurrentContextMode();
182 } catch (const css::uno::Exception
& e
) {
183 SAL_INFO("binaryurp", "caught " << e
);
184 } catch (const std::exception
& e
) {
185 SAL_INFO("binaryurp", "caught C++ exception " << e
.what());
187 bridge_
->terminate(false);
191 void Writer::sendRequest(
192 rtl::ByteSequence
const & tid
, OUString
const & oid
,
193 css::uno::TypeDescription
const & type
,
194 css::uno::TypeDescription
const & member
,
195 std::vector
< BinaryAny
> const & inArguments
, bool currentContextMode
,
196 css::uno::UnoInterfaceReference
const & currentContext
)
198 assert(tid
.getLength() != 0);
199 assert(!oid
.isEmpty());
201 css::uno::TypeDescription
t(type
);
202 sal_Int32 functionId
= 0;
203 bool bForceSynchronous
= false;
204 member
.makeComplete();
205 switch (member
.get()->eTypeClass
) {
206 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
208 typelib_InterfaceAttributeTypeDescription
* atd
=
209 reinterpret_cast< typelib_InterfaceAttributeTypeDescription
* >(
211 assert(atd
->pInterface
!= nullptr);
213 t
= css::uno::TypeDescription(&atd
->pInterface
->aBase
);
216 functionId
= atd
->pInterface
->pMapMemberIndexToFunctionIndex
[
217 atd
->aBase
.nPosition
];
218 if (!inArguments
.empty()) { // setter
223 case typelib_TypeClass_INTERFACE_METHOD
:
225 typelib_InterfaceMethodTypeDescription
* mtd
=
226 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
228 assert(mtd
->pInterface
!= nullptr);
230 t
= css::uno::TypeDescription(&mtd
->pInterface
->aBase
);
233 functionId
= mtd
->pInterface
->pMapMemberIndexToFunctionIndex
[
234 mtd
->aBase
.nPosition
];
235 bForceSynchronous
= mtd
->bOneWay
&&
236 functionId
!= SPECIAL_FUNCTION_ID_RELEASE
;
240 assert(false); // this cannot happen
243 assert(functionId
>= 0);
244 if (functionId
> SAL_MAX_UINT16
) {
245 throw css::uno::RuntimeException("function ID too large for URP");
247 std::vector
< unsigned char > buf
;
248 bool newType
= !(lastType_
.is() && t
.equals(lastType_
));
249 bool newOid
= oid
!= lastOid_
;
250 bool newTid
= tid
!= lastTid_
;
251 if (newType
|| newOid
|| newTid
|| bForceSynchronous
|| functionId
> 0x3FFF)
252 // > 14 bit function ID
256 (0xC0 | (newType
? 0x20 : 0) | (newOid
? 0x10 : 0) |
257 (newTid
? 0x08 : 0) | (functionId
> 0xFF ? 0x04 : 0) |
258 (bForceSynchronous
? 0x01 : 0)));
259 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
260 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
261 if (bForceSynchronous
) {
262 Marshal::write8(&buf
, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
264 if (functionId
<= 0xFF) {
265 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
267 Marshal::write16(&buf
, static_cast< sal_uInt16
>(functionId
));
270 marshal_
.writeType(&buf
, t
);
273 marshal_
.writeOid(&buf
, oid
);
276 marshal_
.writeTid(&buf
, tid
);
278 } else if (functionId
<= 0x3F) { // <= 6 bit function ID
279 Marshal::write8(&buf
, static_cast< sal_uInt8
>(functionId
));
280 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
283 &buf
, static_cast< sal_uInt8
>(0x40 | (functionId
>> 8)));
284 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
285 Marshal::write8(&buf
, functionId
& 0xFF);
287 if (currentContextMode
) {
288 css::uno::UnoInterfaceReference
cc(currentContext
);
291 css::uno::TypeDescription(
293 css::uno::Reference
< css::uno::XCurrentContext
> >::get()),
295 css::uno::TypeDescription(
298 css::uno::XCurrentContext
> >::get()),
301 switch (member
.get()->eTypeClass
) {
302 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
303 if (!inArguments
.empty()) { // setter
304 assert(inArguments
.size() == 1);
307 css::uno::TypeDescription(
309 typelib_InterfaceAttributeTypeDescription
* >(
312 inArguments
.front());
315 case typelib_TypeClass_INTERFACE_METHOD
:
317 typelib_InterfaceMethodTypeDescription
* mtd
=
318 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
320 std::vector
< BinaryAny
>::const_iterator
i(inArguments
.begin());
321 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
322 if (mtd
->pParams
[j
].bIn
) {
325 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
329 assert(i
== inArguments
.end());
333 assert(false); // this cannot happen
342 void Writer::sendReply(
343 rtl::ByteSequence
const & tid
,
344 com::sun::star::uno::TypeDescription
const & member
, bool setter
,
345 bool exception
, BinaryAny
const & returnValue
,
346 std::vector
< BinaryAny
> const & outArguments
)
348 assert(tid
.getLength() != 0);
350 assert(member
.get()->bComplete
);
351 std::vector
< unsigned char > buf
;
352 bool newTid
= tid
!= lastTid_
;
353 Marshal::write8(&buf
, 0x80 | (exception
? 0x20 : 0) | (newTid
? 0x08 : 0));
354 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
356 marshal_
.writeTid(&buf
, tid
);
361 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()),
364 switch (member
.get()->eTypeClass
) {
365 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
369 css::uno::TypeDescription(
371 typelib_InterfaceAttributeTypeDescription
* >(
377 case typelib_TypeClass_INTERFACE_METHOD
:
379 typelib_InterfaceMethodTypeDescription
* mtd
=
381 typelib_InterfaceMethodTypeDescription
* >(
384 &buf
, css::uno::TypeDescription(mtd
->pReturnTypeRef
),
386 std::vector
< BinaryAny
>::const_iterator
i(
387 outArguments
.begin());
388 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
) {
389 if (mtd
->pParams
[j
].bOut
) {
392 css::uno::TypeDescription(mtd
->pParams
[j
].pTypeRef
),
396 assert(i
== outArguments
.end());
400 assert(false); // this cannot happen
406 bridge_
->decrementCalls();
409 void Writer::sendMessage(std::vector
< unsigned char > const & buffer
) {
410 std::vector
< unsigned char > header
;
411 if (buffer
.size() > SAL_MAX_UINT32
) {
412 throw css::uno::RuntimeException(
413 "message too large for URP");
415 Marshal::write32(&header
, static_cast< sal_uInt32
>(buffer
.size()));
416 Marshal::write32(&header
, 1);
417 assert(!buffer
.empty());
418 unsigned char const * p
= buffer
.data();
419 std::vector
< unsigned char >::size_type n
= buffer
.size();
420 assert(header
.size() <= SAL_MAX_INT32
);
421 /*static_*/assert(SAL_MAX_INT32
<= std::numeric_limits
<std::size_t>::max());
422 std::size_t k
= SAL_MAX_INT32
- header
.size();
426 css::uno::Sequence
<sal_Int8
> s(header
.size() + k
);
427 assert(!header
.empty());
428 std::memcpy(s
.getArray(), header
.data(), header
.size());
430 std::memcpy(s
.getArray() + s
.getLength() - k
, p
, k
);
432 bridge_
->getConnection()->write(s
);
433 } catch (const css::io::IOException
& e
) {
434 css::uno::Any
exc(cppu::getCaughtException());
435 throw css::lang::WrappedTargetRuntimeException(
436 "Binary URP write raised IO exception: " + e
.Message
,
437 css::uno::Reference
< css::uno::XInterface
>(), exc
);
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */