lok: jsbuilder: avoid sending early id to client side
[LibreOffice.git] / binaryurp / source / reader.cxx
blobb11b77ffe658832650809909465f705e143d5fe9
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 <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>
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");
68 css::uno::Sequence< sal_Int8 > buf;
69 sal_Int32 n = connection->read(buf, static_cast< sal_Int32 >(size));
70 if (n == 0 && eofOk) {
71 return css::uno::Sequence< sal_Int8 >();
73 if (n != static_cast< sal_Int32 >(size)) {
74 throw css::io::IOException(
75 "binaryurp::Reader: premature end of input");
77 assert(buf.getLength() == static_cast< sal_Int32 >(size));
78 return buf;
81 extern "C" void request(void * pThreadSpecificData) {
82 assert(pThreadSpecificData != nullptr);
83 std::unique_ptr< IncomingRequest >(
84 static_cast< IncomingRequest * >(pThreadSpecificData))->
85 execute();
90 Reader::Reader(rtl::Reference< Bridge > const & bridge):
91 Thread("binaryurpReader"), bridge_(bridge)
93 assert(bridge.is());
96 Reader::~Reader() {}
98 void Reader::execute() {
99 try {
100 bridge_->sendRequestChangeRequest();
101 css::uno::Reference< css::connection::XConnection > con(
102 bridge_->getConnection());
103 for (;;) {
104 css::uno::Sequence< sal_Int8 > s(read(con, 8, true));
105 if (!s.hasElements()) {
106 break;
108 Unmarshal header(bridge_, state_, s);
109 sal_uInt32 size = header.read32();
110 sal_uInt32 count = header.read32();
111 header.done();
112 if (count == 0) {
113 throw css::io::IOException(
114 "binaryurp::Reader: block with zero message count received");
116 Unmarshal block(bridge_, state_, read(con, size, false));
117 for (sal_uInt32 i = 0; i != count; ++i) {
118 readMessage(block);
120 block.done();
122 } catch (const css::uno::Exception & e) {
123 SAL_WARN("binaryurp", "caught UNO exception '" << e << '\'');
124 } catch (const std::exception & e) {
125 SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
127 bridge_->terminate(false);
128 bridge_.clear();
131 void Reader::readMessage(Unmarshal & unmarshal) {
132 sal_uInt8 flags1 = unmarshal.read8();
133 bool newType;
134 bool newOid;
135 bool newTid;
136 bool forceSynchronous;
137 sal_uInt16 functionId;
138 if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER
139 if ((flags1 & 0x40) == 0) { // bit 6: REQUEST
140 readReplyMessage(unmarshal, flags1);
141 return;
143 newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE
144 newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID
145 newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID
146 if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS
147 sal_uInt8 flags2 = unmarshal.read8();
148 forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY
149 if (((flags2 & 0x40) != 0) != forceSynchronous) {
150 // bit 6: SYNCHRONOUS
151 throw css::uno::RuntimeException(
152 "URP: request message with MUSTREPLY != SYNCHRONOUS"
153 " received");
155 } else {
156 forceSynchronous = false;
158 functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16
159 ? unmarshal.read16() : unmarshal.read8();
160 } else {
161 newType = false;
162 newOid = false;
163 newTid = false;
164 forceSynchronous = false;
165 functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14
166 ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F;
168 css::uno::TypeDescription type;
169 if (newType) {
170 type = unmarshal.readType();
171 lastType_ = type;
172 } else {
173 if (!lastType_.is()) {
174 throw css::uno::RuntimeException(
175 "URP: request message with NEWTYPE received when last"
176 " interface type has not yet been set");
178 type = lastType_;
180 OUString oid;
181 if (newOid) {
182 oid = unmarshal.readOid();
183 if (oid.isEmpty()) {
184 throw css::io::IOException(
185 "binaryurp::Unmarshal: empty OID");
187 lastOid_ = oid;
188 } else {
189 if (lastOid_.isEmpty()) {
190 throw css::uno::RuntimeException(
191 "URP: request message with NEWOID received when last OID has"
192 " not yet been set");
194 oid = lastOid_;
196 rtl::ByteSequence tid(getTid(unmarshal, newTid));
197 lastTid_ = tid;
198 type.makeComplete();
199 if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) {
200 throw css::uno::RuntimeException(
201 "URP: request message with non-interface interface type received");
203 typelib_InterfaceTypeDescription * itd =
204 reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get());
205 if (functionId >= itd->nMapFunctionIndexToMemberIndex) {
206 throw css::uno::RuntimeException(
207 "URP: request message with unknown function ID received");
209 sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId];
210 css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]);
211 memberTd.makeComplete();
212 assert(memberTd.is());
213 bool protProps = bridge_->isProtocolPropertiesRequest(oid, type);
214 bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE &&
215 bridge_->isCurrentContextMode();
216 css::uno::UnoInterfaceReference cc;
217 if (ccMode) {
218 css::uno::TypeDescription t(
219 cppu::UnoType<css::uno::XCurrentContext>::get());
220 cc.set(
221 *static_cast< uno_Interface ** >(
222 unmarshal.readValue(t).getValue(t)));
224 bool oneWay =
225 memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD &&
226 (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
227 memberTd.get())->
228 bOneWay);
229 SAL_INFO_IF(
230 !oneWay && forceSynchronous, "binaryurp",
231 ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
232 " non-oneway function ID"));
233 bool synchronous = !oneWay || forceSynchronous;
234 bool bSetter = false;
235 std::vector< BinaryAny > inArgs;
236 switch (memberTd.get()->eTypeClass) {
237 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
238 bSetter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId;
239 // pMapMemberIndexToFunctionIndex contains function index of
240 // attribute getter
241 if (bSetter) {
242 inArgs.push_back(
243 unmarshal.readValue(
244 css::uno::TypeDescription(
245 reinterpret_cast<
246 typelib_InterfaceAttributeTypeDescription * >(
247 memberTd.get())->
248 pAttributeTypeRef)));
250 break;
251 case typelib_TypeClass_INTERFACE_METHOD:
253 typelib_InterfaceMethodTypeDescription * mtd =
254 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
255 memberTd.get());
256 for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
257 if (mtd->pParams[i].bIn) {
258 inArgs.push_back(
259 unmarshal.readValue(
260 css::uno::TypeDescription(
261 mtd->pParams[i].pTypeRef)));
264 break;
266 default:
267 assert(false); // this cannot happen
268 break;
270 bridge_->incrementCalls(
271 !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE);
272 if (protProps) {
273 switch (functionId) {
274 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE:
275 bridge_->handleRequestChangeRequest(tid, inArgs);
276 break;
277 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE:
278 bridge_->handleCommitChangeRequest(tid, inArgs);
279 break;
280 default:
281 throw css::uno::RuntimeException(
282 "URP: request message with UrpProtocolProperties OID and"
283 " unknown function ID received");
285 } else {
286 css::uno::UnoInterfaceReference obj;
287 switch (functionId) {
288 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
289 obj = bridge_->findStub(oid, type);
290 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 if (!(type.equals(
297 css::uno::TypeDescription(
298 cppu::UnoType<
299 css::uno::Reference<
300 css::uno::XInterface > >::get()))
301 && (css::uno::TypeDescription(
302 *static_cast<
303 typelib_TypeDescriptionReference ** >(
304 inArgs[0].getValue(inArgs[0].getType()))).
305 equals(
306 css::uno::TypeDescription(
307 cppu::UnoType<
308 css::uno::Reference<
309 css::uno::XInterface > >::get())))))
311 throw css::uno::RuntimeException(
312 "URP: queryInterface request message with unknown OID '"
313 + oid + "' received");
316 break;
317 case SPECIAL_FUNCTION_ID_RESERVED:
318 throw css::uno::RuntimeException(
319 "URP: request message with unknown function ID 1 received");
320 case SPECIAL_FUNCTION_ID_RELEASE:
321 break;
322 default:
323 obj = bridge_->findStub(oid, type);
324 if (!obj.is()) {
325 throw css::uno::RuntimeException(
326 "URP: request message with unknown OID received");
328 break;
330 std::unique_ptr< IncomingRequest > req(
331 new IncomingRequest(
332 bridge_, tid, oid, obj, type, functionId, synchronous, memberTd,
333 bSetter, inArgs, ccMode, cc));
334 if (synchronous) {
335 bridge_->incrementActiveCalls();
337 uno_threadpool_putJob(
338 bridge_->getThreadPool(), tid.getHandle(), req.get(), &request,
339 !synchronous);
340 req.release();
344 void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) {
345 rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0));
346 // bit 3: NEWTID
347 lastTid_ = tid;
348 OutgoingRequest req(bridge_->lastOutgoingRequest(tid));
349 bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION
350 BinaryAny ret;
351 std::vector< BinaryAny > outArgs;
352 if (exc) {
353 ret = unmarshal.readValue(
354 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()));
355 if (!typelib_typedescription_isAssignableFrom(
356 (css::uno::TypeDescription(
357 cppu::UnoType< css::uno::RuntimeException >::get()).
358 get()),
359 ret.getType().get()))
361 sal_Int32 n = 0;
362 typelib_TypeDescriptionReference ** p = nullptr;
363 switch (req.member.get()->eTypeClass) {
364 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
366 typelib_InterfaceAttributeTypeDescription * atd =
367 reinterpret_cast<
368 typelib_InterfaceAttributeTypeDescription * >(
369 req.member.get());
370 n = req.setter ? atd->nSetExceptions : atd->nGetExceptions;
371 p = req.setter
372 ? atd->ppSetExceptions : atd->ppGetExceptions;
373 break;
375 case typelib_TypeClass_INTERFACE_METHOD:
377 typelib_InterfaceMethodTypeDescription * mtd =
378 reinterpret_cast<
379 typelib_InterfaceMethodTypeDescription * >(
380 req.member.get());
381 n = mtd->nExceptions;
382 p = mtd->ppExceptions;
383 break;
385 default:
386 assert(false); // this cannot happen
387 break;
389 bool bOk = false;
390 for (sal_Int32 i = 0; i != n; ++i) {
391 if (typelib_typedescriptionreference_isAssignableFrom(
392 p[i],
393 reinterpret_cast< typelib_TypeDescriptionReference * >(
394 ret.getType().get())))
396 bOk = true;
397 break;
400 if (!bOk) {
401 throw css::uno::RuntimeException(
402 "URP: reply message with bad exception type received");
405 } else {
406 switch (req.member.get()->eTypeClass) {
407 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
408 if (!req.setter) {
409 ret = unmarshal.readValue(
410 css::uno::TypeDescription(
411 reinterpret_cast<
412 typelib_InterfaceAttributeTypeDescription * >(
413 req.member.get())->
414 pAttributeTypeRef));
416 break;
417 case typelib_TypeClass_INTERFACE_METHOD:
419 typelib_InterfaceMethodTypeDescription * mtd =
420 reinterpret_cast<
421 typelib_InterfaceMethodTypeDescription * >(
422 req.member.get());
423 ret = unmarshal.readValue(
424 css::uno::TypeDescription(mtd->pReturnTypeRef));
425 for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
426 if (mtd->pParams[i].bOut) {
427 outArgs.push_back(
428 unmarshal.readValue(
429 css::uno::TypeDescription(
430 mtd->pParams[i].pTypeRef)));
433 break;
435 default:
436 assert(false); // this cannot happen
437 break;
440 switch (req.kind) {
441 case OutgoingRequest::KIND_NORMAL:
443 std::unique_ptr< IncomingReply > resp(
444 new IncomingReply(exc, ret, outArgs));
445 uno_threadpool_putJob(
446 bridge_->getThreadPool(), tid.getHandle(), resp.get(), nullptr,
447 false);
448 resp.release();
449 break;
451 case OutgoingRequest::KIND_REQUEST_CHANGE:
452 assert(outArgs.empty());
453 bridge_->handleRequestChangeReply(exc, ret);
454 break;
455 case OutgoingRequest::KIND_COMMIT_CHANGE:
456 assert(outArgs.empty());
457 bridge_->handleCommitChangeReply(exc, ret);
458 break;
459 default:
460 assert(false); // this cannot happen
461 break;
465 rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const {
466 if (newTid) {
467 return unmarshal.readTid();
469 if (lastTid_.getLength() == 0) {
470 throw css::uno::RuntimeException(
471 "URP: message with NEWTID received when last TID has not yet been"
472 " set");
474 return lastTid_;
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */