Bump version to 4.3-4
[LibreOffice.git] / binaryurp / source / writer.cxx
blob6b666b089057d1a408137aa5dd083a0020e5e8cc
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 <exception>
23 #include <vector>
24 #include <string.h>
26 #include "com/sun/star/connection/XConnection.hpp"
27 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
28 #include "com/sun/star/uno/XCurrentContext.hpp"
29 #include "cppuhelper/exc_hlp.hxx"
30 #include "osl/mutex.hxx"
31 #include "uno/dispatcher.hxx"
33 #include "binaryany.hxx"
34 #include "bridge.hxx"
35 #include "currentcontext.hxx"
36 #include "specialfunctionids.hxx"
37 #include "writer.hxx"
39 namespace binaryurp {
41 Writer::Item::Item()
42 : request(false)
43 , setter(false)
44 , exception(false)
45 , setCurrentContextMode(false)
48 Writer::Item::Item(
49 rtl::ByteSequence const & theTid, OUString const & theOid,
50 css::uno::TypeDescription const & theType,
51 css::uno::TypeDescription const & theMember,
52 std::vector< BinaryAny > const & inArguments,
53 css::uno::UnoInterfaceReference const & theCurrentContext):
54 request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
55 setter(false), arguments(inArguments), exception(false),
56 currentContext(theCurrentContext), setCurrentContextMode(false)
59 Writer::Item::Item(
60 rtl::ByteSequence const & theTid,
61 css::uno::TypeDescription const & theMember, bool theSetter,
62 bool theException, BinaryAny const & theReturnValue,
63 std::vector< BinaryAny > const & outArguments,
64 bool theSetCurrentContextMode):
65 request(false), tid(theTid), member(theMember), setter(theSetter),
66 arguments(outArguments), exception(theException),
67 returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
70 Writer::Writer(rtl::Reference< Bridge > const & bridge):
71 Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
72 stop_(false)
74 OSL_ASSERT(bridge.is());
77 void Writer::sendDirectRequest(
78 rtl::ByteSequence const & tid, OUString const & oid,
79 css::uno::TypeDescription const & type,
80 css::uno::TypeDescription const & member,
81 std::vector< BinaryAny > const & inArguments)
83 OSL_ASSERT(!unblocked_.check());
84 sendRequest(
85 tid, oid, type, member, inArguments, false,
86 css::uno::UnoInterfaceReference());
89 void Writer::sendDirectReply(
90 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
91 bool exception, BinaryAny const & returnValue,
92 std::vector< BinaryAny > const & outArguments)
94 OSL_ASSERT(!unblocked_.check());
95 sendReply(tid, member, false, exception, returnValue,outArguments);
98 void Writer::queueRequest(
99 rtl::ByteSequence const & tid, OUString const & oid,
100 css::uno::TypeDescription const & type,
101 css::uno::TypeDescription const & member,
102 std::vector< BinaryAny > const & inArguments)
104 css::uno::UnoInterfaceReference cc(current_context::get());
105 osl::MutexGuard g(mutex_);
106 queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
107 items_.set();
110 void Writer::queueReply(
111 rtl::ByteSequence const & tid,
112 com::sun::star::uno::TypeDescription const & member, bool setter,
113 bool exception, BinaryAny const & returnValue,
114 std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
116 osl::MutexGuard g(mutex_);
117 queue_.push_back(
118 Item(
119 tid, member, setter, exception, returnValue, outArguments,
120 setCurrentContextMode));
121 items_.set();
124 void Writer::unblock() {
125 // Assumes that osl::Condition::set works as a memory barrier, so that
126 // changes made by preceding sendDirectRequest/Reply calls are visible to
127 // subsequent sendRequest/Reply calls:
128 unblocked_.set();
131 void Writer::stop() {
133 osl::MutexGuard g(mutex_);
134 stop_ = true;
136 unblocked_.set();
137 items_.set();
140 Writer::~Writer() {}
142 void Writer::execute() {
143 try {
144 unblocked_.wait();
145 for (;;) {
146 items_.wait();
147 Item item;
149 osl::MutexGuard g(mutex_);
150 if (stop_) {
151 return;
153 OSL_ASSERT(!queue_.empty());
154 item = queue_.front();
155 queue_.pop_front();
156 if (queue_.empty()) {
157 items_.reset();
160 if (item.request) {
161 sendRequest(
162 item.tid, item.oid, item.type, item.member, item.arguments,
163 (item.oid != "UrpProtocolProperties" &&
164 !item.member.equals(
165 css::uno::TypeDescription(
166 "com.sun.star.uno.XInterface::release")) &&
167 bridge_->isCurrentContextMode()),
168 item.currentContext);
169 } else {
170 sendReply(
171 item.tid, item.member, item.setter, item.exception,
172 item.returnValue, item.arguments);
173 if (item.setCurrentContextMode) {
174 bridge_->setCurrentContextMode();
178 } catch (const css::uno::Exception & e) {
179 OSL_TRACE(
180 "caught UNO exception '%s'",
181 OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
182 } catch (const std::exception & e) {
183 OSL_TRACE("caught C++ exception '%s'", e.what());
185 bridge_->terminate(false);
186 bridge_.clear();
189 void Writer::sendRequest(
190 rtl::ByteSequence const & tid, OUString const & oid,
191 css::uno::TypeDescription const & type,
192 css::uno::TypeDescription const & member,
193 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
194 css::uno::UnoInterfaceReference const & currentContext)
196 OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
197 css::uno::TypeDescription t(type);
198 sal_Int32 functionId = 0;
199 bool forceSynchronous = false;
200 member.makeComplete();
201 switch (member.get()->eTypeClass) {
202 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
204 typelib_InterfaceAttributeTypeDescription * atd =
205 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
206 member.get());
207 OSL_ASSERT(atd->pInterface != 0);
208 if (!t.is()) {
209 t = css::uno::TypeDescription(&atd->pInterface->aBase);
211 t.makeComplete();
212 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
213 atd->aBase.nPosition];
214 if (!inArguments.empty()) { // setter
215 ++functionId;
217 break;
219 case typelib_TypeClass_INTERFACE_METHOD:
221 typelib_InterfaceMethodTypeDescription * mtd =
222 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
223 member.get());
224 OSL_ASSERT(mtd->pInterface != 0);
225 if (!t.is()) {
226 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
228 t.makeComplete();
229 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
230 mtd->aBase.nPosition];
231 forceSynchronous = mtd->bOneWay &&
232 functionId != SPECIAL_FUNCTION_ID_RELEASE;
233 break;
235 default:
236 OSL_ASSERT(false); // this cannot happen
237 break;
239 OSL_ASSERT(functionId >= 0);
240 if (functionId > SAL_MAX_UINT16) {
241 throw css::uno::RuntimeException(
242 "function ID too large for URP",
243 css::uno::Reference< css::uno::XInterface >());
245 std::vector< unsigned char > buf;
246 bool newType = !(lastType_.is() && t.equals(lastType_));
247 bool newOid = oid != lastOid_;
248 bool newTid = tid != lastTid_;
249 if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
250 // > 14 bit function ID
252 Marshal::write8(
253 &buf,
254 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
255 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
256 (forceSynchronous ? 0x01 : 0)));
257 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
258 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
259 if (forceSynchronous) {
260 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
262 if (functionId <= 0xFF) {
263 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
264 } else {
265 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
267 if (newType) {
268 marshal_.writeType(&buf, t);
270 if (newOid) {
271 marshal_.writeOid(&buf, oid);
273 if (newTid) {
274 marshal_.writeTid(&buf, tid);
276 } else if (functionId <= 0x3F) { // <= 6 bit function ID
277 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
278 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
279 } else {
280 Marshal::write8(
281 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
282 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
283 Marshal::write8(&buf, functionId & 0xFF);
285 if (currentContextMode) {
286 css::uno::UnoInterfaceReference cc(currentContext);
287 marshal_.writeValue(
288 &buf,
289 css::uno::TypeDescription(
290 cppu::UnoType<
291 css::uno::Reference< css::uno::XCurrentContext > >::get()),
292 BinaryAny(
293 css::uno::TypeDescription(
294 cppu::UnoType<
295 css::uno::Reference<
296 css::uno::XCurrentContext > >::get()),
297 &cc.m_pUnoI));
299 switch (member.get()->eTypeClass) {
300 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
301 if (!inArguments.empty()) { // setter
302 OSL_ASSERT(inArguments.size() == 1);
303 marshal_.writeValue(
304 &buf,
305 css::uno::TypeDescription(
306 reinterpret_cast<
307 typelib_InterfaceAttributeTypeDescription * >(
308 member.get())->
309 pAttributeTypeRef),
310 inArguments.front());
312 break;
313 case typelib_TypeClass_INTERFACE_METHOD:
315 typelib_InterfaceMethodTypeDescription * mtd =
316 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
317 member.get());
318 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
319 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
320 if (mtd->pParams[j].bIn) {
321 marshal_.writeValue(
322 &buf,
323 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
324 *i++);
327 OSL_ASSERT(i == inArguments.end());
328 break;
330 default:
331 OSL_ASSERT(false); // this cannot happen
332 break;
334 sendMessage(buf);
335 lastType_ = t;
336 lastOid_ = oid;
337 lastTid_ = tid;
340 void Writer::sendReply(
341 rtl::ByteSequence const & tid,
342 com::sun::star::uno::TypeDescription const & member, bool setter,
343 bool exception, BinaryAny const & returnValue,
344 std::vector< BinaryAny > const & outArguments)
346 OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
347 std::vector< unsigned char > buf;
348 bool newTid = tid != lastTid_;
349 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
350 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
351 if (newTid) {
352 marshal_.writeTid(&buf, tid);
354 if (exception) {
355 marshal_.writeValue(
356 &buf,
357 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
358 returnValue);
359 } else {
360 switch (member.get()->eTypeClass) {
361 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
362 if (!setter) {
363 marshal_.writeValue(
364 &buf,
365 css::uno::TypeDescription(
366 reinterpret_cast<
367 typelib_InterfaceAttributeTypeDescription * >(
368 member.get())->
369 pAttributeTypeRef),
370 returnValue);
372 break;
373 case typelib_TypeClass_INTERFACE_METHOD:
375 typelib_InterfaceMethodTypeDescription * mtd =
376 reinterpret_cast<
377 typelib_InterfaceMethodTypeDescription * >(
378 member.get());
379 marshal_.writeValue(
380 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
381 returnValue);
382 std::vector< BinaryAny >::const_iterator i(
383 outArguments.begin());
384 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
385 if (mtd->pParams[j].bOut) {
386 marshal_.writeValue(
387 &buf,
388 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
389 *i++);
392 OSL_ASSERT(i == outArguments.end());
393 break;
395 default:
396 OSL_ASSERT(false); // this cannot happen
397 break;
400 sendMessage(buf);
401 lastTid_ = tid;
402 bridge_->decrementCalls();
405 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
406 std::vector< unsigned char > header;
407 if (buffer.size() > SAL_MAX_UINT32) {
408 throw css::uno::RuntimeException(
409 "message too large for URP",
410 css::uno::Reference< css::uno::XInterface >());
412 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
413 Marshal::write32(&header, 1);
414 OSL_ASSERT(!buffer.empty());
415 unsigned char const * p = &buffer[0];
416 std::vector< unsigned char >::size_type n = buffer.size();
417 OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
418 sal_Size k = SAL_MAX_INT32 - header.size();
419 if (n < k) {
420 k = static_cast< sal_Size >(n);
422 css::uno::Sequence< sal_Int8 > s(
423 static_cast< sal_Int32 >(header.size() + k));
424 OSL_ASSERT(!header.empty());
425 memcpy(
426 s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
427 for (;;) {
428 memcpy(s.getArray() + s.getLength() - k, p, k);
429 try {
430 bridge_->getConnection()->write(s);
431 } catch (const css::io::IOException & e) {
432 css::uno::Any exc(cppu::getCaughtException());
433 throw css::lang::WrappedTargetRuntimeException(
434 "Binary URP write raised IO exception: " + e.Message,
435 css::uno::Reference< css::uno::XInterface >(), exc);
437 n = static_cast< std::vector< unsigned char >::size_type >(n - k);
438 if (n == 0) {
439 break;
441 p += k;
442 k = SAL_MAX_INT32;
443 if (n < k) {
444 k = static_cast< sal_Size >(n);
446 s.realloc(k);
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */