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 "boost/scoped_ptr.hpp"
28 #include "com/sun/star/connection/XConnection.hpp"
29 #include "com/sun/star/io/IOException.hpp"
30 #include "com/sun/star/uno/Any.hxx"
31 #include "com/sun/star/uno/Exception.hpp"
32 #include "com/sun/star/uno/Reference.hxx"
33 #include "com/sun/star/uno/RuntimeException.hpp"
34 #include "com/sun/star/uno/Sequence.hxx"
35 #include "com/sun/star/uno/Type.hxx"
36 #include "com/sun/star/uno/XCurrentContext.hpp"
37 #include "com/sun/star/uno/XInterface.hpp"
38 #include "cppu/unotype.hxx"
39 #include "rtl/byteseq.h"
40 #include "rtl/ustring.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",
67 css::uno::Reference
< css::uno::XInterface
>());
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 (n
!= static_cast< sal_Int32
>(size
)) {
75 throw css::io::IOException(
76 "binaryurp::Reader: premature end of input",
77 css::uno::Reference
< css::uno::XInterface
>());
79 assert(buf
.getLength() == static_cast< sal_Int32
>(size
));
83 extern "C" void SAL_CALL
request(void * pThreadSpecificData
) {
84 assert(pThreadSpecificData
!= 0);
85 boost::scoped_ptr
< IncomingRequest
>(
86 static_cast< IncomingRequest
* >(pThreadSpecificData
))->
92 Reader::Reader(rtl::Reference
< Bridge
> const & bridge
):
93 Thread("binaryurpReader"), bridge_(bridge
)
100 void Reader::execute() {
102 bridge_
->sendRequestChangeRequest();
103 css::uno::Reference
< css::connection::XConnection
> con(
104 bridge_
->getConnection());
106 css::uno::Sequence
< sal_Int8
> s(read(con
, 8, true));
107 if (s
.getLength() == 0) {
110 Unmarshal
header(bridge_
, state_
, s
);
111 sal_uInt32 size
= header
.read32();
112 sal_uInt32 count
= header
.read32();
115 throw css::io::IOException(
116 "binaryurp::Reader: block with zero message count received",
117 css::uno::Reference
< css::uno::XInterface
>());
119 Unmarshal
block(bridge_
, state_
, read(con
, size
, false));
120 for (sal_uInt32 i
= 0; i
!= count
; ++i
) {
125 } catch (const css::uno::Exception
& e
) {
126 SAL_WARN("binaryurp", "caught UNO exception '" << e
.Message
<< '\'');
127 } catch (const std::exception
& e
) {
128 SAL_WARN("binaryurp", "caught C++ exception '" << e
.what() << '\'');
130 bridge_
->terminate(false);
134 void Reader::readMessage(Unmarshal
& unmarshal
) {
135 sal_uInt8 flags1
= unmarshal
.read8();
139 bool forceSynchronous
;
140 sal_uInt16 functionId
;
141 if ((flags1
& 0x80) != 0) { // bit 7: LONGHEADER
142 if ((flags1
& 0x40) == 0) { // bit 6: REQUEST
143 readReplyMessage(unmarshal
, flags1
);
146 newType
= (flags1
& 0x20) != 0; // bit 5: NEWTYPE
147 newOid
= (flags1
& 0x10) != 0; // bit 4: NEWOID
148 newTid
= (flags1
& 0x08) != 0; // bit 3: NEWTID
149 if ((flags1
& 0x01) != 0) { // bit 0: MOREFLAGSS
150 sal_uInt8 flags2
= unmarshal
.read8();
151 forceSynchronous
= (flags2
& 0x80) != 0; // bit 7: MUSTREPLY
152 if (((flags2
& 0x40) != 0) != forceSynchronous
) {
153 // bit 6: SYNCHRONOUS
154 throw css::uno::RuntimeException(
155 ("URP: request message with MUSTREPLY != SYNCHRONOUS"
157 css::uno::Reference
< css::uno::XInterface
>());
160 forceSynchronous
= false;
162 functionId
= ((flags1
& 0x04) != 0) // bit 2: FUNCTIONID16
163 ? unmarshal
.read16() : unmarshal
.read8();
168 forceSynchronous
= false;
169 functionId
= ((flags1
& 0x40) != 0) // bit 6: FUNCTIONID14
170 ? ((flags1
& 0x3F) << 8) | unmarshal
.read8() : flags1
& 0x3F;
172 css::uno::TypeDescription type
;
174 type
= unmarshal
.readType();
177 if (!lastType_
.is()) {
178 throw css::uno::RuntimeException(
179 ("URP: request message with NEWTYPE received when last"
180 " interface type has not yet been set"),
181 css::uno::Reference
< css::uno::XInterface
>());
187 oid
= unmarshal
.readOid();
189 throw css::io::IOException(
190 "binaryurp::Unmarshal: emtpy OID",
191 css::uno::Reference
< css::uno::XInterface
>());
195 if (lastOid_
.isEmpty()) {
196 throw css::uno::RuntimeException(
197 ("URP: request message with NEWOID received when last OID has"
198 " not yet been set"),
199 css::uno::Reference
< css::uno::XInterface
>());
203 rtl::ByteSequence
tid(getTid(unmarshal
, newTid
));
206 if (type
.get()->eTypeClass
!= typelib_TypeClass_INTERFACE
) {
207 throw css::uno::RuntimeException(
208 "URP: request message with non-interface interface type received",
209 css::uno::Reference
< css::uno::XInterface
>());
211 typelib_InterfaceTypeDescription
* itd
=
212 reinterpret_cast< typelib_InterfaceTypeDescription
* >(type
.get());
213 if (functionId
>= itd
->nMapFunctionIndexToMemberIndex
) {
214 throw css::uno::RuntimeException(
215 "URP: request message with unknown function ID received",
216 css::uno::Reference
< css::uno::XInterface
>());
218 sal_Int32 memberId
= itd
->pMapFunctionIndexToMemberIndex
[functionId
];
219 css::uno::TypeDescription
memberTd(itd
->ppAllMembers
[memberId
]);
220 memberTd
.makeComplete();
221 assert(memberTd
.is());
222 bool protProps
= bridge_
->isProtocolPropertiesRequest(oid
, type
);
223 bool ccMode
= !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
&&
224 bridge_
->isCurrentContextMode();
225 css::uno::UnoInterfaceReference cc
;
227 css::uno::TypeDescription
t(
228 cppu::UnoType
< css::uno::Reference
< css::uno::XCurrentContext
> >::
231 *static_cast< uno_Interface
** >(
232 unmarshal
.readValue(t
).getValue(t
)));
235 if (memberTd
.get()->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
&&
236 (reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
240 synchronous
= forceSynchronous
;
243 forceSynchronous
, "binaryurp",
244 ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
245 " non-oneway function ID"));
249 std::vector
< BinaryAny
> inArgs
;
250 switch (memberTd
.get()->eTypeClass
) {
251 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
252 setter
= itd
->pMapMemberIndexToFunctionIndex
[memberId
] != functionId
;
253 // pMapMemberIndexToFunctionIndex contains function index of
258 css::uno::TypeDescription(
260 typelib_InterfaceAttributeTypeDescription
* >(
262 pAttributeTypeRef
)));
265 case typelib_TypeClass_INTERFACE_METHOD
:
267 typelib_InterfaceMethodTypeDescription
* mtd
=
268 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
270 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
271 if (mtd
->pParams
[i
].bIn
) {
274 css::uno::TypeDescription(
275 mtd
->pParams
[i
].pTypeRef
)));
281 assert(false); // this cannot happen
284 bridge_
->incrementCalls(
285 !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
);
287 switch (functionId
) {
288 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE
:
289 bridge_
->handleRequestChangeRequest(tid
, inArgs
);
291 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE
:
292 bridge_
->handleCommitChangeRequest(tid
, inArgs
);
295 throw css::uno::RuntimeException(
296 ("URP: request message with UrpProtocolProperties OID and"
297 " unknown function ID received"),
298 css::uno::Reference
< css::uno::XInterface
>());
301 css::uno::UnoInterfaceReference obj
;
302 switch (functionId
) {
303 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE
:
304 obj
= bridge_
->findStub(oid
, type
);
308 && inArgs
[0].getType().equals(
309 css::uno::TypeDescription(
310 cppu::UnoType
< css::uno::Type
>::get())));
312 css::uno::TypeDescription(
315 css::uno::XInterface
> >::get()))
316 && (css::uno::TypeDescription(
318 typelib_TypeDescriptionReference
** >(
319 inArgs
[0].getValue(inArgs
[0].getType()))).
321 css::uno::TypeDescription(
324 css::uno::XInterface
> >::get())))))
326 throw css::uno::RuntimeException(
327 ("URP: queryInterface request message with unknown OID"
329 css::uno::Reference
< css::uno::XInterface
>());
333 case SPECIAL_FUNCTION_ID_RESERVED
:
334 throw css::uno::RuntimeException(
335 "URP: request message with unknown function ID 1 received",
336 css::uno::Reference
< css::uno::XInterface
>());
337 case SPECIAL_FUNCTION_ID_RELEASE
:
340 obj
= bridge_
->findStub(oid
, type
);
342 throw css::uno::RuntimeException(
343 "URP: request message with unknown OID received",
344 css::uno::Reference
< css::uno::XInterface
>());
348 SAL_WNODEPRECATED_DECLARATIONS_PUSH
349 std::auto_ptr
< IncomingRequest
> req(
351 bridge_
, tid
, oid
, obj
, type
, functionId
, synchronous
, memberTd
,
352 setter
, inArgs
, ccMode
, cc
));
353 SAL_WNODEPRECATED_DECLARATIONS_POP
355 bridge_
->incrementActiveCalls();
357 uno_threadpool_putJob(
358 bridge_
->getThreadPool(), tid
.getHandle(), req
.get(), &request
,
364 void Reader::readReplyMessage(Unmarshal
& unmarshal
, sal_uInt8 flags1
) {
365 rtl::ByteSequence
tid(getTid(unmarshal
, (flags1
& 0x08) != 0));
368 OutgoingRequest
req(bridge_
->lastOutgoingRequest(tid
));
369 bool exc
= (flags1
& 0x20) != 0; // bit 5: EXCEPTION
371 std::vector
< BinaryAny
> outArgs
;
373 ret
= unmarshal
.readValue(
374 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()));
375 if (!typelib_typedescription_isAssignableFrom(
376 (css::uno::TypeDescription(
377 cppu::UnoType
< css::uno::RuntimeException
>::get()).
379 ret
.getType().get()))
382 typelib_TypeDescriptionReference
** p
= 0;
383 switch (req
.member
.get()->eTypeClass
) {
384 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
386 typelib_InterfaceAttributeTypeDescription
* atd
=
388 typelib_InterfaceAttributeTypeDescription
* >(
390 n
= req
.setter
? atd
->nSetExceptions
: atd
->nGetExceptions
;
392 ? atd
->ppSetExceptions
: atd
->ppGetExceptions
;
395 case typelib_TypeClass_INTERFACE_METHOD
:
397 typelib_InterfaceMethodTypeDescription
* mtd
=
399 typelib_InterfaceMethodTypeDescription
* >(
401 n
= mtd
->nExceptions
;
402 p
= mtd
->ppExceptions
;
406 assert(false); // this cannot happen
410 for (sal_Int32 i
= 0; i
!= n
; ++i
) {
411 if (typelib_typedescriptionreference_isAssignableFrom(
413 reinterpret_cast< typelib_TypeDescriptionReference
* >(
414 ret
.getType().get())))
421 throw css::uno::RuntimeException(
422 "URP: reply message with bad exception type received",
423 css::uno::Reference
< css::uno::XInterface
>());
427 switch (req
.member
.get()->eTypeClass
) {
428 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
430 ret
= unmarshal
.readValue(
431 css::uno::TypeDescription(
433 typelib_InterfaceAttributeTypeDescription
* >(
438 case typelib_TypeClass_INTERFACE_METHOD
:
440 typelib_InterfaceMethodTypeDescription
* mtd
=
442 typelib_InterfaceMethodTypeDescription
* >(
444 ret
= unmarshal
.readValue(
445 css::uno::TypeDescription(mtd
->pReturnTypeRef
));
446 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
447 if (mtd
->pParams
[i
].bOut
) {
450 css::uno::TypeDescription(
451 mtd
->pParams
[i
].pTypeRef
)));
457 assert(false); // this cannot happen
462 case OutgoingRequest::KIND_NORMAL
:
464 SAL_WNODEPRECATED_DECLARATIONS_PUSH
465 std::auto_ptr
< IncomingReply
> resp(
466 new IncomingReply(exc
, ret
, outArgs
));
467 SAL_WNODEPRECATED_DECLARATIONS_POP
468 uno_threadpool_putJob(
469 bridge_
->getThreadPool(), tid
.getHandle(), resp
.get(), 0,
474 case OutgoingRequest::KIND_REQUEST_CHANGE
:
475 assert(outArgs
.empty());
476 bridge_
->handleRequestChangeReply(exc
, ret
);
478 case OutgoingRequest::KIND_COMMIT_CHANGE
:
479 assert(outArgs
.empty());
480 bridge_
->handleCommitChangeReply(exc
, ret
);
483 assert(false); // this cannot happen
488 rtl::ByteSequence
Reader::getTid(Unmarshal
& unmarshal
, bool newTid
) const {
490 return unmarshal
.readTid();
492 if (lastTid_
.getLength() == 0) {
493 throw css::uno::RuntimeException(
494 ("URP: message with NEWTID received when last TID has not yet been"
496 css::uno::Reference
< css::uno::XInterface
>());
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */