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