Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <cassert>
23 : #include <exception>
24 : #include <vector>
25 :
26 : #include "boost/scoped_ptr.hpp"
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/heap_ptr.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"
45 :
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"
54 :
55 : namespace binaryurp {
56 :
57 : namespace {
58 :
59 0 : css::uno::Sequence< sal_Int8 > read(
60 : css::uno::Reference< css::connection::XConnection > const & connection,
61 : sal_uInt32 size, bool eofOk)
62 : {
63 : assert(connection.is());
64 0 : if (size > SAL_MAX_INT32) {
65 : throw css::uno::RuntimeException(
66 : "binaryurp::Reader: block size too large",
67 0 : css::uno::Reference< css::uno::XInterface >());
68 : }
69 0 : css::uno::Sequence< sal_Int8 > buf;
70 0 : sal_Int32 n = connection->read(buf, static_cast< sal_Int32 >(size));
71 0 : if (n == 0 && eofOk) {
72 0 : return css::uno::Sequence< sal_Int8 >();
73 : }
74 0 : if (n != static_cast< sal_Int32 >(size)) {
75 : throw css::io::IOException(
76 : "binaryurp::Reader: premature end of input",
77 0 : css::uno::Reference< css::uno::XInterface >());
78 : }
79 : assert(buf.getLength() == static_cast< sal_Int32 >(size));
80 0 : return buf;
81 : }
82 :
83 0 : extern "C" void SAL_CALL request(void * pThreadSpecificData) {
84 : assert(pThreadSpecificData != 0);
85 : boost::scoped_ptr< IncomingRequest >(
86 : static_cast< IncomingRequest * >(pThreadSpecificData))->
87 0 : execute();
88 0 : }
89 :
90 : }
91 :
92 0 : Reader::Reader(rtl::Reference< Bridge > const & bridge):
93 0 : Thread("binaryurpReader"), bridge_(bridge)
94 : {
95 : assert(bridge.is());
96 0 : }
97 :
98 0 : Reader::~Reader() {}
99 :
100 0 : void Reader::execute() {
101 : try {
102 0 : bridge_->sendRequestChangeRequest();
103 : css::uno::Reference< css::connection::XConnection > con(
104 0 : bridge_->getConnection());
105 : for (;;) {
106 0 : css::uno::Sequence< sal_Int8 > s(read(con, 8, true));
107 0 : if (s.getLength() == 0) {
108 0 : break;
109 : }
110 0 : Unmarshal header(bridge_, state_, s);
111 0 : sal_uInt32 size = header.read32();
112 0 : sal_uInt32 count = header.read32();
113 0 : header.done();
114 0 : if (count == 0) {
115 : throw css::io::IOException(
116 : "binaryurp::Reader: block with zero message count received",
117 0 : css::uno::Reference< css::uno::XInterface >());
118 : }
119 0 : Unmarshal block(bridge_, state_, read(con, size, false));
120 0 : for (sal_uInt32 i = 0; i != count; ++i) {
121 0 : readMessage(block);
122 : }
123 0 : block.done();
124 0 : }
125 0 : } catch (const css::uno::Exception & e) {
126 : SAL_WARN("binaryurp", "caught UNO exception '" << e.Message << '\'');
127 0 : } catch (const std::exception & e) {
128 : SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
129 : }
130 0 : bridge_->terminate(false);
131 0 : bridge_.clear();
132 0 : }
133 :
134 0 : void Reader::readMessage(Unmarshal & unmarshal) {
135 0 : sal_uInt8 flags1 = unmarshal.read8();
136 : bool newType;
137 : bool newOid;
138 : bool newTid;
139 : bool forceSynchronous;
140 : sal_uInt16 functionId;
141 0 : if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER
142 0 : if ((flags1 & 0x40) == 0) { // bit 6: REQUEST
143 0 : readReplyMessage(unmarshal, flags1);
144 0 : return;
145 : }
146 0 : newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE
147 0 : newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID
148 0 : newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID
149 0 : if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS
150 0 : sal_uInt8 flags2 = unmarshal.read8();
151 0 : forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY
152 0 : if (((flags2 & 0x40) != 0) != forceSynchronous) {
153 : // bit 6: SYNCHRONOUS
154 : throw css::uno::RuntimeException(
155 : ("URP: request message with MUSTREPLY != SYNCHRONOUS"
156 : " received"),
157 0 : css::uno::Reference< css::uno::XInterface >());
158 : }
159 : } else {
160 0 : forceSynchronous = false;
161 : }
162 0 : functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16
163 0 : ? unmarshal.read16() : unmarshal.read8();
164 : } else {
165 0 : newType = false;
166 0 : newOid = false;
167 0 : newTid = false;
168 0 : forceSynchronous = false;
169 0 : functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14
170 0 : ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F;
171 : }
172 0 : css::uno::TypeDescription type;
173 0 : if (newType) {
174 0 : type = unmarshal.readType();
175 0 : lastType_ = type;
176 : } else {
177 0 : 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 0 : css::uno::Reference< css::uno::XInterface >());
182 : }
183 0 : type = lastType_;
184 : }
185 0 : OUString oid;
186 0 : if (newOid) {
187 0 : oid = unmarshal.readOid();
188 0 : if (oid.isEmpty()) {
189 : throw css::io::IOException(
190 : "binaryurp::Unmarshal: emtpy OID",
191 0 : css::uno::Reference< css::uno::XInterface >());
192 : }
193 0 : lastOid_ = oid;
194 : } else {
195 0 : 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 0 : css::uno::Reference< css::uno::XInterface >());
200 : }
201 0 : oid = lastOid_;
202 : }
203 0 : rtl::ByteSequence tid(getTid(unmarshal, newTid));
204 0 : lastTid_ = tid;
205 0 : type.makeComplete();
206 0 : if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) {
207 : throw css::uno::RuntimeException(
208 : "URP: request message with non-interface interface type received",
209 0 : css::uno::Reference< css::uno::XInterface >());
210 : }
211 : typelib_InterfaceTypeDescription * itd =
212 0 : reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get());
213 0 : if (functionId >= itd->nMapFunctionIndexToMemberIndex) {
214 : throw css::uno::RuntimeException(
215 : "URP: request message with unknown function ID received",
216 0 : css::uno::Reference< css::uno::XInterface >());
217 : }
218 0 : sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId];
219 0 : css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]);
220 0 : memberTd.makeComplete();
221 : assert(memberTd.is());
222 0 : bool protProps = bridge_->isProtocolPropertiesRequest(oid, type);
223 0 : bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE &&
224 0 : bridge_->isCurrentContextMode();
225 0 : css::uno::UnoInterfaceReference cc;
226 0 : if (ccMode) {
227 : css::uno::TypeDescription t(
228 : cppu::UnoType< css::uno::Reference< css::uno::XCurrentContext > >::
229 0 : get());
230 : cc.set(
231 : *static_cast< uno_Interface ** >(
232 0 : unmarshal.readValue(t).getValue(t)));
233 : }
234 : bool oneWay =
235 0 : memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD &&
236 : (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
237 0 : memberTd.get())->
238 0 : bOneWay);
239 : SAL_INFO_IF(
240 : !oneWay && forceSynchronous, "binaryurp",
241 : ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
242 : " non-oneway function ID"));
243 0 : bool synchronous = !oneWay || forceSynchronous;
244 0 : bool setter = false;
245 0 : std::vector< BinaryAny > inArgs;
246 0 : switch (memberTd.get()->eTypeClass) {
247 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
248 0 : setter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId;
249 : // pMapMemberIndexToFunctionIndex contains function index of
250 : // attribute getter
251 0 : if (setter) {
252 : inArgs.push_back(
253 : unmarshal.readValue(
254 : css::uno::TypeDescription(
255 : reinterpret_cast<
256 : typelib_InterfaceAttributeTypeDescription * >(
257 0 : memberTd.get())->
258 0 : pAttributeTypeRef)));
259 : }
260 0 : break;
261 : case typelib_TypeClass_INTERFACE_METHOD:
262 : {
263 : typelib_InterfaceMethodTypeDescription * mtd =
264 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
265 0 : memberTd.get());
266 0 : for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
267 0 : if (mtd->pParams[i].bIn) {
268 : inArgs.push_back(
269 : unmarshal.readValue(
270 : css::uno::TypeDescription(
271 0 : mtd->pParams[i].pTypeRef)));
272 : }
273 : }
274 0 : break;
275 : }
276 : default:
277 : assert(false); // this cannot happen
278 0 : break;
279 : }
280 : bridge_->incrementCalls(
281 0 : !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE);
282 0 : if (protProps) {
283 0 : switch (functionId) {
284 : case SPECIAL_FUNCTION_ID_REQUEST_CHANGE:
285 0 : bridge_->handleRequestChangeRequest(tid, inArgs);
286 0 : break;
287 : case SPECIAL_FUNCTION_ID_COMMIT_CHANGE:
288 0 : bridge_->handleCommitChangeRequest(tid, inArgs);
289 0 : break;
290 : default:
291 : throw css::uno::RuntimeException(
292 : ("URP: request message with UrpProtocolProperties OID and"
293 : " unknown function ID received"),
294 0 : css::uno::Reference< css::uno::XInterface >());
295 : }
296 : } else {
297 0 : css::uno::UnoInterfaceReference obj;
298 0 : switch (functionId) {
299 : case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
300 0 : obj = bridge_->findStub(oid, type);
301 0 : if (!obj.is()) {
302 : assert(
303 : inArgs.size() == 1
304 : && inArgs[0].getType().equals(
305 : css::uno::TypeDescription(
306 : cppu::UnoType< css::uno::Type >::get())));
307 0 : if (!(type.equals(
308 : css::uno::TypeDescription(
309 : cppu::UnoType<
310 : css::uno::Reference<
311 0 : css::uno::XInterface > >::get()))
312 : && (css::uno::TypeDescription(
313 : *static_cast<
314 : typelib_TypeDescriptionReference ** >(
315 0 : inArgs[0].getValue(inArgs[0].getType()))).
316 : equals(
317 : css::uno::TypeDescription(
318 : cppu::UnoType<
319 : css::uno::Reference<
320 0 : css::uno::XInterface > >::get())))))
321 : {
322 : throw css::uno::RuntimeException(
323 : ("URP: queryInterface request message with unknown OID"
324 : " received"),
325 0 : css::uno::Reference< css::uno::XInterface >());
326 : }
327 : }
328 0 : break;
329 : case SPECIAL_FUNCTION_ID_RESERVED:
330 : throw css::uno::RuntimeException(
331 : "URP: request message with unknown function ID 1 received",
332 0 : css::uno::Reference< css::uno::XInterface >());
333 : case SPECIAL_FUNCTION_ID_RELEASE:
334 0 : break;
335 : default:
336 0 : obj = bridge_->findStub(oid, type);
337 0 : if (!obj.is()) {
338 : throw css::uno::RuntimeException(
339 : "URP: request message with unknown OID received",
340 0 : css::uno::Reference< css::uno::XInterface >());
341 : }
342 0 : break;
343 : }
344 : o3tl::heap_ptr< IncomingRequest > req(
345 : new IncomingRequest(
346 : bridge_, tid, oid, obj, type, functionId, synchronous, memberTd,
347 0 : setter, inArgs, ccMode, cc));
348 0 : if (synchronous) {
349 0 : bridge_->incrementActiveCalls();
350 : }
351 : uno_threadpool_putJob(
352 0 : bridge_->getThreadPool(), tid.getHandle(), req.get(), &request,
353 0 : !synchronous);
354 0 : req.release();
355 0 : }
356 : }
357 :
358 0 : void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) {
359 0 : rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0));
360 : // bit 3: NEWTID
361 0 : lastTid_ = tid;
362 0 : OutgoingRequest req(bridge_->lastOutgoingRequest(tid));
363 0 : bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION
364 0 : BinaryAny ret;
365 0 : std::vector< BinaryAny > outArgs;
366 0 : if (exc) {
367 0 : ret = unmarshal.readValue(
368 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()));
369 0 : if (!typelib_typedescription_isAssignableFrom(
370 : (css::uno::TypeDescription(
371 0 : cppu::UnoType< css::uno::RuntimeException >::get()).
372 : get()),
373 0 : ret.getType().get()))
374 : {
375 0 : sal_Int32 n = 0;
376 0 : typelib_TypeDescriptionReference ** p = 0;
377 0 : switch (req.member.get()->eTypeClass) {
378 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
379 : {
380 : typelib_InterfaceAttributeTypeDescription * atd =
381 : reinterpret_cast<
382 : typelib_InterfaceAttributeTypeDescription * >(
383 0 : req.member.get());
384 0 : n = req.setter ? atd->nSetExceptions : atd->nGetExceptions;
385 : p = req.setter
386 0 : ? atd->ppSetExceptions : atd->ppGetExceptions;
387 0 : break;
388 : }
389 : case typelib_TypeClass_INTERFACE_METHOD:
390 : {
391 : typelib_InterfaceMethodTypeDescription * mtd =
392 : reinterpret_cast<
393 : typelib_InterfaceMethodTypeDescription * >(
394 0 : req.member.get());
395 0 : n = mtd->nExceptions;
396 0 : p = mtd->ppExceptions;
397 0 : break;
398 : }
399 : default:
400 : assert(false); // this cannot happen
401 0 : break;
402 : }
403 0 : bool ok = false;
404 0 : for (sal_Int32 i = 0; i != n; ++i) {
405 0 : if (typelib_typedescriptionreference_isAssignableFrom(
406 0 : p[i],
407 : reinterpret_cast< typelib_TypeDescriptionReference * >(
408 0 : ret.getType().get())))
409 : {
410 0 : ok = true;
411 0 : break;
412 : }
413 : }
414 0 : if (!ok) {
415 : throw css::uno::RuntimeException(
416 : "URP: reply message with bad exception type received",
417 0 : css::uno::Reference< css::uno::XInterface >());
418 : }
419 : }
420 : } else {
421 0 : switch (req.member.get()->eTypeClass) {
422 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
423 0 : if (!req.setter) {
424 0 : ret = unmarshal.readValue(
425 : css::uno::TypeDescription(
426 : reinterpret_cast<
427 : typelib_InterfaceAttributeTypeDescription * >(
428 0 : req.member.get())->
429 0 : pAttributeTypeRef));
430 : }
431 0 : break;
432 : case typelib_TypeClass_INTERFACE_METHOD:
433 : {
434 : typelib_InterfaceMethodTypeDescription * mtd =
435 : reinterpret_cast<
436 : typelib_InterfaceMethodTypeDescription * >(
437 0 : req.member.get());
438 0 : ret = unmarshal.readValue(
439 0 : css::uno::TypeDescription(mtd->pReturnTypeRef));
440 0 : for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
441 0 : if (mtd->pParams[i].bOut) {
442 : outArgs.push_back(
443 : unmarshal.readValue(
444 : css::uno::TypeDescription(
445 0 : mtd->pParams[i].pTypeRef)));
446 : }
447 : }
448 0 : break;
449 : }
450 : default:
451 : assert(false); // this cannot happen
452 0 : break;
453 : }
454 : }
455 0 : switch (req.kind) {
456 : case OutgoingRequest::KIND_NORMAL:
457 : {
458 : o3tl::heap_ptr< IncomingReply > resp(
459 0 : new IncomingReply(exc, ret, outArgs));
460 : uno_threadpool_putJob(
461 0 : bridge_->getThreadPool(), tid.getHandle(), resp.get(), 0,
462 0 : false);
463 0 : resp.release();
464 0 : break;
465 : }
466 : case OutgoingRequest::KIND_REQUEST_CHANGE:
467 : assert(outArgs.empty());
468 0 : bridge_->handleRequestChangeReply(exc, ret);
469 0 : break;
470 : case OutgoingRequest::KIND_COMMIT_CHANGE:
471 : assert(outArgs.empty());
472 0 : bridge_->handleCommitChangeReply(exc, ret);
473 0 : break;
474 : default:
475 : assert(false); // this cannot happen
476 0 : break;
477 0 : }
478 0 : }
479 :
480 0 : rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const {
481 0 : if (newTid) {
482 0 : return unmarshal.readTid();
483 : }
484 0 : if (lastTid_.getLength() == 0) {
485 : throw css::uno::RuntimeException(
486 : ("URP: message with NEWTID received when last TID has not yet been"
487 : " set"),
488 0 : css::uno::Reference< css::uno::XInterface >());
489 : }
490 0 : return lastTid_;
491 : }
492 :
493 : }
494 :
495 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|