fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / binaryurp / source / reader.cxx
blob331e4b333465f3efb83570755f503ecd88a8c819
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <cassert>
23 #include <exception>
24 #include <memory>
25 #include <vector>
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"
47 #include "bridge.hxx"
48 #include "incomingreply.hxx"
49 #include "incomingrequest.hxx"
50 #include "outgoingrequest.hxx"
51 #include "reader.hxx"
52 #include "specialfunctionids.hxx"
53 #include "unmarshal.hxx"
55 namespace binaryurp {
57 namespace {
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));
80 return buf;
83 extern "C" void SAL_CALL request(void * pThreadSpecificData) {
84 assert(pThreadSpecificData != 0);
85 boost::scoped_ptr< IncomingRequest >(
86 static_cast< IncomingRequest * >(pThreadSpecificData))->
87 execute();
92 Reader::Reader(rtl::Reference< Bridge > const & bridge):
93 Thread("binaryurpReader"), bridge_(bridge)
95 assert(bridge.is());
98 Reader::~Reader() {}
100 void Reader::execute() {
101 try {
102 bridge_->sendRequestChangeRequest();
103 css::uno::Reference< css::connection::XConnection > con(
104 bridge_->getConnection());
105 for (;;) {
106 css::uno::Sequence< sal_Int8 > s(read(con, 8, true));
107 if (s.getLength() == 0) {
108 break;
110 Unmarshal header(bridge_, state_, s);
111 sal_uInt32 size = header.read32();
112 sal_uInt32 count = header.read32();
113 header.done();
114 if (count == 0) {
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) {
121 readMessage(block);
123 block.done();
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);
131 bridge_.clear();
134 void Reader::readMessage(Unmarshal & unmarshal) {
135 sal_uInt8 flags1 = unmarshal.read8();
136 bool newType;
137 bool newOid;
138 bool newTid;
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);
144 return;
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"
156 " received"),
157 css::uno::Reference< css::uno::XInterface >());
159 } else {
160 forceSynchronous = false;
162 functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16
163 ? unmarshal.read16() : unmarshal.read8();
164 } else {
165 newType = false;
166 newOid = false;
167 newTid = false;
168 forceSynchronous = false;
169 functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14
170 ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F;
172 css::uno::TypeDescription type;
173 if (newType) {
174 type = unmarshal.readType();
175 lastType_ = type;
176 } else {
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 >());
183 type = lastType_;
185 OUString oid;
186 if (newOid) {
187 oid = unmarshal.readOid();
188 if (oid.isEmpty()) {
189 throw css::io::IOException(
190 "binaryurp::Unmarshal: emtpy OID",
191 css::uno::Reference< css::uno::XInterface >());
193 lastOid_ = oid;
194 } else {
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 >());
201 oid = lastOid_;
203 rtl::ByteSequence tid(getTid(unmarshal, newTid));
204 lastTid_ = tid;
205 type.makeComplete();
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;
226 if (ccMode) {
227 css::uno::TypeDescription t(
228 cppu::UnoType< css::uno::Reference< css::uno::XCurrentContext > >::
229 get());
230 cc.set(
231 *static_cast< uno_Interface ** >(
232 unmarshal.readValue(t).getValue(t)));
234 bool synchronous;
235 if (memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD &&
236 (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
237 memberTd.get())->
238 bOneWay))
240 synchronous = forceSynchronous;
241 } else {
242 SAL_INFO_IF(
243 forceSynchronous, "binaryurp",
244 ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
245 " non-oneway function ID"));
246 synchronous = true;
248 bool setter = false;
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
254 // attribute getter
255 if (setter) {
256 inArgs.push_back(
257 unmarshal.readValue(
258 css::uno::TypeDescription(
259 reinterpret_cast<
260 typelib_InterfaceAttributeTypeDescription * >(
261 memberTd.get())->
262 pAttributeTypeRef)));
264 break;
265 case typelib_TypeClass_INTERFACE_METHOD:
267 typelib_InterfaceMethodTypeDescription * mtd =
268 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
269 memberTd.get());
270 for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
271 if (mtd->pParams[i].bIn) {
272 inArgs.push_back(
273 unmarshal.readValue(
274 css::uno::TypeDescription(
275 mtd->pParams[i].pTypeRef)));
278 break;
280 default:
281 assert(false); // this cannot happen
282 break;
284 bridge_->incrementCalls(
285 !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE);
286 if (protProps) {
287 switch (functionId) {
288 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE:
289 bridge_->handleRequestChangeRequest(tid, inArgs);
290 break;
291 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE:
292 bridge_->handleCommitChangeRequest(tid, inArgs);
293 break;
294 default:
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 >());
300 } else {
301 css::uno::UnoInterfaceReference obj;
302 switch (functionId) {
303 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
304 obj = bridge_->findStub(oid, type);
305 if (!obj.is()) {
306 assert(
307 inArgs.size() == 1
308 && inArgs[0].getType().equals(
309 css::uno::TypeDescription(
310 cppu::UnoType< css::uno::Type >::get())));
311 if (!(type.equals(
312 css::uno::TypeDescription(
313 cppu::UnoType<
314 css::uno::Reference<
315 css::uno::XInterface > >::get()))
316 && (css::uno::TypeDescription(
317 *static_cast<
318 typelib_TypeDescriptionReference ** >(
319 inArgs[0].getValue(inArgs[0].getType()))).
320 equals(
321 css::uno::TypeDescription(
322 cppu::UnoType<
323 css::uno::Reference<
324 css::uno::XInterface > >::get())))))
326 throw css::uno::RuntimeException(
327 ("URP: queryInterface request message with unknown OID"
328 " received"),
329 css::uno::Reference< css::uno::XInterface >());
332 break;
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:
338 break;
339 default:
340 obj = bridge_->findStub(oid, type);
341 if (!obj.is()) {
342 throw css::uno::RuntimeException(
343 "URP: request message with unknown OID received",
344 css::uno::Reference< css::uno::XInterface >());
346 break;
348 SAL_WNODEPRECATED_DECLARATIONS_PUSH
349 std::auto_ptr< IncomingRequest > req(
350 new IncomingRequest(
351 bridge_, tid, oid, obj, type, functionId, synchronous, memberTd,
352 setter, inArgs, ccMode, cc));
353 SAL_WNODEPRECATED_DECLARATIONS_POP
354 if (synchronous) {
355 bridge_->incrementActiveCalls();
357 uno_threadpool_putJob(
358 bridge_->getThreadPool(), tid.getHandle(), req.get(), &request,
359 !synchronous);
360 req.release();
364 void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) {
365 rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0));
366 // bit 3: NEWTID
367 lastTid_ = tid;
368 OutgoingRequest req(bridge_->lastOutgoingRequest(tid));
369 bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION
370 BinaryAny ret;
371 std::vector< BinaryAny > outArgs;
372 if (exc) {
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()).
378 get()),
379 ret.getType().get()))
381 sal_Int32 n = 0;
382 typelib_TypeDescriptionReference ** p = 0;
383 switch (req.member.get()->eTypeClass) {
384 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
386 typelib_InterfaceAttributeTypeDescription * atd =
387 reinterpret_cast<
388 typelib_InterfaceAttributeTypeDescription * >(
389 req.member.get());
390 n = req.setter ? atd->nSetExceptions : atd->nGetExceptions;
391 p = req.setter
392 ? atd->ppSetExceptions : atd->ppGetExceptions;
393 break;
395 case typelib_TypeClass_INTERFACE_METHOD:
397 typelib_InterfaceMethodTypeDescription * mtd =
398 reinterpret_cast<
399 typelib_InterfaceMethodTypeDescription * >(
400 req.member.get());
401 n = mtd->nExceptions;
402 p = mtd->ppExceptions;
403 break;
405 default:
406 assert(false); // this cannot happen
407 break;
409 bool ok = false;
410 for (sal_Int32 i = 0; i != n; ++i) {
411 if (typelib_typedescriptionreference_isAssignableFrom(
412 p[i],
413 reinterpret_cast< typelib_TypeDescriptionReference * >(
414 ret.getType().get())))
416 ok = true;
417 break;
420 if (!ok) {
421 throw css::uno::RuntimeException(
422 "URP: reply message with bad exception type received",
423 css::uno::Reference< css::uno::XInterface >());
426 } else {
427 switch (req.member.get()->eTypeClass) {
428 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
429 if (!req.setter) {
430 ret = unmarshal.readValue(
431 css::uno::TypeDescription(
432 reinterpret_cast<
433 typelib_InterfaceAttributeTypeDescription * >(
434 req.member.get())->
435 pAttributeTypeRef));
437 break;
438 case typelib_TypeClass_INTERFACE_METHOD:
440 typelib_InterfaceMethodTypeDescription * mtd =
441 reinterpret_cast<
442 typelib_InterfaceMethodTypeDescription * >(
443 req.member.get());
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) {
448 outArgs.push_back(
449 unmarshal.readValue(
450 css::uno::TypeDescription(
451 mtd->pParams[i].pTypeRef)));
454 break;
456 default:
457 assert(false); // this cannot happen
458 break;
461 switch (req.kind) {
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,
470 false);
471 resp.release();
472 break;
474 case OutgoingRequest::KIND_REQUEST_CHANGE:
475 assert(outArgs.empty());
476 bridge_->handleRequestChangeReply(exc, ret);
477 break;
478 case OutgoingRequest::KIND_COMMIT_CHANGE:
479 assert(outArgs.empty());
480 bridge_->handleCommitChangeReply(exc, ret);
481 break;
482 default:
483 assert(false); // this cannot happen
484 break;
488 rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const {
489 if (newTid) {
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"
495 " set"),
496 css::uno::Reference< css::uno::XInterface >());
498 return lastTid_;
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */