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>
27 #include <com/sun/star/connection/XConnection.hpp>
28 #include <com/sun/star/io/IOException.hpp>
29 #include <com/sun/star/uno/Any.hxx>
30 #include <com/sun/star/uno/Exception.hpp>
31 #include <com/sun/star/uno/Reference.hxx>
32 #include <com/sun/star/uno/RuntimeException.hpp>
33 #include <com/sun/star/uno/Sequence.hxx>
34 #include <com/sun/star/uno/Type.hxx>
35 #include <com/sun/star/uno/XCurrentContext.hpp>
36 #include <com/sun/star/uno/XInterface.hpp>
37 #include <cppu/unotype.hxx>
38 #include <o3tl/safeint.hxx>
39 #include <rtl/byteseq.h>
40 #include <rtl/ustring.hxx>
41 #include <sal/log.hxx>
42 #include <sal/types.h>
43 #include <typelib/typeclass.h>
44 #include <typelib/typedescription.h>
45 #include <typelib/typedescription.hxx>
47 #include "binaryany.hxx"
49 #include "incomingreply.hxx"
50 #include "incomingrequest.hxx"
51 #include "outgoingrequest.hxx"
53 #include "specialfunctionids.hxx"
54 #include "unmarshal.hxx"
60 css::uno::Sequence
< sal_Int8
> read(
61 css::uno::Reference
< css::connection::XConnection
> const & connection
,
62 sal_uInt32 size
, bool eofOk
)
64 assert(connection
.is());
65 if (size
> SAL_MAX_INT32
) {
66 throw css::uno::RuntimeException(
67 "binaryurp::Reader: block size too large");
69 css::uno::Sequence
< sal_Int8
> buf
;
70 sal_Int32 n
= connection
->read(buf
, static_cast< sal_Int32
>(size
));
71 if (n
== 0 && eofOk
) {
72 return css::uno::Sequence
< sal_Int8
>();
74 if (o3tl::make_unsigned(n
) != size
) {
75 throw css::io::IOException(
76 "binaryurp::Reader: premature end of input");
78 assert(o3tl::make_unsigned(buf
.getLength()) == size
);
82 extern "C" void request(void * pThreadSpecificData
) {
83 assert(pThreadSpecificData
!= nullptr);
84 std::unique_ptr
< IncomingRequest
>(
85 static_cast< IncomingRequest
* >(pThreadSpecificData
))->
91 Reader::Reader(rtl::Reference
< Bridge
> const & bridge
):
92 Thread("binaryurpReader"), bridge_(bridge
)
99 void Reader::execute() {
101 bridge_
->sendRequestChangeRequest();
102 css::uno::Reference
< css::connection::XConnection
> con(
103 bridge_
->getConnection());
105 css::uno::Sequence
< sal_Int8
> s(read(con
, 8, true));
106 if (!s
.hasElements()) {
109 Unmarshal
header(bridge_
, state_
, s
);
110 sal_uInt32 size
= header
.read32();
111 sal_uInt32 count
= header
.read32();
114 throw css::io::IOException(
115 "binaryurp::Reader: block with zero message count received");
117 Unmarshal
block(bridge_
, state_
, read(con
, size
, false));
118 for (sal_uInt32 i
= 0; i
!= count
; ++i
) {
123 } catch (const css::uno::Exception
& e
) {
124 SAL_WARN("binaryurp", "caught UNO exception '" << e
<< '\'');
125 } catch (const std::exception
& e
) {
126 SAL_WARN("binaryurp", "caught C++ exception '" << e
.what() << '\'');
128 bridge_
->terminate(false);
132 void Reader::readMessage(Unmarshal
& unmarshal
) {
133 sal_uInt8 flags1
= unmarshal
.read8();
137 bool forceSynchronous
;
138 sal_uInt16 functionId
;
139 if ((flags1
& 0x80) != 0) { // bit 7: LONGHEADER
140 if ((flags1
& 0x40) == 0) { // bit 6: REQUEST
141 readReplyMessage(unmarshal
, flags1
);
144 newType
= (flags1
& 0x20) != 0; // bit 5: NEWTYPE
145 newOid
= (flags1
& 0x10) != 0; // bit 4: NEWOID
146 newTid
= (flags1
& 0x08) != 0; // bit 3: NEWTID
147 if ((flags1
& 0x01) != 0) { // bit 0: MOREFLAGSS
148 sal_uInt8 flags2
= unmarshal
.read8();
149 forceSynchronous
= (flags2
& 0x80) != 0; // bit 7: MUSTREPLY
150 if (((flags2
& 0x40) != 0) != forceSynchronous
) {
151 // bit 6: SYNCHRONOUS
152 throw css::uno::RuntimeException(
153 "URP: request message with MUSTREPLY != SYNCHRONOUS"
157 forceSynchronous
= false;
159 functionId
= ((flags1
& 0x04) != 0) // bit 2: FUNCTIONID16
160 ? unmarshal
.read16() : unmarshal
.read8();
165 forceSynchronous
= false;
166 functionId
= ((flags1
& 0x40) != 0) // bit 6: FUNCTIONID14
167 ? ((flags1
& 0x3F) << 8) | unmarshal
.read8() : flags1
& 0x3F;
169 css::uno::TypeDescription type
;
171 type
= unmarshal
.readType();
174 if (!lastType_
.is()) {
175 throw css::uno::RuntimeException(
176 "URP: request message with NEWTYPE received when last"
177 " interface type has not yet been set");
183 oid
= unmarshal
.readOid();
185 throw css::io::IOException(
186 "binaryurp::Unmarshal: empty OID");
190 if (lastOid_
.isEmpty()) {
191 throw css::uno::RuntimeException(
192 "URP: request message with NEWOID received when last OID has"
193 " not yet been set");
197 rtl::ByteSequence
tid(getTid(unmarshal
, newTid
));
200 if (type
.get()->eTypeClass
!= typelib_TypeClass_INTERFACE
) {
201 throw css::uno::RuntimeException(
202 "URP: request message with non-interface interface type received");
204 typelib_InterfaceTypeDescription
* itd
=
205 reinterpret_cast< typelib_InterfaceTypeDescription
* >(type
.get());
206 if (functionId
>= itd
->nMapFunctionIndexToMemberIndex
) {
207 throw css::uno::RuntimeException(
208 "URP: request message with unknown function ID received");
210 sal_Int32 memberId
= itd
->pMapFunctionIndexToMemberIndex
[functionId
];
211 css::uno::TypeDescription
memberTd(itd
->ppAllMembers
[memberId
]);
212 memberTd
.makeComplete();
213 assert(memberTd
.is());
214 bool protProps
= bridge_
->isProtocolPropertiesRequest(oid
, type
);
215 bool ccMode
= !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
&&
216 bridge_
->isCurrentContextMode();
217 css::uno::UnoInterfaceReference cc
;
219 css::uno::TypeDescription
t(
220 cppu::UnoType
<css::uno::XCurrentContext
>::get());
222 *static_cast< uno_Interface
** >(
223 unmarshal
.readValue(t
).getValue(t
)));
226 memberTd
.get()->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
&&
227 (reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
231 !oneWay
&& forceSynchronous
, "binaryurp",
232 ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
233 " non-oneway function ID"));
234 bool synchronous
= !oneWay
|| forceSynchronous
;
235 bool bSetter
= false;
236 std::vector
< BinaryAny
> inArgs
;
237 switch (memberTd
.get()->eTypeClass
) {
238 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
239 bSetter
= itd
->pMapMemberIndexToFunctionIndex
[memberId
] != functionId
;
240 // pMapMemberIndexToFunctionIndex contains function index of
245 css::uno::TypeDescription(
247 typelib_InterfaceAttributeTypeDescription
* >(
249 pAttributeTypeRef
)));
252 case typelib_TypeClass_INTERFACE_METHOD
:
254 typelib_InterfaceMethodTypeDescription
* mtd
=
255 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
257 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
258 if (mtd
->pParams
[i
].bIn
) {
261 css::uno::TypeDescription(
262 mtd
->pParams
[i
].pTypeRef
)));
268 assert(false); // this cannot happen
271 bridge_
->incrementCalls(
272 !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
);
274 switch (functionId
) {
275 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE
:
276 bridge_
->handleRequestChangeRequest(tid
, inArgs
);
278 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE
:
279 bridge_
->handleCommitChangeRequest(tid
, inArgs
);
282 throw css::uno::RuntimeException(
283 "URP: request message with UrpProtocolProperties OID and"
284 " unknown function ID received");
287 css::uno::UnoInterfaceReference obj
;
288 switch (functionId
) {
289 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE
:
290 obj
= bridge_
->findStub(oid
, type
);
294 && inArgs
[0].getType().equals(
295 css::uno::TypeDescription(
296 cppu::UnoType
< css::uno::Type
>::get())));
298 css::uno::TypeDescription(
301 css::uno::XInterface
> >::get()))
302 && (css::uno::TypeDescription(
304 typelib_TypeDescriptionReference
** >(
305 inArgs
[0].getValue(inArgs
[0].getType()))).
307 css::uno::TypeDescription(
310 css::uno::XInterface
> >::get())))))
312 throw css::uno::RuntimeException(
313 "URP: queryInterface request message with unknown OID '"
314 + oid
+ "' received");
318 case SPECIAL_FUNCTION_ID_RESERVED
:
319 throw css::uno::RuntimeException(
320 "URP: request message with unknown function ID 1 received");
321 case SPECIAL_FUNCTION_ID_RELEASE
:
324 obj
= bridge_
->findStub(oid
, type
);
326 throw css::uno::RuntimeException(
327 "URP: request message with unknown OID received");
331 std::unique_ptr
< IncomingRequest
> req(
333 bridge_
, tid
, oid
, obj
, type
, functionId
, synchronous
, memberTd
,
334 bSetter
, std::move(inArgs
), ccMode
, cc
));
336 bridge_
->incrementActiveCalls();
338 uno_threadpool_putJob(
339 bridge_
->getThreadPool(), tid
.getHandle(), req
.get(), &request
,
341 // coverity[leaked_storage] - "request" destroys req when executed
346 void Reader::readReplyMessage(Unmarshal
& unmarshal
, sal_uInt8 flags1
) {
347 rtl::ByteSequence
tid(getTid(unmarshal
, (flags1
& 0x08) != 0));
350 OutgoingRequest
req(bridge_
->lastOutgoingRequest(tid
));
351 bool exc
= (flags1
& 0x20) != 0; // bit 5: EXCEPTION
353 std::vector
< BinaryAny
> outArgs
;
355 ret
= unmarshal
.readValue(
356 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()));
357 if (!typelib_typedescription_isAssignableFrom(
358 (css::uno::TypeDescription(
359 cppu::UnoType
< css::uno::RuntimeException
>::get()).
361 ret
.getType().get()))
364 typelib_TypeDescriptionReference
** p
= nullptr;
365 switch (req
.member
.get()->eTypeClass
) {
366 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
368 typelib_InterfaceAttributeTypeDescription
* atd
=
370 typelib_InterfaceAttributeTypeDescription
* >(
372 n
= req
.setter
? atd
->nSetExceptions
: atd
->nGetExceptions
;
374 ? atd
->ppSetExceptions
: atd
->ppGetExceptions
;
377 case typelib_TypeClass_INTERFACE_METHOD
:
379 typelib_InterfaceMethodTypeDescription
* mtd
=
381 typelib_InterfaceMethodTypeDescription
* >(
383 n
= mtd
->nExceptions
;
384 p
= mtd
->ppExceptions
;
388 assert(false); // this cannot happen
392 for (sal_Int32 i
= 0; i
!= n
; ++i
) {
393 if (typelib_typedescriptionreference_isAssignableFrom(
395 reinterpret_cast< typelib_TypeDescriptionReference
* >(
396 ret
.getType().get())))
403 throw css::uno::RuntimeException(
404 "URP: reply message with bad exception type received");
408 switch (req
.member
.get()->eTypeClass
) {
409 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
411 ret
= unmarshal
.readValue(
412 css::uno::TypeDescription(
414 typelib_InterfaceAttributeTypeDescription
* >(
419 case typelib_TypeClass_INTERFACE_METHOD
:
421 typelib_InterfaceMethodTypeDescription
* mtd
=
423 typelib_InterfaceMethodTypeDescription
* >(
425 ret
= unmarshal
.readValue(
426 css::uno::TypeDescription(mtd
->pReturnTypeRef
));
427 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
428 if (mtd
->pParams
[i
].bOut
) {
431 css::uno::TypeDescription(
432 mtd
->pParams
[i
].pTypeRef
)));
438 assert(false); // this cannot happen
443 case OutgoingRequest::KIND_NORMAL
:
445 std::unique_ptr
< IncomingReply
> resp(
446 new IncomingReply(exc
, ret
, std::move(outArgs
)));
447 uno_threadpool_putJob(
448 bridge_
->getThreadPool(), tid
.getHandle(), resp
.get(), nullptr,
450 // coverity[leaked_storage] - "Bridge::makeCall" destroys resp when received
454 case OutgoingRequest::KIND_REQUEST_CHANGE
:
455 assert(outArgs
.empty());
456 bridge_
->handleRequestChangeReply(exc
, ret
);
458 case OutgoingRequest::KIND_COMMIT_CHANGE
:
459 assert(outArgs
.empty());
460 bridge_
->handleCommitChangeReply(exc
, ret
);
463 assert(false); // this cannot happen
468 rtl::ByteSequence
Reader::getTid(Unmarshal
& unmarshal
, bool newTid
) const {
470 return unmarshal
.readTid();
472 if (lastTid_
.getLength() == 0) {
473 throw css::uno::RuntimeException(
474 "URP: message with NEWTID received when last TID has not yet been"
482 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */