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 <memory>
25 : #include <vector>
26 :
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"
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 0 : for (;;) {
106 0 : css::uno::Sequence< sal_Int8 > s(read(con, 8, true));
107 0 : if (s.getLength() == 0) {
108 : 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 : }
132 :
133 0 : void Reader::readMessage(Unmarshal & unmarshal) {
134 0 : sal_uInt8 flags1 = unmarshal.read8();
135 : bool newType;
136 : bool newOid;
137 : bool newTid;
138 : bool forceSynchronous;
139 : sal_uInt16 functionId;
140 0 : if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER
141 0 : if ((flags1 & 0x40) == 0) { // bit 6: REQUEST
142 0 : readReplyMessage(unmarshal, flags1);
143 0 : return;
144 : }
145 0 : newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE
146 0 : newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID
147 0 : newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID
148 0 : if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS
149 0 : sal_uInt8 flags2 = unmarshal.read8();
150 0 : forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY
151 0 : if (((flags2 & 0x40) != 0) != forceSynchronous) {
152 : // bit 6: SYNCHRONOUS
153 : throw css::uno::RuntimeException(
154 : ("URP: request message with MUSTREPLY != SYNCHRONOUS"
155 : " received"),
156 0 : css::uno::Reference< css::uno::XInterface >());
157 : }
158 : } else {
159 0 : forceSynchronous = false;
160 : }
161 : functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16
162 0 : ? unmarshal.read16() : unmarshal.read8();
163 : } else {
164 0 : newType = false;
165 0 : newOid = false;
166 0 : newTid = false;
167 0 : forceSynchronous = false;
168 : functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14
169 0 : ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F;
170 : }
171 0 : css::uno::TypeDescription type;
172 0 : if (newType) {
173 0 : type = unmarshal.readType();
174 0 : lastType_ = type;
175 : } else {
176 0 : 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 0 : css::uno::Reference< css::uno::XInterface >());
181 : }
182 0 : type = lastType_;
183 : }
184 0 : OUString oid;
185 0 : if (newOid) {
186 0 : oid = unmarshal.readOid();
187 0 : if (oid.isEmpty()) {
188 : throw css::io::IOException(
189 : "binaryurp::Unmarshal: emtpy OID",
190 0 : css::uno::Reference< css::uno::XInterface >());
191 : }
192 0 : lastOid_ = oid;
193 : } else {
194 0 : 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 0 : css::uno::Reference< css::uno::XInterface >());
199 : }
200 0 : oid = lastOid_;
201 : }
202 0 : rtl::ByteSequence tid(getTid(unmarshal, newTid));
203 0 : lastTid_ = tid;
204 0 : type.makeComplete();
205 0 : if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) {
206 : throw css::uno::RuntimeException(
207 : "URP: request message with non-interface interface type received",
208 0 : css::uno::Reference< css::uno::XInterface >());
209 : }
210 : typelib_InterfaceTypeDescription * itd =
211 0 : reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get());
212 0 : if (functionId >= itd->nMapFunctionIndexToMemberIndex) {
213 : throw css::uno::RuntimeException(
214 : "URP: request message with unknown function ID received",
215 0 : css::uno::Reference< css::uno::XInterface >());
216 : }
217 0 : sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId];
218 0 : css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]);
219 0 : memberTd.makeComplete();
220 : assert(memberTd.is());
221 0 : bool protProps = bridge_->isProtocolPropertiesRequest(oid, type);
222 0 : bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE &&
223 0 : bridge_->isCurrentContextMode();
224 0 : css::uno::UnoInterfaceReference cc;
225 0 : if (ccMode) {
226 : css::uno::TypeDescription t(
227 : cppu::UnoType< css::uno::Reference< css::uno::XCurrentContext > >::
228 0 : get());
229 : cc.set(
230 : *static_cast< uno_Interface ** >(
231 0 : unmarshal.readValue(t).getValue(t)));
232 : }
233 : bool synchronous;
234 0 : if (memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD &&
235 : (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
236 0 : memberTd.get())->
237 : bOneWay))
238 : {
239 0 : synchronous = forceSynchronous;
240 : } else {
241 0 : if (forceSynchronous) {
242 : throw css::uno::RuntimeException(
243 : ("URP: synchronous request message with non-oneway function ID"
244 : " received"),
245 0 : css::uno::Reference< css::uno::XInterface >());
246 : }
247 0 : synchronous = true;
248 : }
249 0 : bool setter = false;
250 0 : std::vector< BinaryAny > inArgs;
251 0 : switch (memberTd.get()->eTypeClass) {
252 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
253 0 : setter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId;
254 : // pMapMemberIndexToFunctionIndex contains function index of
255 : // attribute getter
256 0 : if (setter) {
257 : inArgs.push_back(
258 : unmarshal.readValue(
259 : css::uno::TypeDescription(
260 : reinterpret_cast<
261 : typelib_InterfaceAttributeTypeDescription * >(
262 0 : memberTd.get())->
263 0 : pAttributeTypeRef)));
264 : }
265 0 : break;
266 : case typelib_TypeClass_INTERFACE_METHOD:
267 : {
268 : typelib_InterfaceMethodTypeDescription * mtd =
269 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
270 0 : memberTd.get());
271 0 : for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
272 0 : if (mtd->pParams[i].bIn) {
273 : inArgs.push_back(
274 : unmarshal.readValue(
275 : css::uno::TypeDescription(
276 0 : mtd->pParams[i].pTypeRef)));
277 : }
278 : }
279 0 : break;
280 : }
281 : default:
282 : assert(false); // this cannot happen
283 0 : break;
284 : }
285 : bridge_->incrementCalls(
286 0 : !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE);
287 0 : if (protProps) {
288 0 : switch (functionId) {
289 : case SPECIAL_FUNCTION_ID_REQUEST_CHANGE:
290 0 : bridge_->handleRequestChangeRequest(tid, inArgs);
291 0 : break;
292 : case SPECIAL_FUNCTION_ID_COMMIT_CHANGE:
293 0 : bridge_->handleCommitChangeRequest(tid, inArgs);
294 0 : break;
295 : default:
296 : throw css::uno::RuntimeException(
297 : ("URP: request message with UrpProtocolProperties OID and"
298 : " unknown function ID received"),
299 0 : css::uno::Reference< css::uno::XInterface >());
300 : }
301 : } else {
302 0 : css::uno::UnoInterfaceReference obj;
303 0 : switch (functionId) {
304 : case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
305 0 : obj = bridge_->findStub(oid, type);
306 0 : if (!obj.is()) {
307 : assert(
308 : inArgs.size() == 1
309 : && inArgs[0].getType().equals(
310 : css::uno::TypeDescription(
311 : cppu::UnoType< css::uno::Type >::get())));
312 0 : if (!(type.equals(
313 : css::uno::TypeDescription(
314 : cppu::UnoType<
315 : css::uno::Reference<
316 0 : css::uno::XInterface > >::get()))
317 : && (css::uno::TypeDescription(
318 : *static_cast<
319 : typelib_TypeDescriptionReference ** >(
320 0 : inArgs[0].getValue(inArgs[0].getType()))).
321 : equals(
322 : css::uno::TypeDescription(
323 : cppu::UnoType<
324 : css::uno::Reference<
325 0 : css::uno::XInterface > >::get())))))
326 : {
327 : throw css::uno::RuntimeException(
328 : ("URP: queryInterface request message with unknown OID"
329 : " received"),
330 0 : css::uno::Reference< css::uno::XInterface >());
331 : }
332 : }
333 0 : break;
334 : case SPECIAL_FUNCTION_ID_RESERVED:
335 : throw css::uno::RuntimeException(
336 : "URP: request message with unknown function ID 1 received",
337 0 : css::uno::Reference< css::uno::XInterface >());
338 : case SPECIAL_FUNCTION_ID_RELEASE:
339 0 : break;
340 : default:
341 0 : obj = bridge_->findStub(oid, type);
342 0 : if (!obj.is()) {
343 : throw css::uno::RuntimeException(
344 : "URP: request message with unknown OID received",
345 0 : css::uno::Reference< css::uno::XInterface >());
346 : }
347 0 : break;
348 : }
349 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
350 : std::auto_ptr< IncomingRequest > req(
351 : new IncomingRequest(
352 : bridge_, tid, oid, obj, type, functionId, synchronous, memberTd,
353 0 : setter, inArgs, ccMode, cc));
354 : SAL_WNODEPRECATED_DECLARATIONS_POP
355 0 : if (synchronous) {
356 0 : bridge_->incrementActiveCalls();
357 : }
358 : uno_threadpool_putJob(
359 0 : bridge_->getThreadPool(), tid.getHandle(), req.get(), &request,
360 0 : !synchronous);
361 0 : req.release();
362 0 : }
363 : }
364 :
365 0 : void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) {
366 0 : rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0));
367 : // bit 3: NEWTID
368 0 : lastTid_ = tid;
369 0 : OutgoingRequest req(bridge_->lastOutgoingRequest(tid));
370 0 : bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION
371 0 : BinaryAny ret;
372 0 : std::vector< BinaryAny > outArgs;
373 0 : if (exc) {
374 : ret = unmarshal.readValue(
375 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()));
376 0 : if (!typelib_typedescription_isAssignableFrom(
377 : (css::uno::TypeDescription(
378 0 : cppu::UnoType< css::uno::RuntimeException >::get()).
379 : get()),
380 0 : ret.getType().get()))
381 : {
382 0 : sal_Int32 n = 0;
383 0 : typelib_TypeDescriptionReference ** p = 0;
384 0 : switch (req.member.get()->eTypeClass) {
385 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
386 : {
387 : typelib_InterfaceAttributeTypeDescription * atd =
388 : reinterpret_cast<
389 : typelib_InterfaceAttributeTypeDescription * >(
390 0 : req.member.get());
391 0 : n = req.setter ? atd->nSetExceptions : atd->nGetExceptions;
392 : p = req.setter
393 0 : ? atd->ppSetExceptions : atd->ppGetExceptions;
394 0 : break;
395 : }
396 : case typelib_TypeClass_INTERFACE_METHOD:
397 : {
398 : typelib_InterfaceMethodTypeDescription * mtd =
399 : reinterpret_cast<
400 : typelib_InterfaceMethodTypeDescription * >(
401 0 : req.member.get());
402 0 : n = mtd->nExceptions;
403 0 : p = mtd->ppExceptions;
404 0 : break;
405 : }
406 : default:
407 : assert(false); // this cannot happen
408 0 : break;
409 : }
410 0 : bool ok = false;
411 0 : for (sal_Int32 i = 0; i != n; ++i) {
412 0 : if (typelib_typedescriptionreference_isAssignableFrom(
413 0 : p[i],
414 : reinterpret_cast< typelib_TypeDescriptionReference * >(
415 0 : ret.getType().get())))
416 : {
417 0 : ok = true;
418 0 : break;
419 : }
420 : }
421 0 : if (!ok) {
422 : throw css::uno::RuntimeException(
423 : "URP: reply message with bad exception type received",
424 0 : css::uno::Reference< css::uno::XInterface >());
425 : }
426 : }
427 : } else {
428 0 : switch (req.member.get()->eTypeClass) {
429 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
430 0 : if (!req.setter) {
431 : ret = unmarshal.readValue(
432 : css::uno::TypeDescription(
433 : reinterpret_cast<
434 : typelib_InterfaceAttributeTypeDescription * >(
435 0 : req.member.get())->
436 0 : pAttributeTypeRef));
437 : }
438 0 : break;
439 : case typelib_TypeClass_INTERFACE_METHOD:
440 : {
441 : typelib_InterfaceMethodTypeDescription * mtd =
442 : reinterpret_cast<
443 : typelib_InterfaceMethodTypeDescription * >(
444 0 : req.member.get());
445 : ret = unmarshal.readValue(
446 0 : css::uno::TypeDescription(mtd->pReturnTypeRef));
447 0 : for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
448 0 : if (mtd->pParams[i].bOut) {
449 : outArgs.push_back(
450 : unmarshal.readValue(
451 : css::uno::TypeDescription(
452 0 : mtd->pParams[i].pTypeRef)));
453 : }
454 : }
455 0 : break;
456 : }
457 : default:
458 : assert(false); // this cannot happen
459 0 : break;
460 : }
461 : }
462 0 : switch (req.kind) {
463 : case OutgoingRequest::KIND_NORMAL:
464 : {
465 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
466 : std::auto_ptr< IncomingReply > resp(
467 0 : new IncomingReply(exc, ret, outArgs));
468 : SAL_WNODEPRECATED_DECLARATIONS_POP
469 : uno_threadpool_putJob(
470 0 : bridge_->getThreadPool(), tid.getHandle(), resp.get(), 0,
471 0 : false);
472 0 : resp.release();
473 0 : break;
474 : }
475 : case OutgoingRequest::KIND_REQUEST_CHANGE:
476 : assert(outArgs.empty());
477 0 : bridge_->handleRequestChangeReply(exc, ret);
478 0 : break;
479 : case OutgoingRequest::KIND_COMMIT_CHANGE:
480 : assert(outArgs.empty());
481 0 : bridge_->handleCommitChangeReply(exc, ret);
482 0 : break;
483 : default:
484 : assert(false); // this cannot happen
485 0 : break;
486 0 : }
487 0 : }
488 :
489 0 : rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const {
490 0 : if (newTid) {
491 0 : return unmarshal.readTid();
492 : }
493 0 : if (lastTid_.getLength() == 0) {
494 : throw css::uno::RuntimeException(
495 : ("URP: message with NEWTID received when last TID has not yet been"
496 : " set"),
497 0 : css::uno::Reference< css::uno::XInterface >());
498 : }
499 0 : return lastTid_;
500 : }
501 :
502 : }
503 :
504 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|