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 219282 : Writer::Item::Item()
42 : : request(false)
43 : , setter(false)
44 : , exception(false)
45 219282 : , setCurrentContextMode(false)
46 219282 : {}
47 :
48 11879 : 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 11879 : currentContext(theCurrentContext), setCurrentContextMode(false)
57 11879 : {}
58 :
59 207339 : 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 207339 : returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
68 207339 : {}
69 :
70 66 : Writer::Writer(rtl::Reference< Bridge > const & bridge):
71 : Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
72 66 : stop_(false)
73 : {
74 : OSL_ASSERT(bridge.is());
75 66 : }
76 :
77 103 : 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 103 : css::uno::UnoInterfaceReference());
87 103 : }
88 :
89 95 : 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 95 : sendReply(tid, member, false, exception, returnValue,outArguments);
96 95 : }
97 :
98 11879 : 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 11879 : css::uno::UnoInterfaceReference cc(current_context::get());
105 23758 : osl::MutexGuard g(mutex_);
106 11879 : queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
107 23758 : items_.set();
108 11879 : }
109 :
110 207339 : 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 207339 : osl::MutexGuard g(mutex_);
117 : queue_.push_back(
118 : Item(
119 : tid, member, setter, exception, returnValue, outArguments,
120 207339 : setCurrentContextMode));
121 207339 : items_.set();
122 207339 : }
123 :
124 66 : 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 66 : unblocked_.set();
129 66 : }
130 :
131 66 : void Writer::stop() {
132 : {
133 66 : osl::MutexGuard g(mutex_);
134 66 : stop_ = true;
135 : }
136 66 : unblocked_.set();
137 66 : items_.set();
138 66 : }
139 :
140 132 : Writer::~Writer() {}
141 :
142 66 : void Writer::execute() {
143 : try {
144 66 : unblocked_.wait();
145 : for (;;) {
146 219282 : items_.wait();
147 219282 : Item item;
148 : {
149 219282 : osl::MutexGuard g(mutex_);
150 219282 : if (stop_) {
151 132 : return;
152 : }
153 : OSL_ASSERT(!queue_.empty());
154 219216 : item = queue_.front();
155 219216 : queue_.pop_front();
156 219216 : if (queue_.empty()) {
157 216558 : items_.reset();
158 219216 : }
159 : }
160 219216 : if (item.request) {
161 : sendRequest(
162 : item.tid, item.oid, item.type, item.member, item.arguments,
163 35631 : (item.oid != "UrpProtocolProperties" &&
164 : !item.member.equals(
165 : css::uno::TypeDescription(
166 66525 : "com.sun.star.uno.XInterface::release")) &&
167 7140 : bridge_->isCurrentContextMode()),
168 11877 : item.currentContext);
169 : } else {
170 : sendReply(
171 : item.tid, item.member, item.setter, item.exception,
172 207339 : item.returnValue, item.arguments);
173 207339 : if (item.setCurrentContextMode) {
174 0 : bridge_->setCurrentContextMode();
175 : }
176 : }
177 219216 : }
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 11980 : 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 11980 : css::uno::TypeDescription t(type);
198 11980 : sal_Int32 functionId = 0;
199 11980 : bool forceSynchronous = false;
200 11980 : member.makeComplete();
201 11980 : switch (member.get()->eTypeClass) {
202 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
203 : {
204 : typelib_InterfaceAttributeTypeDescription * atd =
205 : reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
206 964 : member.get());
207 : OSL_ASSERT(atd->pInterface != 0);
208 964 : if (!t.is()) {
209 964 : t = css::uno::TypeDescription(&atd->pInterface->aBase);
210 : }
211 964 : t.makeComplete();
212 : functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
213 964 : atd->aBase.nPosition];
214 964 : if (!inArguments.empty()) { // setter
215 0 : ++functionId;
216 : }
217 964 : break;
218 : }
219 : case typelib_TypeClass_INTERFACE_METHOD:
220 : {
221 : typelib_InterfaceMethodTypeDescription * mtd =
222 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
223 11016 : member.get());
224 : assert(mtd->pInterface != 0);
225 11016 : if (!t.is()) {
226 6176 : t = css::uno::TypeDescription(&mtd->pInterface->aBase);
227 : }
228 11016 : t.makeComplete();
229 : functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
230 11016 : mtd->aBase.nPosition];
231 11016 : forceSynchronous = mtd->bOneWay &&
232 11016 : functionId != SPECIAL_FUNCTION_ID_RELEASE;
233 11016 : break;
234 : }
235 : default:
236 : OSL_ASSERT(false); // this cannot happen
237 0 : break;
238 : }
239 : OSL_ASSERT(functionId >= 0);
240 11980 : if (functionId > SAL_MAX_UINT16) {
241 0 : throw css::uno::RuntimeException("function ID too large for URP");
242 : }
243 11980 : std::vector< unsigned char > buf;
244 11980 : bool newType = !(lastType_.is() && t.equals(lastType_));
245 11980 : bool newOid = oid != lastOid_;
246 11980 : bool newTid = tid != lastTid_;
247 11980 : 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 5616 : (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 5616 : if (forceSynchronous) {
258 0 : Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
259 : }
260 5616 : if (functionId <= 0xFF) {
261 5616 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
262 : } else {
263 0 : Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
264 : }
265 5616 : if (newType) {
266 1910 : marshal_.writeType(&buf, t);
267 : }
268 5616 : if (newOid) {
269 2322 : marshal_.writeOid(&buf, oid);
270 : }
271 11232 : if (newTid) {
272 3081 : marshal_.writeTid(&buf, tid);
273 : }
274 6364 : } else if (functionId <= 0x3F) { // <= 6 bit function ID
275 6364 : 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 11980 : if (currentContextMode) {
284 7140 : css::uno::UnoInterfaceReference cc(currentContext);
285 : marshal_.writeValue(
286 : &buf,
287 : css::uno::TypeDescription(
288 : cppu::UnoType<
289 7140 : css::uno::Reference< css::uno::XCurrentContext > >::get()),
290 : BinaryAny(
291 : css::uno::TypeDescription(
292 : cppu::UnoType<
293 : css::uno::Reference<
294 7140 : css::uno::XCurrentContext > >::get()),
295 14280 : &cc.m_pUnoI));
296 : }
297 11980 : switch (member.get()->eTypeClass) {
298 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
299 964 : 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 964 : break;
311 : case typelib_TypeClass_INTERFACE_METHOD:
312 : {
313 : typelib_InterfaceMethodTypeDescription * mtd =
314 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
315 11016 : member.get());
316 11016 : std::vector< BinaryAny >::const_iterator i(inArguments.begin());
317 16983 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
318 5967 : if (mtd->pParams[j].bIn) {
319 : marshal_.writeValue(
320 : &buf,
321 5960 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
322 11920 : *i++);
323 : }
324 : }
325 : OSL_ASSERT(i == inArguments.end());
326 11016 : break;
327 : }
328 : default:
329 : OSL_ASSERT(false); // this cannot happen
330 0 : break;
331 : }
332 11980 : sendMessage(buf);
333 11980 : lastType_ = t;
334 11980 : lastOid_ = oid;
335 11980 : lastTid_ = tid;
336 11980 : }
337 :
338 207434 : 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 207434 : std::vector< unsigned char > buf;
346 207434 : bool newTid = tid != lastTid_;
347 207434 : Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
348 : // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
349 207434 : if (newTid) {
350 8045 : marshal_.writeTid(&buf, tid);
351 : }
352 207434 : if (exception) {
353 : marshal_.writeValue(
354 : &buf,
355 937 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
356 937 : returnValue);
357 : } else {
358 206497 : switch (member.get()->eTypeClass) {
359 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
360 3966 : if (!setter) {
361 : marshal_.writeValue(
362 : &buf,
363 : css::uno::TypeDescription(
364 : reinterpret_cast<
365 : typelib_InterfaceAttributeTypeDescription * >(
366 3780 : member.get())->
367 : pAttributeTypeRef),
368 3780 : returnValue);
369 : }
370 3966 : break;
371 : case typelib_TypeClass_INTERFACE_METHOD:
372 : {
373 : typelib_InterfaceMethodTypeDescription * mtd =
374 : reinterpret_cast<
375 : typelib_InterfaceMethodTypeDescription * >(
376 202531 : member.get());
377 : marshal_.writeValue(
378 : &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
379 202531 : returnValue);
380 : std::vector< BinaryAny >::const_iterator i(
381 202531 : outArguments.begin());
382 363162 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
383 160631 : if (mtd->pParams[j].bOut) {
384 : marshal_.writeValue(
385 : &buf,
386 101 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
387 202 : *i++);
388 : }
389 : }
390 : OSL_ASSERT(i == outArguments.end());
391 202531 : break;
392 : }
393 : default:
394 : OSL_ASSERT(false); // this cannot happen
395 0 : break;
396 : }
397 : }
398 207434 : sendMessage(buf);
399 207434 : lastTid_ = tid;
400 207434 : bridge_->decrementCalls();
401 207434 : }
402 :
403 219414 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
404 219414 : std::vector< unsigned char > header;
405 219414 : if (buffer.size() > SAL_MAX_UINT32) {
406 : throw css::uno::RuntimeException(
407 0 : "message too large for URP");
408 : }
409 219414 : Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
410 219414 : Marshal::write32(&header, 1);
411 : OSL_ASSERT(!buffer.empty());
412 219414 : unsigned char const * p = &buffer[0];
413 219414 : std::vector< unsigned char >::size_type n = buffer.size();
414 : OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
415 219414 : sal_Size k = SAL_MAX_INT32 - header.size();
416 219414 : if (n < k) {
417 219414 : k = static_cast< sal_Size >(n);
418 : }
419 : css::uno::Sequence< sal_Int8 > s(
420 438828 : static_cast< sal_Int32 >(header.size() + k));
421 : OSL_ASSERT(!header.empty());
422 : memcpy(
423 219414 : s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
424 : for (;;) {
425 219414 : memcpy(s.getArray() + s.getLength() - k, p, k);
426 : try {
427 219414 : 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 219414 : n = static_cast< std::vector< unsigned char >::size_type >(n - k);
435 219414 : if (n == 0) {
436 219414 : 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 219414 : }
445 219414 : }
446 :
447 : }
448 :
449 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|