LibreOffice Module binaryurp (master) 1
writer.cxx
Go to the documentation of this file.
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 <cstddef>
24#include <cstring>
25#include <exception>
26#include <limits>
27#include <utility>
28#include <vector>
29
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>
35#include <sal/log.hxx>
36#include <uno/dispatcher.hxx>
37
38#include "binaryany.hxx"
39#include "bridge.hxx"
40#include "currentcontext.hxx"
42#include "writer.hxx"
43
44namespace binaryurp {
45
47 : request(false)
48 , setter(false)
49 , exception(false)
50 , setCurrentContextMode(false)
51{}
52
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)
62{}
63
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)
74{}
75
77 Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
78 stop_(false)
79{
80 assert(bridge.is());
81}
82
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)
88{
89 assert(!unblocked_.check());
91 tid, oid, type, member, inArguments, false,
92 css::uno::UnoInterfaceReference());
93}
94
96 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
97 bool exception, BinaryAny const & returnValue,
98 std::vector< BinaryAny > const & outArguments)
99{
100 assert(!unblocked_.check());
101 sendReply(tid, member, false, exception, returnValue,outArguments);
102}
103
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)
109{
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();
114}
115
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)
121{
122 std::lock_guard g(mutex_);
123 queue_.emplace_back(
124 tid, member, setter, exception, returnValue, std::move(outArguments),
125 setCurrentContextMode);
126 items_.set();
127}
128
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();
134}
135
137 {
138 std::lock_guard g(mutex_);
139 stop_ = true;
140 }
141 unblocked_.set();
142 items_.set();
143}
144
146
148 try {
149 unblocked_.wait();
150 for (;;) {
151 items_.wait();
152 Item item;
153 {
154 std::lock_guard g(mutex_);
155 if (stop_) {
156 return;
157 }
158 assert(!queue_.empty());
159 item = queue_.front();
160 queue_.pop_front();
161 if (queue_.empty()) {
162 items_.reset();
163 }
164 }
165 if (item.request) {
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();
180 }
181 }
182 }
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());
187 }
188 bridge_->terminate(false);
189 bridge_.clear();
190}
191
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)
198{
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:
208 {
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);
215 }
216 t.makeComplete();
217 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
218 atd->aBase.nPosition];
219 if (!inArguments.empty()) { // setter
220 ++functionId;
221 }
222 break;
223 }
224 case typelib_TypeClass_INTERFACE_METHOD:
225 {
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);
232 }
233 t.makeComplete();
234 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
235 mtd->aBase.nPosition];
236 bForceSynchronous = mtd->bOneWay &&
237 functionId != SPECIAL_FUNCTION_ID_RELEASE;
238 break;
239 }
240 default:
241 assert(false); // this cannot happen
242 break;
243 }
244 assert(functionId >= 0);
245 if (functionId > SAL_MAX_UINT16) {
246 throw css::uno::RuntimeException("function ID too large for URP");
247 }
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
254 {
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
264 }
265 if (functionId <= 0xFF) {
266 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
267 } else {
268 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
269 }
270 if (newType) {
271 marshal_.writeType(&buf, t);
272 }
273 if (newOid) {
274 marshal_.writeOid(&buf, oid);
275 }
276 if (newTid) {
277 marshal_.writeTid(&buf, tid);
278 }
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 {
284 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
285 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
286 Marshal::write8(&buf, functionId & 0xFF);
287 }
288 if (currentContextMode) {
289 css::uno::UnoInterfaceReference cc(currentContext);
291 &buf,
292 css::uno::TypeDescription(
294 css::uno::Reference< css::uno::XCurrentContext > >::get()),
295 BinaryAny(
296 css::uno::TypeDescription(
298 css::uno::Reference<
299 css::uno::XCurrentContext > >::get()),
300 &cc.m_pUnoI));
301 }
302 switch (member.get()->eTypeClass) {
303 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
304 if (!inArguments.empty()) { // setter
305 assert(inArguments.size() == 1);
307 &buf,
308 css::uno::TypeDescription(
309 reinterpret_cast<
310 typelib_InterfaceAttributeTypeDescription * >(
311 member.get())->
312 pAttributeTypeRef),
313 inArguments.front());
314 }
315 break;
316 case typelib_TypeClass_INTERFACE_METHOD:
317 {
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) {
325 &buf,
326 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
327 *i++);
328 }
329 }
330 assert(i == inArguments.end());
331 break;
332 }
333 default:
334 assert(false); // this cannot happen
335 break;
336 }
337 sendMessage(buf);
338 lastType_ = t;
339 lastOid_ = oid;
340 lastTid_ = tid;
341}
342
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)
348{
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);
358 }
359 if (exception) {
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) {
369 &buf,
370 css::uno::TypeDescription(
371 reinterpret_cast<
372 typelib_InterfaceAttributeTypeDescription * >(
373 member.get())->
374 pAttributeTypeRef),
375 returnValue);
376 }
377 break;
378 case typelib_TypeClass_INTERFACE_METHOD:
379 {
380 typelib_InterfaceMethodTypeDescription * mtd =
381 reinterpret_cast<
382 typelib_InterfaceMethodTypeDescription * >(
383 member.get());
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) {
392 &buf,
393 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
394 *i++);
395 }
396 }
397 assert(i == outArguments.end());
398 break;
399 }
400 default:
401 assert(false); // this cannot happen
402 break;
403 }
404 }
405 sendMessage(buf);
406 lastTid_ = tid;
407 bridge_->decrementCalls();
408}
409
410void 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");
415 }
416 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
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;
426 }
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);
439 }
440 n -= k;
441 if (n == 0) {
442 break;
443 }
444 p += k;
445 k = SAL_MAX_INT32;
446 if (n < k) {
447 k = n;
448 }
449 s.realloc(k);
450 }
451}
452
453}
454
455/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr sal_Int8 header[]
XPropertyListType t
static void write16(std::vector< unsigned char > *buffer, sal_uInt16 value)
Definition: marshal.cxx:102
void writeType(std::vector< unsigned char > *buffer, com::sun::star::uno::TypeDescription const &value)
Definition: marshal.cxx:125
void writeValue(std::vector< unsigned char > *buffer, com::sun::star::uno::TypeDescription const &type, BinaryAny const &value)
void writeTid(std::vector< unsigned char > *buffer, rtl::ByteSequence const &tid)
Definition: marshal.cxx:167
void writeOid(std::vector< unsigned char > *buffer, OUString const &oid)
Definition: marshal.cxx:148
static void write32(std::vector< unsigned char > *buffer, sal_uInt32 value)
Definition: marshal.cxx:107
static void write8(std::vector< unsigned char > *buffer, sal_uInt8 value)
Definition: marshal.cxx:97
std::mutex mutex_
Definition: writer.hxx:143
Marshal marshal_
Definition: writer.hxx:136
void sendDirectReply(rtl::ByteSequence const &tid, com::sun::star::uno::TypeDescription const &member, bool exception, BinaryAny const &returnValue, std::vector< BinaryAny > const &outArguments)
Definition: writer.cxx:95
std::deque< Item > queue_
Definition: writer.hxx:144
void queueRequest(rtl::ByteSequence const &tid, OUString const &oid, com::sun::star::uno::TypeDescription const &type, com::sun::star::uno::TypeDescription const &member, std::vector< BinaryAny > &&inArguments)
Definition: writer.cxx:104
void sendRequest(rtl::ByteSequence const &tid, OUString const &oid, com::sun::star::uno::TypeDescription const &type, com::sun::star::uno::TypeDescription const &member, std::vector< BinaryAny > const &inArguments, bool currentContextMode, com::sun::star::uno::UnoInterfaceReference const &currentContext)
Definition: writer.cxx:192
osl::Condition items_
Definition: writer.hxx:141
com::sun::star::uno::TypeDescription lastType_
Definition: writer.hxx:137
void queueReply(rtl::ByteSequence const &tid, com::sun::star::uno::TypeDescription const &member, bool setter, bool exception, BinaryAny const &returnValue, std::vector< BinaryAny > &&outArguments, bool setCurrentContextMode)
Definition: writer.cxx:116
void sendDirectRequest(rtl::ByteSequence const &tid, OUString const &oid, com::sun::star::uno::TypeDescription const &type, com::sun::star::uno::TypeDescription const &member, std::vector< BinaryAny > const &inArguments)
Definition: writer.cxx:83
Writer(rtl::Reference< Bridge > const &bridge)
Definition: writer.cxx:76
rtl::ByteSequence lastTid_
Definition: writer.hxx:139
WriterState state_
Definition: writer.hxx:135
rtl::Reference< Bridge > bridge_
Definition: writer.hxx:134
virtual ~Writer() override
Definition: writer.cxx:145
void sendReply(rtl::ByteSequence const &tid, com::sun::star::uno::TypeDescription const &member, bool setter, bool exception, BinaryAny const &returnValue, std::vector< BinaryAny > const &outArguments)
Definition: writer.cxx:343
virtual void execute() override
Definition: writer.cxx:147
osl::Condition unblocked_
Definition: writer.hxx:140
void sendMessage(std::vector< unsigned char > const &buffer)
Definition: writer.cxx:410
OUString lastOid_
Definition: writer.hxx:138
Thread(char const *name)
void * p
sal_Int64 n
#define SAL_INFO(area, stream)
css::uno::UnoInterfaceReference get()
Any SAL_CALL getCaughtException()
int i
std::vector< BinaryAny > arguments
Definition: writer.hxx:127
com::sun::star::uno::UnoInterfaceReference currentContext
Definition: writer.hxx:125
rtl::ByteSequence tid
Definition: writer.hxx:121
com::sun::star::uno::TypeDescription member
Definition: writer.hxx:124
com::sun::star::uno::TypeDescription type
Definition: writer.hxx:123
unsigned char sal_uInt8
#define SAL_MAX_UINT16
#define SAL_MAX_INT32
#define SAL_MAX_UINT32
ResultType type