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 <rtl/byteseq.h>
39 #include <rtl/ustring.hxx>
40 #include <sal/log.hxx>
41 #include <sal/types.h>
42 #include <typelib/typeclass.h>
43 #include <typelib/typedescription.h>
44 #include <typelib/typedescription.hxx>
46 #include "binaryany.hxx"
48 #include "incomingreply.hxx"
49 #include "incomingrequest.hxx"
50 #include "outgoingrequest.hxx"
52 #include "specialfunctionids.hxx"
53 #include "unmarshal.hxx"
59 css::uno::Sequence
< sal_Int8
> read(
60 css::uno::Reference
< css::connection::XConnection
> const & connection
,
61 sal_uInt32 size
, bool eofOk
)
63 assert(connection
.is());
64 if (size
> SAL_MAX_INT32
) {
65 throw css::uno::RuntimeException(
66 "binaryurp::Reader: block size too large");
68 css::uno::Sequence
< sal_Int8
> buf
;
69 sal_Int32 n
= connection
->read(buf
, static_cast< sal_Int32
>(size
));
70 if (n
== 0 && eofOk
) {
71 return css::uno::Sequence
< sal_Int8
>();
73 if (n
!= static_cast< sal_Int32
>(size
)) {
74 throw css::io::IOException(
75 "binaryurp::Reader: premature end of input");
77 assert(buf
.getLength() == static_cast< sal_Int32
>(size
));
81 extern "C" void request(void * pThreadSpecificData
) {
82 assert(pThreadSpecificData
!= nullptr);
83 std::unique_ptr
< IncomingRequest
>(
84 static_cast< IncomingRequest
* >(pThreadSpecificData
))->
90 Reader::Reader(rtl::Reference
< Bridge
> const & bridge
):
91 Thread("binaryurpReader"), bridge_(bridge
)
98 void Reader::execute() {
100 bridge_
->sendRequestChangeRequest();
101 css::uno::Reference
< css::connection::XConnection
> con(
102 bridge_
->getConnection());
104 css::uno::Sequence
< sal_Int8
> s(read(con
, 8, true));
105 if (!s
.hasElements()) {
108 Unmarshal
header(bridge_
, state_
, s
);
109 sal_uInt32 size
= header
.read32();
110 sal_uInt32 count
= header
.read32();
113 throw css::io::IOException(
114 "binaryurp::Reader: block with zero message count received");
116 Unmarshal
block(bridge_
, state_
, read(con
, size
, false));
117 for (sal_uInt32 i
= 0; i
!= count
; ++i
) {
122 } catch (const css::uno::Exception
& e
) {
123 SAL_WARN("binaryurp", "caught UNO exception '" << e
<< '\'');
124 } catch (const std::exception
& e
) {
125 SAL_WARN("binaryurp", "caught C++ exception '" << e
.what() << '\'');
127 bridge_
->terminate(false);
131 void Reader::readMessage(Unmarshal
& unmarshal
) {
132 sal_uInt8 flags1
= unmarshal
.read8();
136 bool forceSynchronous
;
137 sal_uInt16 functionId
;
138 if ((flags1
& 0x80) != 0) { // bit 7: LONGHEADER
139 if ((flags1
& 0x40) == 0) { // bit 6: REQUEST
140 readReplyMessage(unmarshal
, flags1
);
143 newType
= (flags1
& 0x20) != 0; // bit 5: NEWTYPE
144 newOid
= (flags1
& 0x10) != 0; // bit 4: NEWOID
145 newTid
= (flags1
& 0x08) != 0; // bit 3: NEWTID
146 if ((flags1
& 0x01) != 0) { // bit 0: MOREFLAGSS
147 sal_uInt8 flags2
= unmarshal
.read8();
148 forceSynchronous
= (flags2
& 0x80) != 0; // bit 7: MUSTREPLY
149 if (((flags2
& 0x40) != 0) != forceSynchronous
) {
150 // bit 6: SYNCHRONOUS
151 throw css::uno::RuntimeException(
152 "URP: request message with MUSTREPLY != SYNCHRONOUS"
156 forceSynchronous
= false;
158 functionId
= ((flags1
& 0x04) != 0) // bit 2: FUNCTIONID16
159 ? unmarshal
.read16() : unmarshal
.read8();
164 forceSynchronous
= false;
165 functionId
= ((flags1
& 0x40) != 0) // bit 6: FUNCTIONID14
166 ? ((flags1
& 0x3F) << 8) | unmarshal
.read8() : flags1
& 0x3F;
168 css::uno::TypeDescription type
;
170 type
= unmarshal
.readType();
173 if (!lastType_
.is()) {
174 throw css::uno::RuntimeException(
175 "URP: request message with NEWTYPE received when last"
176 " interface type has not yet been set");
182 oid
= unmarshal
.readOid();
184 throw css::io::IOException(
185 "binaryurp::Unmarshal: empty OID");
189 if (lastOid_
.isEmpty()) {
190 throw css::uno::RuntimeException(
191 "URP: request message with NEWOID received when last OID has"
192 " not yet been set");
196 rtl::ByteSequence
tid(getTid(unmarshal
, newTid
));
199 if (type
.get()->eTypeClass
!= typelib_TypeClass_INTERFACE
) {
200 throw css::uno::RuntimeException(
201 "URP: request message with non-interface interface type received");
203 typelib_InterfaceTypeDescription
* itd
=
204 reinterpret_cast< typelib_InterfaceTypeDescription
* >(type
.get());
205 if (functionId
>= itd
->nMapFunctionIndexToMemberIndex
) {
206 throw css::uno::RuntimeException(
207 "URP: request message with unknown function ID received");
209 sal_Int32 memberId
= itd
->pMapFunctionIndexToMemberIndex
[functionId
];
210 css::uno::TypeDescription
memberTd(itd
->ppAllMembers
[memberId
]);
211 memberTd
.makeComplete();
212 assert(memberTd
.is());
213 bool protProps
= bridge_
->isProtocolPropertiesRequest(oid
, type
);
214 bool ccMode
= !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
&&
215 bridge_
->isCurrentContextMode();
216 css::uno::UnoInterfaceReference cc
;
218 css::uno::TypeDescription
t(
219 cppu::UnoType
<css::uno::XCurrentContext
>::get());
221 *static_cast< uno_Interface
** >(
222 unmarshal
.readValue(t
).getValue(t
)));
225 memberTd
.get()->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
&&
226 (reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
230 !oneWay
&& forceSynchronous
, "binaryurp",
231 ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
232 " non-oneway function ID"));
233 bool synchronous
= !oneWay
|| forceSynchronous
;
234 bool bSetter
= false;
235 std::vector
< BinaryAny
> inArgs
;
236 switch (memberTd
.get()->eTypeClass
) {
237 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
238 bSetter
= itd
->pMapMemberIndexToFunctionIndex
[memberId
] != functionId
;
239 // pMapMemberIndexToFunctionIndex contains function index of
244 css::uno::TypeDescription(
246 typelib_InterfaceAttributeTypeDescription
* >(
248 pAttributeTypeRef
)));
251 case typelib_TypeClass_INTERFACE_METHOD
:
253 typelib_InterfaceMethodTypeDescription
* mtd
=
254 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
256 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
257 if (mtd
->pParams
[i
].bIn
) {
260 css::uno::TypeDescription(
261 mtd
->pParams
[i
].pTypeRef
)));
267 assert(false); // this cannot happen
270 bridge_
->incrementCalls(
271 !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
);
273 switch (functionId
) {
274 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE
:
275 bridge_
->handleRequestChangeRequest(tid
, inArgs
);
277 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE
:
278 bridge_
->handleCommitChangeRequest(tid
, inArgs
);
281 throw css::uno::RuntimeException(
282 "URP: request message with UrpProtocolProperties OID and"
283 " unknown function ID received");
286 css::uno::UnoInterfaceReference obj
;
287 switch (functionId
) {
288 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE
:
289 obj
= bridge_
->findStub(oid
, type
);
293 && inArgs
[0].getType().equals(
294 css::uno::TypeDescription(
295 cppu::UnoType
< css::uno::Type
>::get())));
297 css::uno::TypeDescription(
300 css::uno::XInterface
> >::get()))
301 && (css::uno::TypeDescription(
303 typelib_TypeDescriptionReference
** >(
304 inArgs
[0].getValue(inArgs
[0].getType()))).
306 css::uno::TypeDescription(
309 css::uno::XInterface
> >::get())))))
311 throw css::uno::RuntimeException(
312 "URP: queryInterface request message with unknown OID '"
313 + oid
+ "' received");
317 case SPECIAL_FUNCTION_ID_RESERVED
:
318 throw css::uno::RuntimeException(
319 "URP: request message with unknown function ID 1 received");
320 case SPECIAL_FUNCTION_ID_RELEASE
:
323 obj
= bridge_
->findStub(oid
, type
);
325 throw css::uno::RuntimeException(
326 "URP: request message with unknown OID received");
330 std::unique_ptr
< IncomingRequest
> req(
332 bridge_
, tid
, oid
, obj
, type
, functionId
, synchronous
, memberTd
,
333 bSetter
, inArgs
, ccMode
, cc
));
335 bridge_
->incrementActiveCalls();
337 uno_threadpool_putJob(
338 bridge_
->getThreadPool(), tid
.getHandle(), req
.get(), &request
,
344 void Reader::readReplyMessage(Unmarshal
& unmarshal
, sal_uInt8 flags1
) {
345 rtl::ByteSequence
tid(getTid(unmarshal
, (flags1
& 0x08) != 0));
348 OutgoingRequest
req(bridge_
->lastOutgoingRequest(tid
));
349 bool exc
= (flags1
& 0x20) != 0; // bit 5: EXCEPTION
351 std::vector
< BinaryAny
> outArgs
;
353 ret
= unmarshal
.readValue(
354 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()));
355 if (!typelib_typedescription_isAssignableFrom(
356 (css::uno::TypeDescription(
357 cppu::UnoType
< css::uno::RuntimeException
>::get()).
359 ret
.getType().get()))
362 typelib_TypeDescriptionReference
** p
= nullptr;
363 switch (req
.member
.get()->eTypeClass
) {
364 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
366 typelib_InterfaceAttributeTypeDescription
* atd
=
368 typelib_InterfaceAttributeTypeDescription
* >(
370 n
= req
.setter
? atd
->nSetExceptions
: atd
->nGetExceptions
;
372 ? atd
->ppSetExceptions
: atd
->ppGetExceptions
;
375 case typelib_TypeClass_INTERFACE_METHOD
:
377 typelib_InterfaceMethodTypeDescription
* mtd
=
379 typelib_InterfaceMethodTypeDescription
* >(
381 n
= mtd
->nExceptions
;
382 p
= mtd
->ppExceptions
;
386 assert(false); // this cannot happen
390 for (sal_Int32 i
= 0; i
!= n
; ++i
) {
391 if (typelib_typedescriptionreference_isAssignableFrom(
393 reinterpret_cast< typelib_TypeDescriptionReference
* >(
394 ret
.getType().get())))
401 throw css::uno::RuntimeException(
402 "URP: reply message with bad exception type received");
406 switch (req
.member
.get()->eTypeClass
) {
407 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
409 ret
= unmarshal
.readValue(
410 css::uno::TypeDescription(
412 typelib_InterfaceAttributeTypeDescription
* >(
417 case typelib_TypeClass_INTERFACE_METHOD
:
419 typelib_InterfaceMethodTypeDescription
* mtd
=
421 typelib_InterfaceMethodTypeDescription
* >(
423 ret
= unmarshal
.readValue(
424 css::uno::TypeDescription(mtd
->pReturnTypeRef
));
425 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
426 if (mtd
->pParams
[i
].bOut
) {
429 css::uno::TypeDescription(
430 mtd
->pParams
[i
].pTypeRef
)));
436 assert(false); // this cannot happen
441 case OutgoingRequest::KIND_NORMAL
:
443 std::unique_ptr
< IncomingReply
> resp(
444 new IncomingReply(exc
, ret
, outArgs
));
445 uno_threadpool_putJob(
446 bridge_
->getThreadPool(), tid
.getHandle(), resp
.get(), nullptr,
451 case OutgoingRequest::KIND_REQUEST_CHANGE
:
452 assert(outArgs
.empty());
453 bridge_
->handleRequestChangeReply(exc
, ret
);
455 case OutgoingRequest::KIND_COMMIT_CHANGE
:
456 assert(outArgs
.empty());
457 bridge_
->handleCommitChangeReply(exc
, ret
);
460 assert(false); // this cannot happen
465 rtl::ByteSequence
Reader::getTid(Unmarshal
& unmarshal
, bool newTid
) const {
467 return unmarshal
.readTid();
469 if (lastTid_
.getLength() == 0) {
470 throw css::uno::RuntimeException(
471 "URP: message with NEWTID received when last TID has not yet been"
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */