Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / binaryurp / source / writer.cxx
blob3d5c199befa093fa4269643f6dc98eac8c029a4b
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() {}
43 Writer::Item::Item(
44 rtl::ByteSequence const & theTid, OUString const & theOid,
45 css::uno::TypeDescription const & theType,
46 css::uno::TypeDescription const & theMember,
47 std::vector< BinaryAny > const & inArguments,
48 css::uno::UnoInterfaceReference const & theCurrentContext):
49 request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
50 arguments(inArguments), currentContext(theCurrentContext)
53 Writer::Item::Item(
54 rtl::ByteSequence const & theTid,
55 css::uno::TypeDescription const & theMember, bool theSetter,
56 bool theException, BinaryAny const & theReturnValue,
57 std::vector< BinaryAny > const & outArguments,
58 bool theSetCurrentContextMode):
59 request(false), tid(theTid), member(theMember), setter(theSetter),
60 arguments(outArguments), exception(theException),
61 returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
64 Writer::Writer(rtl::Reference< Bridge > const & bridge):
65 Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
66 stop_(false)
68 OSL_ASSERT(bridge.is());
71 void Writer::sendDirectRequest(
72 rtl::ByteSequence const & tid, OUString const & oid,
73 css::uno::TypeDescription const & type,
74 css::uno::TypeDescription const & member,
75 std::vector< BinaryAny > const & inArguments)
77 OSL_ASSERT(!unblocked_.check());
78 sendRequest(
79 tid, oid, type, member, inArguments, false,
80 css::uno::UnoInterfaceReference());
83 void Writer::sendDirectReply(
84 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
85 bool exception, BinaryAny const & returnValue,
86 std::vector< BinaryAny > const & outArguments)
88 OSL_ASSERT(!unblocked_.check());
89 sendReply(tid, member, false, exception, returnValue,outArguments);
92 void Writer::queueRequest(
93 rtl::ByteSequence const & tid, OUString const & oid,
94 css::uno::TypeDescription const & type,
95 css::uno::TypeDescription const & member,
96 std::vector< BinaryAny > const & inArguments)
98 css::uno::UnoInterfaceReference cc(current_context::get());
99 osl::MutexGuard g(mutex_);
100 queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
101 items_.set();
104 void Writer::queueReply(
105 rtl::ByteSequence const & tid,
106 com::sun::star::uno::TypeDescription const & member, bool setter,
107 bool exception, BinaryAny const & returnValue,
108 std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
110 osl::MutexGuard g(mutex_);
111 queue_.push_back(
112 Item(
113 tid, member, setter, exception, returnValue, outArguments,
114 setCurrentContextMode));
115 items_.set();
118 void Writer::unblock() {
119 // Assumes that osl::Condition::set works as a memory barrier, so that
120 // changes made by preceeding sendDirectRequest/Reply calls are visible to
121 // subsequent sendRequest/Reply calls:
122 unblocked_.set();
125 void Writer::stop() {
127 osl::MutexGuard g(mutex_);
128 stop_ = true;
130 unblocked_.set();
131 items_.set();
134 Writer::~Writer() {}
136 void Writer::execute() {
137 try {
138 unblocked_.wait();
139 for (;;) {
140 items_.wait();
141 Item item;
143 osl::MutexGuard g(mutex_);
144 if (stop_) {
145 return;
147 OSL_ASSERT(!queue_.empty());
148 item = queue_.front();
149 queue_.pop_front();
150 if (queue_.empty()) {
151 items_.reset();
154 if (item.request) {
155 sendRequest(
156 item.tid, item.oid, item.type, item.member, item.arguments,
157 (item.oid != "UrpProtocolProperties" &&
158 !item.member.equals(
159 css::uno::TypeDescription(
160 "com.sun.star.uno.XInterface::release")) &&
161 bridge_->isCurrentContextMode()),
162 item.currentContext);
163 } else {
164 sendReply(
165 item.tid, item.member, item.setter, item.exception,
166 item.returnValue, item.arguments);
167 if (item.setCurrentContextMode) {
168 bridge_->setCurrentContextMode();
172 } catch (const css::uno::Exception & e) {
173 OSL_TRACE(
174 OSL_LOG_PREFIX "caught UNO exception '%s'",
175 OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
176 } catch (const std::exception & e) {
177 OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
179 bridge_->terminate(false);
182 void Writer::sendRequest(
183 rtl::ByteSequence const & tid, OUString const & oid,
184 css::uno::TypeDescription const & type,
185 css::uno::TypeDescription const & member,
186 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
187 css::uno::UnoInterfaceReference const & currentContext)
189 OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
190 css::uno::TypeDescription t(type);
191 sal_Int32 functionId = 0;
192 bool forceSynchronous = false;
193 member.makeComplete();
194 switch (member.get()->eTypeClass) {
195 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
197 typelib_InterfaceAttributeTypeDescription * atd =
198 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
199 member.get());
200 OSL_ASSERT(atd->pInterface != 0);
201 if (!t.is()) {
202 t = css::uno::TypeDescription(&atd->pInterface->aBase);
204 t.makeComplete();
205 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
206 atd->aBase.nPosition];
207 if (!inArguments.empty()) { // setter
208 ++functionId;
210 break;
212 case typelib_TypeClass_INTERFACE_METHOD:
214 typelib_InterfaceMethodTypeDescription * mtd =
215 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
216 member.get());
217 OSL_ASSERT(mtd->pInterface != 0);
218 if (!t.is()) {
219 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
221 t.makeComplete();
222 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
223 mtd->aBase.nPosition];
224 forceSynchronous = mtd->bOneWay &&
225 functionId != SPECIAL_FUNCTION_ID_RELEASE;
226 break;
228 default:
229 OSL_ASSERT(false); // this cannot happen
230 break;
232 OSL_ASSERT(functionId >= 0);
233 if (functionId > SAL_MAX_UINT16) {
234 throw css::uno::RuntimeException(
235 "function ID too large for URP",
236 css::uno::Reference< css::uno::XInterface >());
238 std::vector< unsigned char > buf;
239 bool newType = !(lastType_.is() && t.equals(lastType_));
240 bool newOid = oid != lastOid_;
241 bool newTid = tid != lastTid_;
242 if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
243 // > 14 bit function ID
245 Marshal::write8(
246 &buf,
247 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
248 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
249 (forceSynchronous ? 0x01 : 0)));
250 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
251 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
252 if (forceSynchronous) {
253 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
255 if (functionId <= 0xFF) {
256 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
257 } else {
258 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
260 if (newType) {
261 marshal_.writeType(&buf, t);
263 if (newOid) {
264 marshal_.writeOid(&buf, oid);
266 if (newTid) {
267 marshal_.writeTid(&buf, tid);
269 } else if (functionId <= 0x3F) { // <= 6 bit function ID
270 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
271 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
272 } else {
273 Marshal::write8(
274 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
275 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
276 Marshal::write8(&buf, functionId & 0xFF);
278 if (currentContextMode) {
279 css::uno::UnoInterfaceReference cc(currentContext);
280 marshal_.writeValue(
281 &buf,
282 css::uno::TypeDescription(
283 cppu::UnoType<
284 css::uno::Reference< css::uno::XCurrentContext > >::get()),
285 BinaryAny(
286 css::uno::TypeDescription(
287 cppu::UnoType<
288 css::uno::Reference<
289 css::uno::XCurrentContext > >::get()),
290 &cc.m_pUnoI));
292 switch (member.get()->eTypeClass) {
293 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
294 if (!inArguments.empty()) { // setter
295 OSL_ASSERT(inArguments.size() == 1);
296 marshal_.writeValue(
297 &buf,
298 css::uno::TypeDescription(
299 reinterpret_cast<
300 typelib_InterfaceAttributeTypeDescription * >(
301 member.get())->
302 pAttributeTypeRef),
303 inArguments.front());
305 break;
306 case typelib_TypeClass_INTERFACE_METHOD:
308 typelib_InterfaceMethodTypeDescription * mtd =
309 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
310 member.get());
311 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
312 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
313 if (mtd->pParams[j].bIn) {
314 marshal_.writeValue(
315 &buf,
316 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
317 *i++);
320 OSL_ASSERT(i == inArguments.end());
321 break;
323 default:
324 OSL_ASSERT(false); // this cannot happen
325 break;
327 sendMessage(buf);
328 lastType_ = t;
329 lastOid_ = oid;
330 lastTid_ = tid;
333 void Writer::sendReply(
334 rtl::ByteSequence const & tid,
335 com::sun::star::uno::TypeDescription const & member, bool setter,
336 bool exception, BinaryAny const & returnValue,
337 std::vector< BinaryAny > const & outArguments)
339 OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
340 std::vector< unsigned char > buf;
341 bool newTid = tid != lastTid_;
342 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
343 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
344 if (newTid) {
345 marshal_.writeTid(&buf, tid);
347 if (exception) {
348 marshal_.writeValue(
349 &buf,
350 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
351 returnValue);
352 } else {
353 switch (member.get()->eTypeClass) {
354 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
355 if (!setter) {
356 marshal_.writeValue(
357 &buf,
358 css::uno::TypeDescription(
359 reinterpret_cast<
360 typelib_InterfaceAttributeTypeDescription * >(
361 member.get())->
362 pAttributeTypeRef),
363 returnValue);
365 break;
366 case typelib_TypeClass_INTERFACE_METHOD:
368 typelib_InterfaceMethodTypeDescription * mtd =
369 reinterpret_cast<
370 typelib_InterfaceMethodTypeDescription * >(
371 member.get());
372 marshal_.writeValue(
373 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
374 returnValue);
375 std::vector< BinaryAny >::const_iterator i(
376 outArguments.begin());
377 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
378 if (mtd->pParams[j].bOut) {
379 marshal_.writeValue(
380 &buf,
381 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
382 *i++);
385 OSL_ASSERT(i == outArguments.end());
386 break;
388 default:
389 OSL_ASSERT(false); // this cannot happen
390 break;
393 sendMessage(buf);
394 lastTid_ = tid;
395 bridge_->decrementCalls();
398 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
399 std::vector< unsigned char > header;
400 if (buffer.size() > SAL_MAX_UINT32) {
401 throw css::uno::RuntimeException(
402 "message too large for URP",
403 css::uno::Reference< css::uno::XInterface >());
405 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
406 Marshal::write32(&header, 1);
407 OSL_ASSERT(!buffer.empty());
408 unsigned char const * p = &buffer[0];
409 std::vector< unsigned char >::size_type n = buffer.size();
410 OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
411 sal_Size k = SAL_MAX_INT32 - header.size();
412 if (n < k) {
413 k = static_cast< sal_Size >(n);
415 css::uno::Sequence< sal_Int8 > s(
416 static_cast< sal_Int32 >(header.size() + k));
417 OSL_ASSERT(!header.empty());
418 memcpy(
419 s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
420 for (;;) {
421 memcpy(s.getArray() + s.getLength() - k, p, k);
422 try {
423 bridge_->getConnection()->write(s);
424 } catch (const css::io::IOException & e) {
425 css::uno::Any exc(cppu::getCaughtException());
426 throw css::lang::WrappedTargetRuntimeException(
427 "Binary URP write raised IO exception: " + e.Message,
428 css::uno::Reference< css::uno::XInterface >(), exc);
430 n = static_cast< std::vector< unsigned char >::size_type >(n - k);
431 if (n == 0) {
432 break;
434 p += k;
435 k = SAL_MAX_INT32;
436 if (n < k) {
437 k = static_cast< sal_Size >(n);
439 s.realloc(k);
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */