update credits
[LibreOffice.git] / binaryurp / source / writer.cxx
blobedcb0f5090ced4846a7a47d4b02cc9aebe9e5108
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);
180 bridge_.clear();
183 void Writer::sendRequest(
184 rtl::ByteSequence const & tid, OUString const & oid,
185 css::uno::TypeDescription const & type,
186 css::uno::TypeDescription const & member,
187 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
188 css::uno::UnoInterfaceReference const & currentContext)
190 OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
191 css::uno::TypeDescription t(type);
192 sal_Int32 functionId = 0;
193 bool forceSynchronous = false;
194 member.makeComplete();
195 switch (member.get()->eTypeClass) {
196 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
198 typelib_InterfaceAttributeTypeDescription * atd =
199 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
200 member.get());
201 OSL_ASSERT(atd->pInterface != 0);
202 if (!t.is()) {
203 t = css::uno::TypeDescription(&atd->pInterface->aBase);
205 t.makeComplete();
206 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
207 atd->aBase.nPosition];
208 if (!inArguments.empty()) { // setter
209 ++functionId;
211 break;
213 case typelib_TypeClass_INTERFACE_METHOD:
215 typelib_InterfaceMethodTypeDescription * mtd =
216 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
217 member.get());
218 OSL_ASSERT(mtd->pInterface != 0);
219 if (!t.is()) {
220 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
222 t.makeComplete();
223 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
224 mtd->aBase.nPosition];
225 forceSynchronous = mtd->bOneWay &&
226 functionId != SPECIAL_FUNCTION_ID_RELEASE;
227 break;
229 default:
230 OSL_ASSERT(false); // this cannot happen
231 break;
233 OSL_ASSERT(functionId >= 0);
234 if (functionId > SAL_MAX_UINT16) {
235 throw css::uno::RuntimeException(
236 "function ID too large for URP",
237 css::uno::Reference< css::uno::XInterface >());
239 std::vector< unsigned char > buf;
240 bool newType = !(lastType_.is() && t.equals(lastType_));
241 bool newOid = oid != lastOid_;
242 bool newTid = tid != lastTid_;
243 if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
244 // > 14 bit function ID
246 Marshal::write8(
247 &buf,
248 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
249 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
250 (forceSynchronous ? 0x01 : 0)));
251 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
252 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
253 if (forceSynchronous) {
254 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
256 if (functionId <= 0xFF) {
257 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
258 } else {
259 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
261 if (newType) {
262 marshal_.writeType(&buf, t);
264 if (newOid) {
265 marshal_.writeOid(&buf, oid);
267 if (newTid) {
268 marshal_.writeTid(&buf, tid);
270 } else if (functionId <= 0x3F) { // <= 6 bit function ID
271 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
272 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
273 } else {
274 Marshal::write8(
275 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
276 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
277 Marshal::write8(&buf, functionId & 0xFF);
279 if (currentContextMode) {
280 css::uno::UnoInterfaceReference cc(currentContext);
281 marshal_.writeValue(
282 &buf,
283 css::uno::TypeDescription(
284 cppu::UnoType<
285 css::uno::Reference< css::uno::XCurrentContext > >::get()),
286 BinaryAny(
287 css::uno::TypeDescription(
288 cppu::UnoType<
289 css::uno::Reference<
290 css::uno::XCurrentContext > >::get()),
291 &cc.m_pUnoI));
293 switch (member.get()->eTypeClass) {
294 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
295 if (!inArguments.empty()) { // setter
296 OSL_ASSERT(inArguments.size() == 1);
297 marshal_.writeValue(
298 &buf,
299 css::uno::TypeDescription(
300 reinterpret_cast<
301 typelib_InterfaceAttributeTypeDescription * >(
302 member.get())->
303 pAttributeTypeRef),
304 inArguments.front());
306 break;
307 case typelib_TypeClass_INTERFACE_METHOD:
309 typelib_InterfaceMethodTypeDescription * mtd =
310 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
311 member.get());
312 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
313 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
314 if (mtd->pParams[j].bIn) {
315 marshal_.writeValue(
316 &buf,
317 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
318 *i++);
321 OSL_ASSERT(i == inArguments.end());
322 break;
324 default:
325 OSL_ASSERT(false); // this cannot happen
326 break;
328 sendMessage(buf);
329 lastType_ = t;
330 lastOid_ = oid;
331 lastTid_ = tid;
334 void Writer::sendReply(
335 rtl::ByteSequence const & tid,
336 com::sun::star::uno::TypeDescription const & member, bool setter,
337 bool exception, BinaryAny const & returnValue,
338 std::vector< BinaryAny > const & outArguments)
340 OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
341 std::vector< unsigned char > buf;
342 bool newTid = tid != lastTid_;
343 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
344 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
345 if (newTid) {
346 marshal_.writeTid(&buf, tid);
348 if (exception) {
349 marshal_.writeValue(
350 &buf,
351 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
352 returnValue);
353 } else {
354 switch (member.get()->eTypeClass) {
355 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
356 if (!setter) {
357 marshal_.writeValue(
358 &buf,
359 css::uno::TypeDescription(
360 reinterpret_cast<
361 typelib_InterfaceAttributeTypeDescription * >(
362 member.get())->
363 pAttributeTypeRef),
364 returnValue);
366 break;
367 case typelib_TypeClass_INTERFACE_METHOD:
369 typelib_InterfaceMethodTypeDescription * mtd =
370 reinterpret_cast<
371 typelib_InterfaceMethodTypeDescription * >(
372 member.get());
373 marshal_.writeValue(
374 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
375 returnValue);
376 std::vector< BinaryAny >::const_iterator i(
377 outArguments.begin());
378 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
379 if (mtd->pParams[j].bOut) {
380 marshal_.writeValue(
381 &buf,
382 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
383 *i++);
386 OSL_ASSERT(i == outArguments.end());
387 break;
389 default:
390 OSL_ASSERT(false); // this cannot happen
391 break;
394 sendMessage(buf);
395 lastTid_ = tid;
396 bridge_->decrementCalls();
399 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
400 std::vector< unsigned char > header;
401 if (buffer.size() > SAL_MAX_UINT32) {
402 throw css::uno::RuntimeException(
403 "message too large for URP",
404 css::uno::Reference< css::uno::XInterface >());
406 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
407 Marshal::write32(&header, 1);
408 OSL_ASSERT(!buffer.empty());
409 unsigned char const * p = &buffer[0];
410 std::vector< unsigned char >::size_type n = buffer.size();
411 OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
412 sal_Size k = SAL_MAX_INT32 - header.size();
413 if (n < k) {
414 k = static_cast< sal_Size >(n);
416 css::uno::Sequence< sal_Int8 > s(
417 static_cast< sal_Int32 >(header.size() + k));
418 OSL_ASSERT(!header.empty());
419 memcpy(
420 s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
421 for (;;) {
422 memcpy(s.getArray() + s.getLength() - k, p, k);
423 try {
424 bridge_->getConnection()->write(s);
425 } catch (const css::io::IOException & e) {
426 css::uno::Any exc(cppu::getCaughtException());
427 throw css::lang::WrappedTargetRuntimeException(
428 "Binary URP write raised IO exception: " + e.Message,
429 css::uno::Reference< css::uno::XInterface >(), exc);
431 n = static_cast< std::vector< unsigned char >::size_type >(n - k);
432 if (n == 0) {
433 break;
435 p += k;
436 k = SAL_MAX_INT32;
437 if (n < k) {
438 k = static_cast< sal_Size >(n);
440 s.realloc(k);
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */