Update git submodules
[LibreOffice.git] / binaryurp / source / writer.cxx
blob539d8a2c532f08023ed437a76d4be6289d6e4d7d
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 <cstddef>
24 #include <cstring>
25 #include <exception>
26 #include <limits>
27 #include <utility>
28 #include <vector>
30 #include <com/sun/star/connection/XConnection.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
33 #include <com/sun/star/uno/XCurrentContext.hpp>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <sal/log.hxx>
36 #include <uno/dispatcher.hxx>
38 #include "binaryany.hxx"
39 #include "bridge.hxx"
40 #include "currentcontext.hxx"
41 #include "specialfunctionids.hxx"
42 #include "writer.hxx"
44 namespace binaryurp {
46 Writer::Item::Item()
47 : request(false)
48 , setter(false)
49 , exception(false)
50 , setCurrentContextMode(false)
53 Writer::Item::Item(
54 rtl::ByteSequence theTid, OUString theOid,
55 css::uno::TypeDescription theType,
56 css::uno::TypeDescription theMember,
57 std::vector< BinaryAny >&& inArguments,
58 css::uno::UnoInterfaceReference theCurrentContext):
59 tid(std::move(theTid)), oid(std::move(theOid)), type(std::move(theType)), member(std::move(theMember)),
60 currentContext(std::move(theCurrentContext)), arguments(std::move(inArguments)),
61 request(true), setter(false), exception(false), setCurrentContextMode(false)
64 Writer::Item::Item(
65 rtl::ByteSequence theTid,
66 css::uno::TypeDescription theMember, bool theSetter,
67 bool theException, BinaryAny theReturnValue,
68 std::vector< BinaryAny >&& outArguments,
69 bool theSetCurrentContextMode):
70 tid(std::move(theTid)), member(std::move(theMember)),
71 returnValue(std::move(theReturnValue)), arguments(std::move(outArguments)),
72 request(false), setter(theSetter),
73 exception(theException), setCurrentContextMode(theSetCurrentContextMode)
76 Writer::Writer(rtl::Reference< Bridge > const & bridge):
77 Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
78 stop_(false)
80 assert(bridge.is());
83 void Writer::sendDirectRequest(
84 rtl::ByteSequence const & tid, OUString const & oid,
85 css::uno::TypeDescription const & type,
86 css::uno::TypeDescription const & member,
87 std::vector< BinaryAny > const & inArguments)
89 assert(!unblocked_.check());
90 sendRequest(
91 tid, oid, type, member, inArguments, false,
92 css::uno::UnoInterfaceReference());
95 void Writer::sendDirectReply(
96 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
97 bool exception, BinaryAny const & returnValue,
98 std::vector< BinaryAny > const & outArguments)
100 assert(!unblocked_.check());
101 sendReply(tid, member, false, exception, returnValue,outArguments);
104 void Writer::queueRequest(
105 rtl::ByteSequence const & tid, OUString const & oid,
106 css::uno::TypeDescription const & type,
107 css::uno::TypeDescription const & member,
108 std::vector< BinaryAny >&& inArguments)
110 css::uno::UnoInterfaceReference cc(current_context::get());
111 std::lock_guard g(mutex_);
112 queue_.emplace_back(tid, oid, type, member, std::move(inArguments), cc);
113 items_.set();
116 void Writer::queueReply(
117 rtl::ByteSequence const & tid,
118 com::sun::star::uno::TypeDescription const & member, bool setter,
119 bool exception, BinaryAny const & returnValue,
120 std::vector< BinaryAny >&& outArguments, bool setCurrentContextMode)
122 std::lock_guard g(mutex_);
123 queue_.emplace_back(
124 tid, member, setter, exception, returnValue, std::move(outArguments),
125 setCurrentContextMode);
126 items_.set();
129 void Writer::unblock() {
130 // Assumes that osl::Condition::set works as a memory barrier, so that
131 // changes made by preceding sendDirectRequest/Reply calls are visible to
132 // subsequent sendRequest/Reply calls:
133 unblocked_.set();
136 void Writer::stop() {
138 std::lock_guard g(mutex_);
139 stop_ = true;
141 unblocked_.set();
142 items_.set();
145 Writer::~Writer() {}
147 void Writer::execute() {
148 try {
149 unblocked_.wait();
150 for (;;) {
151 items_.wait();
152 Item item;
154 std::lock_guard g(mutex_);
155 if (stop_) {
156 return;
158 assert(!queue_.empty());
159 item = queue_.front();
160 queue_.pop_front();
161 if (queue_.empty()) {
162 items_.reset();
165 if (item.request) {
166 sendRequest(
167 item.tid, item.oid, item.type, item.member, item.arguments,
168 (item.oid != "UrpProtocolProperties" &&
169 !item.member.equals(
170 css::uno::TypeDescription(
171 "com.sun.star.uno.XInterface::release")) &&
172 bridge_->isCurrentContextMode()),
173 item.currentContext);
174 } else {
175 sendReply(
176 item.tid, item.member, item.setter, item.exception,
177 item.returnValue, item.arguments);
178 if (item.setCurrentContextMode) {
179 bridge_->setCurrentContextMode();
183 } catch (const css::uno::Exception & e) {
184 SAL_INFO("binaryurp", "caught " << e);
185 } catch (const std::exception & e) {
186 SAL_INFO("binaryurp", "caught C++ exception " << e.what());
188 bridge_->terminate(false);
189 bridge_.clear();
192 void Writer::sendRequest(
193 rtl::ByteSequence const & tid, OUString const & oid,
194 css::uno::TypeDescription const & type,
195 css::uno::TypeDescription const & member,
196 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
197 css::uno::UnoInterfaceReference const & currentContext)
199 assert(tid.getLength() != 0);
200 assert(!oid.isEmpty());
201 assert(member.is());
202 css::uno::TypeDescription t(type);
203 sal_Int32 functionId = 0;
204 bool bForceSynchronous = false;
205 member.makeComplete();
206 switch (member.get()->eTypeClass) {
207 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
209 typelib_InterfaceAttributeTypeDescription * atd =
210 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
211 member.get());
212 assert(atd->pInterface != nullptr);
213 if (!t.is()) {
214 t = css::uno::TypeDescription(&atd->pInterface->aBase);
216 t.makeComplete();
217 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
218 atd->aBase.nPosition];
219 if (!inArguments.empty()) { // setter
220 ++functionId;
222 break;
224 case typelib_TypeClass_INTERFACE_METHOD:
226 typelib_InterfaceMethodTypeDescription * mtd =
227 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
228 member.get());
229 assert(mtd->pInterface != nullptr);
230 if (!t.is()) {
231 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
233 t.makeComplete();
234 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
235 mtd->aBase.nPosition];
236 bForceSynchronous = mtd->bOneWay &&
237 functionId != SPECIAL_FUNCTION_ID_RELEASE;
238 break;
240 default:
241 assert(false); // this cannot happen
242 break;
244 assert(functionId >= 0);
245 if (functionId > SAL_MAX_UINT16) {
246 throw css::uno::RuntimeException("function ID too large for URP");
248 std::vector< unsigned char > buf;
249 bool newType = !(lastType_.is() && t.equals(lastType_));
250 bool newOid = oid != lastOid_;
251 bool newTid = tid != lastTid_;
252 if (newType || newOid || newTid || bForceSynchronous || functionId > 0x3FFF)
253 // > 14 bit function ID
255 Marshal::write8(
256 &buf,
257 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
258 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
259 (bForceSynchronous ? 0x01 : 0)));
260 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
261 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
262 if (bForceSynchronous) {
263 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
265 if (functionId <= 0xFF) {
266 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
267 } else {
268 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
270 if (newType) {
271 marshal_.writeType(&buf, t);
273 if (newOid) {
274 marshal_.writeOid(&buf, oid);
276 if (newTid) {
277 marshal_.writeTid(&buf, tid);
279 } else if (functionId <= 0x3F) { // <= 6 bit function ID
280 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
281 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
282 } else {
283 Marshal::write8(
284 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
285 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
286 Marshal::write8(&buf, functionId & 0xFF);
288 if (currentContextMode) {
289 css::uno::UnoInterfaceReference cc(currentContext);
290 marshal_.writeValue(
291 &buf,
292 css::uno::TypeDescription(
293 cppu::UnoType<
294 css::uno::Reference< css::uno::XCurrentContext > >::get()),
295 BinaryAny(
296 css::uno::TypeDescription(
297 cppu::UnoType<
298 css::uno::Reference<
299 css::uno::XCurrentContext > >::get()),
300 &cc.m_pUnoI));
302 switch (member.get()->eTypeClass) {
303 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
304 if (!inArguments.empty()) { // setter
305 assert(inArguments.size() == 1);
306 marshal_.writeValue(
307 &buf,
308 css::uno::TypeDescription(
309 reinterpret_cast<
310 typelib_InterfaceAttributeTypeDescription * >(
311 member.get())->
312 pAttributeTypeRef),
313 inArguments.front());
315 break;
316 case typelib_TypeClass_INTERFACE_METHOD:
318 typelib_InterfaceMethodTypeDescription * mtd =
319 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
320 member.get());
321 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
322 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
323 if (mtd->pParams[j].bIn) {
324 marshal_.writeValue(
325 &buf,
326 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
327 *i++);
330 assert(i == inArguments.end());
331 break;
333 default:
334 assert(false); // this cannot happen
335 break;
337 sendMessage(buf);
338 lastType_ = t;
339 lastOid_ = oid;
340 lastTid_ = tid;
343 void Writer::sendReply(
344 rtl::ByteSequence const & tid,
345 com::sun::star::uno::TypeDescription const & member, bool setter,
346 bool exception, BinaryAny const & returnValue,
347 std::vector< BinaryAny > const & outArguments)
349 assert(tid.getLength() != 0);
350 assert(member.is());
351 assert(member.get()->bComplete);
352 std::vector< unsigned char > buf;
353 bool newTid = tid != lastTid_;
354 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
355 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
356 if (newTid) {
357 marshal_.writeTid(&buf, tid);
359 if (exception) {
360 marshal_.writeValue(
361 &buf,
362 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
363 returnValue);
364 } else {
365 switch (member.get()->eTypeClass) {
366 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
367 if (!setter) {
368 marshal_.writeValue(
369 &buf,
370 css::uno::TypeDescription(
371 reinterpret_cast<
372 typelib_InterfaceAttributeTypeDescription * >(
373 member.get())->
374 pAttributeTypeRef),
375 returnValue);
377 break;
378 case typelib_TypeClass_INTERFACE_METHOD:
380 typelib_InterfaceMethodTypeDescription * mtd =
381 reinterpret_cast<
382 typelib_InterfaceMethodTypeDescription * >(
383 member.get());
384 marshal_.writeValue(
385 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
386 returnValue);
387 std::vector< BinaryAny >::const_iterator i(
388 outArguments.begin());
389 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
390 if (mtd->pParams[j].bOut) {
391 marshal_.writeValue(
392 &buf,
393 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
394 *i++);
397 assert(i == outArguments.end());
398 break;
400 default:
401 assert(false); // this cannot happen
402 break;
405 sendMessage(buf);
406 lastTid_ = tid;
407 bridge_->decrementCalls();
410 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
411 std::vector< unsigned char > header;
412 if (buffer.size() > SAL_MAX_UINT32) {
413 throw css::uno::RuntimeException(
414 "message too large for URP");
416 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
417 Marshal::write32(&header, 1);
418 assert(!buffer.empty());
419 unsigned char const * p = buffer.data();
420 std::vector< unsigned char >::size_type n = buffer.size();
421 assert(header.size() <= SAL_MAX_INT32);
422 /*static_*/assert(SAL_MAX_INT32 <= std::numeric_limits<std::size_t>::max());
423 std::size_t k = SAL_MAX_INT32 - header.size();
424 if (n < k) {
425 k = n;
427 css::uno::Sequence<sal_Int8> s(header.size() + k);
428 assert(!header.empty());
429 std::memcpy(s.getArray(), header.data(), header.size());
430 for (;;) {
431 std::memcpy(s.getArray() + s.getLength() - k, p, k);
432 try {
433 bridge_->getConnection()->write(s);
434 } catch (const css::io::IOException & e) {
435 css::uno::Any exc(cppu::getCaughtException());
436 throw css::lang::WrappedTargetRuntimeException(
437 "Binary URP write raised IO exception: " + e.Message,
438 css::uno::Reference< css::uno::XInterface >(), exc);
440 n -= k;
441 if (n == 0) {
442 break;
444 p += k;
445 k = SAL_MAX_INT32;
446 if (n < k) {
447 k = n;
449 s.realloc(k);
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */