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