bump product version to 6.3.0.0.beta1
[LibreOffice.git] / binaryurp / source / writer.cxx
blob585f375d7a58bd7f558bcb5eac884c50101bb436
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 <vector>
29 #include <com/sun/star/connection/XConnection.hpp>
30 #include <com/sun/star/io/IOException.hpp>
31 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
32 #include <com/sun/star/uno/XCurrentContext.hpp>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <osl/mutex.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 const & theTid, OUString const & theOid,
55 css::uno::TypeDescription const & theType,
56 css::uno::TypeDescription const & theMember,
57 std::vector< BinaryAny > const & inArguments,
58 css::uno::UnoInterfaceReference const & theCurrentContext):
59 request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
60 setter(false), arguments(inArguments), exception(false),
61 currentContext(theCurrentContext), setCurrentContextMode(false)
64 Writer::Item::Item(
65 rtl::ByteSequence const & theTid,
66 css::uno::TypeDescription const & theMember, bool theSetter,
67 bool theException, BinaryAny const & theReturnValue,
68 std::vector< BinaryAny > const & outArguments,
69 bool theSetCurrentContextMode):
70 request(false), tid(theTid), member(theMember), setter(theSetter),
71 arguments(outArguments), exception(theException),
72 returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
75 Writer::Writer(rtl::Reference< Bridge > const & bridge):
76 Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
77 stop_(false)
79 assert(bridge.is());
82 void Writer::sendDirectRequest(
83 rtl::ByteSequence const & tid, OUString const & oid,
84 css::uno::TypeDescription const & type,
85 css::uno::TypeDescription const & member,
86 std::vector< BinaryAny > const & inArguments)
88 assert(!unblocked_.check());
89 sendRequest(
90 tid, oid, type, member, inArguments, false,
91 css::uno::UnoInterfaceReference());
94 void Writer::sendDirectReply(
95 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
96 bool exception, BinaryAny const & returnValue,
97 std::vector< BinaryAny > const & outArguments)
99 assert(!unblocked_.check());
100 sendReply(tid, member, false, exception, returnValue,outArguments);
103 void Writer::queueRequest(
104 rtl::ByteSequence const & tid, OUString const & oid,
105 css::uno::TypeDescription const & type,
106 css::uno::TypeDescription const & member,
107 std::vector< BinaryAny > const & inArguments)
109 css::uno::UnoInterfaceReference cc(current_context::get());
110 osl::MutexGuard g(mutex_);
111 queue_.emplace_back(tid, oid, type, member, inArguments, cc);
112 items_.set();
115 void Writer::queueReply(
116 rtl::ByteSequence const & tid,
117 com::sun::star::uno::TypeDescription const & member, bool setter,
118 bool exception, BinaryAny const & returnValue,
119 std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
121 osl::MutexGuard g(mutex_);
122 queue_.emplace_back(
123 tid, member, setter, exception, returnValue, outArguments,
124 setCurrentContextMode);
125 items_.set();
128 void Writer::unblock() {
129 // Assumes that osl::Condition::set works as a memory barrier, so that
130 // changes made by preceding sendDirectRequest/Reply calls are visible to
131 // subsequent sendRequest/Reply calls:
132 unblocked_.set();
135 void Writer::stop() {
137 osl::MutexGuard g(mutex_);
138 stop_ = true;
140 unblocked_.set();
141 items_.set();
144 Writer::~Writer() {}
146 void Writer::execute() {
147 try {
148 unblocked_.wait();
149 for (;;) {
150 items_.wait();
151 Item item;
153 osl::MutexGuard g(mutex_);
154 if (stop_) {
155 return;
157 assert(!queue_.empty());
158 item = queue_.front();
159 queue_.pop_front();
160 if (queue_.empty()) {
161 items_.reset();
164 if (item.request) {
165 sendRequest(
166 item.tid, item.oid, item.type, item.member, item.arguments,
167 (item.oid != "UrpProtocolProperties" &&
168 !item.member.equals(
169 css::uno::TypeDescription(
170 "com.sun.star.uno.XInterface::release")) &&
171 bridge_->isCurrentContextMode()),
172 item.currentContext);
173 } else {
174 sendReply(
175 item.tid, item.member, item.setter, item.exception,
176 item.returnValue, item.arguments);
177 if (item.setCurrentContextMode) {
178 bridge_->setCurrentContextMode();
182 } catch (const css::uno::Exception & e) {
183 SAL_INFO("binaryurp", "caught " << e);
184 } catch (const std::exception & e) {
185 SAL_INFO("binaryurp", "caught C++ exception " << e.what());
187 bridge_->terminate(false);
188 bridge_.clear();
191 void Writer::sendRequest(
192 rtl::ByteSequence const & tid, OUString const & oid,
193 css::uno::TypeDescription const & type,
194 css::uno::TypeDescription const & member,
195 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
196 css::uno::UnoInterfaceReference const & currentContext)
198 assert(tid.getLength() != 0);
199 assert(!oid.isEmpty());
200 assert(member.is());
201 css::uno::TypeDescription t(type);
202 sal_Int32 functionId = 0;
203 bool bForceSynchronous = false;
204 member.makeComplete();
205 switch (member.get()->eTypeClass) {
206 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
208 typelib_InterfaceAttributeTypeDescription * atd =
209 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
210 member.get());
211 assert(atd->pInterface != nullptr);
212 if (!t.is()) {
213 t = css::uno::TypeDescription(&atd->pInterface->aBase);
215 t.makeComplete();
216 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
217 atd->aBase.nPosition];
218 if (!inArguments.empty()) { // setter
219 ++functionId;
221 break;
223 case typelib_TypeClass_INTERFACE_METHOD:
225 typelib_InterfaceMethodTypeDescription * mtd =
226 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
227 member.get());
228 assert(mtd->pInterface != nullptr);
229 if (!t.is()) {
230 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
232 t.makeComplete();
233 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
234 mtd->aBase.nPosition];
235 bForceSynchronous = mtd->bOneWay &&
236 functionId != SPECIAL_FUNCTION_ID_RELEASE;
237 break;
239 default:
240 assert(false); // this cannot happen
241 break;
243 assert(functionId >= 0);
244 if (functionId > SAL_MAX_UINT16) {
245 throw css::uno::RuntimeException("function ID too large for URP");
247 std::vector< unsigned char > buf;
248 bool newType = !(lastType_.is() && t.equals(lastType_));
249 bool newOid = oid != lastOid_;
250 bool newTid = tid != lastTid_;
251 if (newType || newOid || newTid || bForceSynchronous || functionId > 0x3FFF)
252 // > 14 bit function ID
254 Marshal::write8(
255 &buf,
256 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
257 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
258 (bForceSynchronous ? 0x01 : 0)));
259 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
260 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
261 if (bForceSynchronous) {
262 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
264 if (functionId <= 0xFF) {
265 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
266 } else {
267 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
269 if (newType) {
270 marshal_.writeType(&buf, t);
272 if (newOid) {
273 marshal_.writeOid(&buf, oid);
275 if (newTid) {
276 marshal_.writeTid(&buf, tid);
278 } else if (functionId <= 0x3F) { // <= 6 bit function ID
279 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
280 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
281 } else {
282 Marshal::write8(
283 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
284 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
285 Marshal::write8(&buf, functionId & 0xFF);
287 if (currentContextMode) {
288 css::uno::UnoInterfaceReference cc(currentContext);
289 marshal_.writeValue(
290 &buf,
291 css::uno::TypeDescription(
292 cppu::UnoType<
293 css::uno::Reference< css::uno::XCurrentContext > >::get()),
294 BinaryAny(
295 css::uno::TypeDescription(
296 cppu::UnoType<
297 css::uno::Reference<
298 css::uno::XCurrentContext > >::get()),
299 &cc.m_pUnoI));
301 switch (member.get()->eTypeClass) {
302 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
303 if (!inArguments.empty()) { // setter
304 assert(inArguments.size() == 1);
305 marshal_.writeValue(
306 &buf,
307 css::uno::TypeDescription(
308 reinterpret_cast<
309 typelib_InterfaceAttributeTypeDescription * >(
310 member.get())->
311 pAttributeTypeRef),
312 inArguments.front());
314 break;
315 case typelib_TypeClass_INTERFACE_METHOD:
317 typelib_InterfaceMethodTypeDescription * mtd =
318 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
319 member.get());
320 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
321 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
322 if (mtd->pParams[j].bIn) {
323 marshal_.writeValue(
324 &buf,
325 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
326 *i++);
329 assert(i == inArguments.end());
330 break;
332 default:
333 assert(false); // this cannot happen
334 break;
336 sendMessage(buf);
337 lastType_ = t;
338 lastOid_ = oid;
339 lastTid_ = tid;
342 void Writer::sendReply(
343 rtl::ByteSequence const & tid,
344 com::sun::star::uno::TypeDescription const & member, bool setter,
345 bool exception, BinaryAny const & returnValue,
346 std::vector< BinaryAny > const & outArguments)
348 assert(tid.getLength() != 0);
349 assert(member.is());
350 assert(member.get()->bComplete);
351 std::vector< unsigned char > buf;
352 bool newTid = tid != lastTid_;
353 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
354 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
355 if (newTid) {
356 marshal_.writeTid(&buf, tid);
358 if (exception) {
359 marshal_.writeValue(
360 &buf,
361 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
362 returnValue);
363 } else {
364 switch (member.get()->eTypeClass) {
365 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
366 if (!setter) {
367 marshal_.writeValue(
368 &buf,
369 css::uno::TypeDescription(
370 reinterpret_cast<
371 typelib_InterfaceAttributeTypeDescription * >(
372 member.get())->
373 pAttributeTypeRef),
374 returnValue);
376 break;
377 case typelib_TypeClass_INTERFACE_METHOD:
379 typelib_InterfaceMethodTypeDescription * mtd =
380 reinterpret_cast<
381 typelib_InterfaceMethodTypeDescription * >(
382 member.get());
383 marshal_.writeValue(
384 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
385 returnValue);
386 std::vector< BinaryAny >::const_iterator i(
387 outArguments.begin());
388 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
389 if (mtd->pParams[j].bOut) {
390 marshal_.writeValue(
391 &buf,
392 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
393 *i++);
396 assert(i == outArguments.end());
397 break;
399 default:
400 assert(false); // this cannot happen
401 break;
404 sendMessage(buf);
405 lastTid_ = tid;
406 bridge_->decrementCalls();
409 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
410 std::vector< unsigned char > header;
411 if (buffer.size() > SAL_MAX_UINT32) {
412 throw css::uno::RuntimeException(
413 "message too large for URP");
415 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
416 Marshal::write32(&header, 1);
417 assert(!buffer.empty());
418 unsigned char const * p = buffer.data();
419 std::vector< unsigned char >::size_type n = buffer.size();
420 assert(header.size() <= SAL_MAX_INT32);
421 /*static_*/assert(SAL_MAX_INT32 <= std::numeric_limits<std::size_t>::max());
422 std::size_t k = SAL_MAX_INT32 - header.size();
423 if (n < k) {
424 k = n;
426 css::uno::Sequence<sal_Int8> s(header.size() + k);
427 assert(!header.empty());
428 std::memcpy(s.getArray(), header.data(), header.size());
429 for (;;) {
430 std::memcpy(s.getArray() + s.getLength() - k, p, k);
431 try {
432 bridge_->getConnection()->write(s);
433 } catch (const css::io::IOException & e) {
434 css::uno::Any exc(cppu::getCaughtException());
435 throw css::lang::WrappedTargetRuntimeException(
436 "Binary URP write raised IO exception: " + e.Message,
437 css::uno::Reference< css::uno::XInterface >(), exc);
439 n -= k;
440 if (n == 0) {
441 break;
443 p += k;
444 k = SAL_MAX_INT32;
445 if (n < k) {
446 k = n;
448 s.realloc(k);
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */