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 : #include <string.h>
25 :
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"
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 415785 : Writer::Item::Item()
42 : : request(false)
43 : , setter(false)
44 : , exception(false)
45 415785 : , setCurrentContextMode(false)
46 415785 : {}
47 :
48 23761 : 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 23761 : currentContext(theCurrentContext), setCurrentContextMode(false)
57 23761 : {}
58 :
59 391926 : 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 391926 : returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
68 391926 : {}
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 165 : 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 165 : css::uno::UnoInterfaceReference());
87 165 : }
88 :
89 141 : 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 141 : sendReply(tid, member, false, exception, returnValue,outArguments);
96 141 : }
97 :
98 23761 : 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 23761 : css::uno::UnoInterfaceReference cc(current_context::get());
105 47522 : osl::MutexGuard g(mutex_);
106 23761 : queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
107 47522 : items_.set();
108 23761 : }
109 :
110 391926 : 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 391926 : osl::MutexGuard g(mutex_);
117 : queue_.push_back(
118 : Item(
119 : tid, member, setter, exception, returnValue, outArguments,
120 391926 : setCurrentContextMode));
121 391926 : items_.set();
122 391926 : }
123 :
124 102 : 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 102 : unblocked_.set();
129 102 : }
130 :
131 102 : void Writer::stop() {
132 : {
133 102 : osl::MutexGuard g(mutex_);
134 102 : stop_ = true;
135 : }
136 102 : unblocked_.set();
137 102 : items_.set();
138 102 : }
139 :
140 204 : Writer::~Writer() {}
141 :
142 102 : void Writer::execute() {
143 : try {
144 102 : unblocked_.wait();
145 : for (;;) {
146 415785 : items_.wait();
147 415785 : Item item;
148 : {
149 415785 : osl::MutexGuard g(mutex_);
150 415785 : if (stop_) {
151 204 : return;
152 : }
153 : OSL_ASSERT(!queue_.empty());
154 415683 : item = queue_.front();
155 415683 : queue_.pop_front();
156 415683 : if (queue_.empty()) {
157 413399 : items_.reset();
158 415683 : }
159 : }
160 415683 : if (item.request) {
161 : sendRequest(
162 : item.tid, item.oid, item.type, item.member, item.arguments,
163 71271 : (item.oid != "UrpProtocolProperties" &&
164 : !item.member.equals(
165 : css::uno::TypeDescription(
166 132927 : "com.sun.star.uno.XInterface::release")) &&
167 14142 : bridge_->isCurrentContextMode()),
168 23757 : item.currentContext);
169 : } else {
170 : sendReply(
171 : item.tid, item.member, item.setter, item.exception,
172 391926 : item.returnValue, item.arguments);
173 391926 : if (item.setCurrentContextMode) {
174 0 : bridge_->setCurrentContextMode();
175 : }
176 : }
177 415683 : }
178 0 : } catch (const css::uno::Exception & e) {
179 : OSL_TRACE(
180 : "caught UNO exception '%s'",
181 : OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
182 0 : } catch (const std::exception & e) {
183 : OSL_TRACE("caught C++ exception '%s'", e.what());
184 : }
185 0 : bridge_->terminate(false);
186 0 : bridge_.clear();
187 : }
188 :
189 23922 : 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)
195 : {
196 : OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
197 23922 : css::uno::TypeDescription t(type);
198 23922 : sal_Int32 functionId = 0;
199 23922 : bool forceSynchronous = false;
200 23922 : member.makeComplete();
201 23922 : switch (member.get()->eTypeClass) {
202 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
203 : {
204 : typelib_InterfaceAttributeTypeDescription * atd =
205 : reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
206 1799 : member.get());
207 : OSL_ASSERT(atd->pInterface != 0);
208 1799 : if (!t.is()) {
209 1799 : t = css::uno::TypeDescription(&atd->pInterface->aBase);
210 : }
211 1799 : t.makeComplete();
212 : functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
213 1799 : atd->aBase.nPosition];
214 1799 : if (!inArguments.empty()) { // setter
215 0 : ++functionId;
216 : }
217 1799 : break;
218 : }
219 : case typelib_TypeClass_INTERFACE_METHOD:
220 : {
221 : typelib_InterfaceMethodTypeDescription * mtd =
222 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
223 22123 : member.get());
224 : assert(mtd->pInterface != 0);
225 22123 : if (!t.is()) {
226 12343 : t = css::uno::TypeDescription(&mtd->pInterface->aBase);
227 : }
228 22123 : t.makeComplete();
229 : functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
230 22123 : mtd->aBase.nPosition];
231 22123 : forceSynchronous = mtd->bOneWay &&
232 22123 : functionId != SPECIAL_FUNCTION_ID_RELEASE;
233 22123 : break;
234 : }
235 : default:
236 : OSL_ASSERT(false); // this cannot happen
237 0 : break;
238 : }
239 : OSL_ASSERT(functionId >= 0);
240 23922 : if (functionId > SAL_MAX_UINT16) {
241 0 : throw css::uno::RuntimeException("function ID too large for URP");
242 : }
243 23922 : std::vector< unsigned char > buf;
244 23922 : bool newType = !(lastType_.is() && t.equals(lastType_));
245 23922 : bool newOid = oid != lastOid_;
246 23922 : bool newTid = tid != lastTid_;
247 23922 : if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
248 : // > 14 bit function ID
249 : {
250 : Marshal::write8(
251 : &buf,
252 : (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
253 : (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
254 11288 : (forceSynchronous ? 0x01 : 0)));
255 : // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
256 : // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
257 11288 : if (forceSynchronous) {
258 0 : Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
259 : }
260 11288 : if (functionId <= 0xFF) {
261 11288 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
262 : } else {
263 0 : Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
264 : }
265 11288 : if (newType) {
266 3594 : marshal_.writeType(&buf, t);
267 : }
268 11288 : if (newOid) {
269 4534 : marshal_.writeOid(&buf, oid);
270 : }
271 22576 : if (newTid) {
272 6390 : marshal_.writeTid(&buf, tid);
273 : }
274 12634 : } else if (functionId <= 0x3F) { // <= 6 bit function ID
275 12634 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
276 : // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
277 : } else {
278 : Marshal::write8(
279 0 : &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
280 : // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
281 0 : Marshal::write8(&buf, functionId & 0xFF);
282 : }
283 23922 : if (currentContextMode) {
284 14142 : css::uno::UnoInterfaceReference cc(currentContext);
285 : marshal_.writeValue(
286 : &buf,
287 : css::uno::TypeDescription(
288 : cppu::UnoType<
289 14142 : css::uno::Reference< css::uno::XCurrentContext > >::get()),
290 : BinaryAny(
291 : css::uno::TypeDescription(
292 : cppu::UnoType<
293 : css::uno::Reference<
294 14142 : css::uno::XCurrentContext > >::get()),
295 28284 : &cc.m_pUnoI));
296 : }
297 23922 : switch (member.get()->eTypeClass) {
298 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
299 1799 : if (!inArguments.empty()) { // setter
300 : OSL_ASSERT(inArguments.size() == 1);
301 : marshal_.writeValue(
302 : &buf,
303 : css::uno::TypeDescription(
304 : reinterpret_cast<
305 : typelib_InterfaceAttributeTypeDescription * >(
306 0 : member.get())->
307 : pAttributeTypeRef),
308 0 : inArguments.front());
309 : }
310 1799 : break;
311 : case typelib_TypeClass_INTERFACE_METHOD:
312 : {
313 : typelib_InterfaceMethodTypeDescription * mtd =
314 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
315 22123 : member.get());
316 22123 : std::vector< BinaryAny >::const_iterator i(inArguments.begin());
317 34005 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
318 11882 : if (mtd->pParams[j].bIn) {
319 : marshal_.writeValue(
320 : &buf,
321 11868 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
322 23736 : *i++);
323 : }
324 : }
325 : OSL_ASSERT(i == inArguments.end());
326 22123 : break;
327 : }
328 : default:
329 : OSL_ASSERT(false); // this cannot happen
330 0 : break;
331 : }
332 23922 : sendMessage(buf);
333 23922 : lastType_ = t;
334 23922 : lastOid_ = oid;
335 23922 : lastTid_ = tid;
336 23922 : }
337 :
338 392067 : void Writer::sendReply(
339 : rtl::ByteSequence const & tid,
340 : com::sun::star::uno::TypeDescription const & member, bool setter,
341 : bool exception, BinaryAny const & returnValue,
342 : std::vector< BinaryAny > const & outArguments)
343 : {
344 : OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
345 392067 : std::vector< unsigned char > buf;
346 392067 : bool newTid = tid != lastTid_;
347 392067 : Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
348 : // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
349 392067 : if (newTid) {
350 6226 : marshal_.writeTid(&buf, tid);
351 : }
352 392067 : if (exception) {
353 : marshal_.writeValue(
354 : &buf,
355 1966 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
356 1966 : returnValue);
357 : } else {
358 390101 : switch (member.get()->eTypeClass) {
359 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
360 8002 : if (!setter) {
361 : marshal_.writeValue(
362 : &buf,
363 : css::uno::TypeDescription(
364 : reinterpret_cast<
365 : typelib_InterfaceAttributeTypeDescription * >(
366 7580 : member.get())->
367 : pAttributeTypeRef),
368 7580 : returnValue);
369 : }
370 8002 : break;
371 : case typelib_TypeClass_INTERFACE_METHOD:
372 : {
373 : typelib_InterfaceMethodTypeDescription * mtd =
374 : reinterpret_cast<
375 : typelib_InterfaceMethodTypeDescription * >(
376 382099 : member.get());
377 : marshal_.writeValue(
378 : &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
379 382099 : returnValue);
380 : std::vector< BinaryAny >::const_iterator i(
381 382099 : outArguments.begin());
382 698771 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
383 316672 : if (mtd->pParams[j].bOut) {
384 : marshal_.writeValue(
385 : &buf,
386 202 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
387 404 : *i++);
388 : }
389 : }
390 : OSL_ASSERT(i == outArguments.end());
391 382099 : break;
392 : }
393 : default:
394 : OSL_ASSERT(false); // this cannot happen
395 0 : break;
396 : }
397 : }
398 392067 : sendMessage(buf);
399 392067 : lastTid_ = tid;
400 392067 : bridge_->decrementCalls();
401 392067 : }
402 :
403 415989 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
404 415989 : std::vector< unsigned char > header;
405 415989 : if (buffer.size() > SAL_MAX_UINT32) {
406 : throw css::uno::RuntimeException(
407 0 : "message too large for URP");
408 : }
409 415989 : Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
410 415989 : Marshal::write32(&header, 1);
411 : OSL_ASSERT(!buffer.empty());
412 415989 : unsigned char const * p = &buffer[0];
413 415989 : std::vector< unsigned char >::size_type n = buffer.size();
414 : OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
415 415989 : sal_Size k = SAL_MAX_INT32 - header.size();
416 415989 : if (n < k) {
417 415989 : k = static_cast< sal_Size >(n);
418 : }
419 : css::uno::Sequence< sal_Int8 > s(
420 831978 : static_cast< sal_Int32 >(header.size() + k));
421 : OSL_ASSERT(!header.empty());
422 : memcpy(
423 415989 : s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
424 : for (;;) {
425 415989 : memcpy(s.getArray() + s.getLength() - k, p, k);
426 : try {
427 415989 : bridge_->getConnection()->write(s);
428 0 : } catch (const css::io::IOException & e) {
429 0 : css::uno::Any exc(cppu::getCaughtException());
430 : throw css::lang::WrappedTargetRuntimeException(
431 0 : "Binary URP write raised IO exception: " + e.Message,
432 0 : css::uno::Reference< css::uno::XInterface >(), exc);
433 : }
434 415989 : n = static_cast< std::vector< unsigned char >::size_type >(n - k);
435 415989 : if (n == 0) {
436 415989 : break;
437 : }
438 0 : p += k;
439 0 : k = SAL_MAX_INT32;
440 0 : if (n < k) {
441 0 : k = static_cast< sal_Size >(n);
442 : }
443 0 : s.realloc(k);
444 415989 : }
445 415989 : }
446 :
447 : }
448 :
449 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|