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);
133 void Reader::readMessage(Unmarshal
& unmarshal
) {
134 sal_uInt8 flags1
= unmarshal
.read8();
138 bool forceSynchronous
;
139 sal_uInt16 functionId
;
140 if ((flags1
& 0x80) != 0) { // bit 7: LONGHEADER
141 if ((flags1
& 0x40) == 0) { // bit 6: REQUEST
142 readReplyMessage(unmarshal
, flags1
);
145 newType
= (flags1
& 0x20) != 0; // bit 5: NEWTYPE
146 newOid
= (flags1
& 0x10) != 0; // bit 4: NEWOID
147 newTid
= (flags1
& 0x08) != 0; // bit 3: NEWTID
148 if ((flags1
& 0x01) != 0) { // bit 0: MOREFLAGSS
149 sal_uInt8 flags2
= unmarshal
.read8();
150 forceSynchronous
= (flags2
& 0x80) != 0; // bit 7: MUSTREPLY
151 if (((flags2
& 0x40) != 0) != forceSynchronous
) {
152 // bit 6: SYNCHRONOUS
153 throw css::uno::RuntimeException(
154 ("URP: request message with MUSTREPLY != SYNCHRONOUS"
156 css::uno::Reference
< css::uno::XInterface
>());
159 forceSynchronous
= false;
161 functionId
= ((flags1
& 0x04) != 0) // bit 2: FUNCTIONID16
162 ? unmarshal
.read16() : unmarshal
.read8();
167 forceSynchronous
= false;
168 functionId
= ((flags1
& 0x40) != 0) // bit 6: FUNCTIONID14
169 ? ((flags1
& 0x3F) << 8) | unmarshal
.read8() : flags1
& 0x3F;
171 css::uno::TypeDescription type
;
173 type
= unmarshal
.readType();
176 if (!lastType_
.is()) {
177 throw css::uno::RuntimeException(
178 ("URP: request message with NEWTYPE received when last"
179 " interface type has not yet been set"),
180 css::uno::Reference
< css::uno::XInterface
>());
186 oid
= unmarshal
.readOid();
188 throw css::io::IOException(
189 "binaryurp::Unmarshal: emtpy OID",
190 css::uno::Reference
< css::uno::XInterface
>());
194 if (lastOid_
.isEmpty()) {
195 throw css::uno::RuntimeException(
196 ("URP: request message with NEWOID received when last OID has"
197 " not yet been set"),
198 css::uno::Reference
< css::uno::XInterface
>());
202 rtl::ByteSequence
tid(getTid(unmarshal
, newTid
));
205 if (type
.get()->eTypeClass
!= typelib_TypeClass_INTERFACE
) {
206 throw css::uno::RuntimeException(
207 "URP: request message with non-interface interface type received",
208 css::uno::Reference
< css::uno::XInterface
>());
210 typelib_InterfaceTypeDescription
* itd
=
211 reinterpret_cast< typelib_InterfaceTypeDescription
* >(type
.get());
212 if (functionId
>= itd
->nMapFunctionIndexToMemberIndex
) {
213 throw css::uno::RuntimeException(
214 "URP: request message with unknown function ID received",
215 css::uno::Reference
< css::uno::XInterface
>());
217 sal_Int32 memberId
= itd
->pMapFunctionIndexToMemberIndex
[functionId
];
218 css::uno::TypeDescription
memberTd(itd
->ppAllMembers
[memberId
]);
219 memberTd
.makeComplete();
220 assert(memberTd
.is());
221 bool protProps
= bridge_
->isProtocolPropertiesRequest(oid
, type
);
222 bool ccMode
= !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
&&
223 bridge_
->isCurrentContextMode();
224 css::uno::UnoInterfaceReference cc
;
226 css::uno::TypeDescription
t(
227 cppu::UnoType
< css::uno::Reference
< css::uno::XCurrentContext
> >::
230 *static_cast< uno_Interface
** >(
231 unmarshal
.readValue(t
).getValue(t
)));
234 if (memberTd
.get()->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
&&
235 (reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
239 synchronous
= forceSynchronous
;
241 if (forceSynchronous
) {
242 throw css::uno::RuntimeException(
243 ("URP: synchronous request message with non-oneway function ID"
245 css::uno::Reference
< css::uno::XInterface
>());
250 std::vector
< BinaryAny
> inArgs
;
251 switch (memberTd
.get()->eTypeClass
) {
252 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
253 setter
= itd
->pMapMemberIndexToFunctionIndex
[memberId
] != functionId
;
254 // pMapMemberIndexToFunctionIndex contains function index of
259 css::uno::TypeDescription(
261 typelib_InterfaceAttributeTypeDescription
* >(
263 pAttributeTypeRef
)));
266 case typelib_TypeClass_INTERFACE_METHOD
:
268 typelib_InterfaceMethodTypeDescription
* mtd
=
269 reinterpret_cast< typelib_InterfaceMethodTypeDescription
* >(
271 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
272 if (mtd
->pParams
[i
].bIn
) {
275 css::uno::TypeDescription(
276 mtd
->pParams
[i
].pTypeRef
)));
282 assert(false); // this cannot happen
285 bridge_
->incrementCalls(
286 !protProps
&& functionId
!= SPECIAL_FUNCTION_ID_RELEASE
);
288 switch (functionId
) {
289 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE
:
290 bridge_
->handleRequestChangeRequest(tid
, inArgs
);
292 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE
:
293 bridge_
->handleCommitChangeRequest(tid
, inArgs
);
296 throw css::uno::RuntimeException(
297 ("URP: request message with UrpProtocolProperties OID and"
298 " unknown function ID received"),
299 css::uno::Reference
< css::uno::XInterface
>());
302 css::uno::UnoInterfaceReference obj
;
303 switch (functionId
) {
304 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE
:
305 obj
= bridge_
->findStub(oid
, type
);
309 && inArgs
[0].getType().equals(
310 css::uno::TypeDescription(
311 cppu::UnoType
< css::uno::Type
>::get())));
313 css::uno::TypeDescription(
316 css::uno::XInterface
> >::get()))
317 && (css::uno::TypeDescription(
319 typelib_TypeDescriptionReference
** >(
320 inArgs
[0].getValue(inArgs
[0].getType()))).
322 css::uno::TypeDescription(
325 css::uno::XInterface
> >::get())))))
327 throw css::uno::RuntimeException(
328 ("URP: queryInterface request message with unknown OID"
330 css::uno::Reference
< css::uno::XInterface
>());
334 case SPECIAL_FUNCTION_ID_RESERVED
:
335 throw css::uno::RuntimeException(
336 "URP: request message with unknown function ID 1 received",
337 css::uno::Reference
< css::uno::XInterface
>());
338 case SPECIAL_FUNCTION_ID_RELEASE
:
341 obj
= bridge_
->findStub(oid
, type
);
343 throw css::uno::RuntimeException(
344 "URP: request message with unknown OID received",
345 css::uno::Reference
< css::uno::XInterface
>());
349 SAL_WNODEPRECATED_DECLARATIONS_PUSH
350 std::auto_ptr
< IncomingRequest
> req(
352 bridge_
, tid
, oid
, obj
, type
, functionId
, synchronous
, memberTd
,
353 setter
, inArgs
, ccMode
, cc
));
354 SAL_WNODEPRECATED_DECLARATIONS_POP
356 bridge_
->incrementActiveCalls();
358 uno_threadpool_putJob(
359 bridge_
->getThreadPool(), tid
.getHandle(), req
.get(), &request
,
365 void Reader::readReplyMessage(Unmarshal
& unmarshal
, sal_uInt8 flags1
) {
366 rtl::ByteSequence
tid(getTid(unmarshal
, (flags1
& 0x08) != 0));
369 OutgoingRequest
req(bridge_
->lastOutgoingRequest(tid
));
370 bool exc
= (flags1
& 0x20) != 0; // bit 5: EXCEPTION
372 std::vector
< BinaryAny
> outArgs
;
374 ret
= unmarshal
.readValue(
375 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()));
376 if (!typelib_typedescription_isAssignableFrom(
377 (css::uno::TypeDescription(
378 cppu::UnoType
< css::uno::RuntimeException
>::get()).
380 ret
.getType().get()))
383 typelib_TypeDescriptionReference
** p
= 0;
384 switch (req
.member
.get()->eTypeClass
) {
385 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
387 typelib_InterfaceAttributeTypeDescription
* atd
=
389 typelib_InterfaceAttributeTypeDescription
* >(
391 n
= req
.setter
? atd
->nSetExceptions
: atd
->nGetExceptions
;
393 ? atd
->ppSetExceptions
: atd
->ppGetExceptions
;
396 case typelib_TypeClass_INTERFACE_METHOD
:
398 typelib_InterfaceMethodTypeDescription
* mtd
=
400 typelib_InterfaceMethodTypeDescription
* >(
402 n
= mtd
->nExceptions
;
403 p
= mtd
->ppExceptions
;
407 assert(false); // this cannot happen
411 for (sal_Int32 i
= 0; i
!= n
; ++i
) {
412 if (typelib_typedescriptionreference_isAssignableFrom(
414 reinterpret_cast< typelib_TypeDescriptionReference
* >(
415 ret
.getType().get())))
422 throw css::uno::RuntimeException(
423 "URP: reply message with bad exception type received",
424 css::uno::Reference
< css::uno::XInterface
>());
428 switch (req
.member
.get()->eTypeClass
) {
429 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
431 ret
= unmarshal
.readValue(
432 css::uno::TypeDescription(
434 typelib_InterfaceAttributeTypeDescription
* >(
439 case typelib_TypeClass_INTERFACE_METHOD
:
441 typelib_InterfaceMethodTypeDescription
* mtd
=
443 typelib_InterfaceMethodTypeDescription
* >(
445 ret
= unmarshal
.readValue(
446 css::uno::TypeDescription(mtd
->pReturnTypeRef
));
447 for (sal_Int32 i
= 0; i
!= mtd
->nParams
; ++i
) {
448 if (mtd
->pParams
[i
].bOut
) {
451 css::uno::TypeDescription(
452 mtd
->pParams
[i
].pTypeRef
)));
458 assert(false); // this cannot happen
463 case OutgoingRequest::KIND_NORMAL
:
465 SAL_WNODEPRECATED_DECLARATIONS_PUSH
466 std::auto_ptr
< IncomingReply
> resp(
467 new IncomingReply(exc
, ret
, outArgs
));
468 SAL_WNODEPRECATED_DECLARATIONS_POP
469 uno_threadpool_putJob(
470 bridge_
->getThreadPool(), tid
.getHandle(), resp
.get(), 0,
475 case OutgoingRequest::KIND_REQUEST_CHANGE
:
476 assert(outArgs
.empty());
477 bridge_
->handleRequestChangeReply(exc
, ret
);
479 case OutgoingRequest::KIND_COMMIT_CHANGE
:
480 assert(outArgs
.empty());
481 bridge_
->handleCommitChangeReply(exc
, ret
);
484 assert(false); // this cannot happen
489 rtl::ByteSequence
Reader::getTid(Unmarshal
& unmarshal
, bool newTid
) const {
491 return unmarshal
.readTid();
493 if (lastTid_
.getLength() == 0) {
494 throw css::uno::RuntimeException(
495 ("URP: message with NEWTID received when last TID has not yet been"
497 css::uno::Reference
< css::uno::XInterface
>());
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */