Branch data Line data Source code
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 <exception>
23 : : #include <vector>
24 : :
25 : : #include "com/sun/star/connection/XConnection.hpp"
26 : : #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
27 : : #include "com/sun/star/uno/XCurrentContext.hpp"
28 : : #include "cppuhelper/exc_hlp.hxx"
29 : : #include "osl/mutex.hxx"
30 : : #include "rtl/memory.h"
31 : : #include "uno/dispatcher.hxx"
32 : :
33 : : #include "binaryany.hxx"
34 : : #include "bridge.hxx"
35 : : #include "currentcontext.hxx"
36 : : #include "specialfunctionids.hxx"
37 : : #include "writer.hxx"
38 : :
39 : : namespace binaryurp {
40 : :
41 : : namespace {
42 : :
43 : : namespace css = com::sun::star;
44 : :
45 : : }
46 : :
47 [ + - ]: 389594 : Writer::Item::Item() {}
48 : :
49 : 22782 : Writer::Item::Item(
50 : : rtl::ByteSequence const & theTid, OUString const & theOid,
51 : : css::uno::TypeDescription const & theType,
52 : : css::uno::TypeDescription const & theMember,
53 : : std::vector< BinaryAny > const & inArguments,
54 : : css::uno::UnoInterfaceReference const & theCurrentContext):
55 : : request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
56 [ + - ][ + - ]: 22782 : arguments(inArguments), currentContext(theCurrentContext)
57 : 22782 : {}
58 : :
59 : 366717 : 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 [ + - ]: 366717 : returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
68 : 366717 : {}
69 : :
70 : 102 : Writer::Writer(rtl::Reference< Bridge > const & bridge):
71 : : Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
72 [ + - ][ + - ]: 102 : stop_(false)
[ + - ][ + - ]
[ + - ][ + - ]
73 : : {
74 : : OSL_ASSERT(bridge.is());
75 : 102 : }
76 : :
77 : 161 : 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)
82 : : {
83 : : OSL_ASSERT(!unblocked_.check());
84 : : sendRequest(
85 : : tid, oid, type, member, inArguments, false,
86 [ + - ]: 161 : css::uno::UnoInterfaceReference());
87 : 161 : }
88 : :
89 : 145 : 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)
93 : : {
94 : : OSL_ASSERT(!unblocked_.check());
95 : 145 : sendReply(tid, member, false, exception, returnValue,outArguments);
96 : 145 : }
97 : :
98 : 22782 : 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)
103 : : {
104 [ + - ]: 22782 : css::uno::UnoInterfaceReference cc(current_context::get());
105 [ + - ]: 22782 : osl::MutexGuard g(mutex_);
106 [ + - ][ + - ]: 22782 : queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
[ + - ]
107 [ + - ][ + - ]: 22782 : items_.set();
[ + - ]
108 : 22782 : }
109 : :
110 : 366717 : 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)
115 : : {
116 [ + - ]: 366717 : osl::MutexGuard g(mutex_);
117 : : queue_.push_back(
118 : : Item(
119 : : tid, member, setter, exception, returnValue, outArguments,
120 [ + - ][ + - ]: 366717 : setCurrentContextMode));
[ + - ]
121 [ + - ][ + - ]: 366717 : items_.set();
122 : 366717 : }
123 : :
124 : 102 : void Writer::unblock() {
125 : : // Assumes that osl::Condition::set works as a memory barrier, so that
126 : : // changes made by preceeding sendDirectRequest/Reply calls are visible to
127 : : // subsequent sendRequest/Reply calls:
128 : 102 : unblocked_.set();
129 : 102 : }
130 : :
131 : 100 : void Writer::stop() {
132 : : {
133 [ + - ]: 100 : osl::MutexGuard g(mutex_);
134 [ + - ]: 100 : stop_ = true;
135 : : }
136 : 100 : unblocked_.set();
137 : 100 : items_.set();
138 : 100 : }
139 : :
140 [ + - ][ + - ]: 200 : Writer::~Writer() {}
[ + - ][ + - ]
[ - + ]
141 : :
142 : 102 : void Writer::execute() {
143 : : try {
144 [ + - ]: 102 : unblocked_.wait();
145 : 389593 : for (;;) {
146 [ + - ]: 389596 : items_.wait();
147 [ + - ]: 389594 : Item item;
148 : : {
149 [ + - ]: 389594 : osl::MutexGuard g(mutex_);
150 [ + + ]: 389594 : if (stop_) {
151 : 100 : return;
152 : : }
153 : : OSL_ASSERT(!queue_.empty());
154 [ + - ][ + - ]: 389495 : item = queue_.front();
155 [ + - ]: 389495 : queue_.pop_front();
156 [ + + ]: 389495 : if (queue_.empty()) {
157 [ + - ]: 389495 : items_.reset();
158 [ + - ][ + + ]: 389594 : }
159 : : }
160 [ + + ]: 389594 : if (item.request) {
161 : : sendRequest(
162 : : item.tid, item.oid, item.type, item.member, item.arguments,
163 : 22778 : (item.oid != "UrpProtocolProperties" &&
164 : : !item.member.equals(
165 : : css::uno::TypeDescription(
166 : : OUString(
167 : : RTL_CONSTASCII_USTRINGPARAM(
168 : : "com.sun.star.uno.XInterface::"
169 [ + - ][ + - ]: 45556 : "release")))) &&
[ + - ][ + - ]
[ # # # # ]
170 [ + - ]: 13606 : bridge_->isCurrentContextMode()),
171 [ + + ][ + - ]: 59162 : item.currentContext);
[ + - ][ + - ]
172 : : } else {
173 : : sendReply(
174 : : item.tid, item.member, item.setter, item.exception,
175 [ + + ]: 366717 : item.returnValue, item.arguments);
176 [ - + ]: 366716 : if (item.setCurrentContextMode) {
177 [ # # ]: 389494 : bridge_->setCurrentContextMode();
178 : : }
179 : : }
180 [ + - ][ + + ]: 389594 : }
[ - + - ]
181 : 1 : } catch (const css::uno::Exception & e) {
182 : : OSL_TRACE(
183 : : OSL_LOG_PREFIX "caught UNO exception '%s'",
184 : : OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
185 : 0 : } catch (const std::exception & e) {
186 : : OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
187 : : }
188 : 1 : bridge_->terminate(false);
189 : : }
190 : :
191 : 22939 : 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)
197 : : {
198 : : OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
199 : 22939 : css::uno::TypeDescription t(type);
200 : 22939 : sal_Int32 functionId = 0;
201 : 22939 : bool forceSynchronous = false;
202 : 22939 : member.makeComplete();
203 [ + + - ]: 22939 : switch (member.get()->eTypeClass) {
204 : : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
205 : : {
206 : : typelib_InterfaceAttributeTypeDescription * atd =
207 : : reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
208 : 1801 : member.get());
209 : : OSL_ASSERT(atd->pInterface != 0);
210 [ + - ]: 1801 : if (!t.is()) {
211 [ + - ]: 1801 : t = css::uno::TypeDescription(&atd->pInterface->aBase);
212 : : }
213 : 1801 : t.makeComplete();
214 : : functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
215 : 1801 : atd->aBase.nPosition];
216 [ - + ]: 1801 : if (!inArguments.empty()) { // setter
217 : 0 : ++functionId;
218 : : }
219 : 1801 : break;
220 : : }
221 : : case typelib_TypeClass_INTERFACE_METHOD:
222 : : {
223 : : typelib_InterfaceMethodTypeDescription * mtd =
224 : : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
225 : 21138 : member.get());
226 : : OSL_ASSERT(mtd->pInterface != 0);
227 [ + + ]: 21138 : if (!t.is()) {
228 [ + - ]: 11805 : t = css::uno::TypeDescription(&mtd->pInterface->aBase);
229 : : }
230 : 21138 : t.makeComplete();
231 : : functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
232 : 21138 : mtd->aBase.nPosition];
233 : : forceSynchronous = mtd->bOneWay &&
234 [ + + ][ + + ]: 21138 : functionId != SPECIAL_FUNCTION_ID_RELEASE;
235 : 21138 : break;
236 : : }
237 : : default:
238 : : OSL_ASSERT(false); // this cannot happen
239 : 0 : break;
240 : : }
241 : : OSL_ASSERT(functionId >= 0);
242 [ - + ]: 22939 : if (functionId > SAL_MAX_UINT16) {
243 : : throw css::uno::RuntimeException(
244 : : OUString(
245 : : RTL_CONSTASCII_USTRINGPARAM("function ID too large for URP")),
246 [ # # ][ # # ]: 0 : css::uno::Reference< css::uno::XInterface >());
247 : : }
248 [ + - ]: 22939 : std::vector< unsigned char > buf;
249 [ + + ][ + - ]: 22939 : bool newType = !(lastType_.is() && t.equals(lastType_));
[ + + ]
250 : 22939 : bool newOid = oid != lastOid_;
251 : 22939 : bool newTid = tid != lastTid_;
252 [ + + ][ + + ]: 22939 : if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
[ + + ][ - + ]
[ + + ]
253 : : // > 14 bit function ID
254 : : {
255 : : Marshal::write8(
256 : : &buf,
257 : : (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
258 : : (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
259 [ + + ][ + + ]: 12076 : (forceSynchronous ? 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 [ + + ]: 12076 : if (forceSynchronous) {
263 [ + - ]: 1148 : Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
264 : : }
265 [ + - ]: 12076 : if (functionId <= 0xFF) {
266 [ + - ]: 12076 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
267 : : } else {
268 [ # # ]: 0 : Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
269 : : }
270 [ + + ]: 12076 : if (newType) {
271 [ + - ]: 3523 : marshal_.writeType(&buf, t);
272 : : }
273 [ + + ]: 12076 : if (newOid) {
274 [ + - ]: 4572 : marshal_.writeOid(&buf, oid);
275 : : }
276 [ + + ]: 18723 : if (newTid) {
277 [ + - ]: 6647 : marshal_.writeTid(&buf, tid);
278 : : }
279 [ + - ]: 10863 : } else if (functionId <= 0x3F) { // <= 6 bit function ID
280 [ + - ]: 10863 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
281 : : // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
282 : : } else {
283 : : Marshal::write8(
284 [ # # ]: 0 : &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
285 : : // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
286 [ # # ]: 0 : Marshal::write8(&buf, functionId & 0xFF);
287 : : }
288 [ + + ]: 22939 : if (currentContextMode) {
289 [ + - ]: 13606 : css::uno::UnoInterfaceReference cc(currentContext);
290 : : marshal_.writeValue(
291 : : &buf,
292 : : css::uno::TypeDescription(
293 : : cppu::UnoType<
294 [ + - ]: 13606 : css::uno::Reference< css::uno::XCurrentContext > >::get()),
295 : : BinaryAny(
296 : : css::uno::TypeDescription(
297 : : cppu::UnoType<
298 : : css::uno::Reference<
299 [ + - ]: 13606 : css::uno::XCurrentContext > >::get()),
300 [ + - ][ + - ]: 27212 : &cc.m_pUnoI));
301 : : }
302 [ + + - ]: 22939 : switch (member.get()->eTypeClass) {
303 : : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
304 [ - + ]: 1801 : if (!inArguments.empty()) { // setter
305 : : OSL_ASSERT(inArguments.size() == 1);
306 : : marshal_.writeValue(
307 : : &buf,
308 : : css::uno::TypeDescription(
309 : : reinterpret_cast<
310 : : typelib_InterfaceAttributeTypeDescription * >(
311 : 0 : member.get())->
312 : : pAttributeTypeRef),
313 [ # # # # ]: 0 : inArguments.front());
314 : : }
315 : 1801 : break;
316 : : case typelib_TypeClass_INTERFACE_METHOD:
317 : : {
318 : : typelib_InterfaceMethodTypeDescription * mtd =
319 : : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
320 : 21138 : member.get());
321 : 21138 : std::vector< BinaryAny >::const_iterator i(inArguments.begin());
322 [ + + ]: 32467 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
323 [ + + ]: 11329 : if (mtd->pParams[j].bIn) {
324 : : marshal_.writeValue(
325 : : &buf,
326 : 11319 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
327 [ + - ][ + - ]: 11319 : *i++);
328 : : }
329 : : }
330 : : OSL_ASSERT(i == inArguments.end());
331 : : break;
332 : : }
333 : : default:
334 : : OSL_ASSERT(false); // this cannot happen
335 : 0 : break;
336 : : }
337 [ + - ]: 22939 : sendMessage(buf);
338 [ + - ]: 22939 : lastType_ = t;
339 : 22939 : lastOid_ = oid;
340 : 22939 : lastTid_ = tid;
341 : 22939 : }
342 : :
343 : 366862 : void Writer::sendReply(
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 : : OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
350 [ + - ]: 366862 : std::vector< unsigned char > buf;
351 : 366862 : bool newTid = tid != lastTid_;
352 [ + + ][ + - ]: 366862 : Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
[ + + ]
353 : : // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
354 [ + + ]: 366862 : if (newTid) {
355 [ + - ]: 6352 : marshal_.writeTid(&buf, tid);
356 : : }
357 [ + + ]: 366862 : if (exception) {
358 : : marshal_.writeValue(
359 : : &buf,
360 : 1784 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
361 [ + - ]: 1784 : returnValue);
362 : : } else {
363 [ + + - ]: 365078 : switch (member.get()->eTypeClass) {
364 : : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
365 [ + + ]: 7514 : if (!setter) {
366 : : marshal_.writeValue(
367 : : &buf,
368 : : css::uno::TypeDescription(
369 : : reinterpret_cast<
370 : : typelib_InterfaceAttributeTypeDescription * >(
371 : 7032 : member.get())->
372 : : pAttributeTypeRef),
373 [ + - ]: 7032 : returnValue);
374 : : }
375 : 7514 : break;
376 : : case typelib_TypeClass_INTERFACE_METHOD:
377 : : {
378 : : typelib_InterfaceMethodTypeDescription * mtd =
379 : : reinterpret_cast<
380 : : typelib_InterfaceMethodTypeDescription * >(
381 : 357564 : member.get());
382 : : marshal_.writeValue(
383 : : &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
384 [ + - ]: 357564 : returnValue);
385 : : std::vector< BinaryAny >::const_iterator i(
386 : 357564 : outArguments.begin());
387 [ + + ]: 655596 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
388 [ + + ]: 298032 : if (mtd->pParams[j].bOut) {
389 : : marshal_.writeValue(
390 : : &buf,
391 : 202 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
392 [ + - ][ + - ]: 202 : *i++);
393 : : }
394 : : }
395 : : OSL_ASSERT(i == outArguments.end());
396 : : break;
397 : : }
398 : : default:
399 : : OSL_ASSERT(false); // this cannot happen
400 : 0 : break;
401 : : }
402 : : }
403 [ + + ]: 366862 : sendMessage(buf);
404 : 366861 : lastTid_ = tid;
405 [ + - ]: 366862 : bridge_->decrementCalls();
406 : 366861 : }
407 : :
408 : 389801 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
409 [ + - ]: 389801 : std::vector< unsigned char > header;
410 [ - + ]: 389801 : if (buffer.size() > SAL_MAX_UINT32) {
411 : : throw css::uno::RuntimeException(
412 : : OUString(
413 : : RTL_CONSTASCII_USTRINGPARAM("message too large for URP")),
414 [ # # ][ # # ]: 0 : css::uno::Reference< css::uno::XInterface >());
415 : : }
416 [ + - ]: 389801 : Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
417 [ + - ]: 389801 : Marshal::write32(&header, 1);
418 : : OSL_ASSERT(!buffer.empty());
419 [ + - ]: 389801 : unsigned char const * p = &buffer[0];
420 : 389801 : std::vector< unsigned char >::size_type n = buffer.size();
421 : : OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
422 : 389801 : sal_Size k = SAL_MAX_INT32 - header.size();
423 [ + - ]: 389801 : if (n < k) {
424 : 389801 : k = static_cast< sal_Size >(n);
425 : : }
426 : : css::uno::Sequence< sal_Int8 > s(
427 [ + - ]: 389801 : static_cast< sal_Int32 >(header.size() + k));
428 : : OSL_ASSERT(!header.empty());
429 : : rtl_copyMemory(
430 [ + - ][ + - ]: 389801 : s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
[ + - ]
431 : 0 : for (;;) {
432 [ + - ][ + - ]: 389801 : rtl_copyMemory(s.getArray() + s.getLength() - k, p, k);
433 : : try {
434 [ + - ][ + - ]: 389801 : bridge_->getConnection()->write(s);
[ + + ]
435 [ - + ]: 2 : } catch (const css::io::IOException & e) {
436 [ - + ]: 1 : css::uno::Any exc(cppu::getCaughtException());
437 : : throw css::lang::WrappedTargetRuntimeException(
438 : : (OUString(
439 : : RTL_CONSTASCII_USTRINGPARAM(
440 : : "Binary URP write raised IO exception: ")) +
441 : : e.Message),
442 [ - + ][ - + ]: 1 : css::uno::Reference< css::uno::XInterface >(), exc);
443 : : }
444 : 389800 : n = static_cast< std::vector< unsigned char >::size_type >(n - k);
445 [ + - ]: 389800 : if (n == 0) {
446 : 389800 : break;
447 : : }
448 : 0 : p += k;
449 : 0 : k = SAL_MAX_INT32;
450 [ # # ]: 0 : if (n < k) {
451 : 0 : k = static_cast< sal_Size >(n);
452 : : }
453 [ # # ]: 0 : s.realloc(k);
454 [ + - ]: 389801 : }
455 : 389800 : }
456 : :
457 : : }
458 : :
459 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|