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 207494 : Writer::Item::Item() {}
42 :
43 11855 : 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 11855 : arguments(inArguments), currentContext(theCurrentContext)
51 11855 : {}
52 :
53 195593 : 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 195593 : returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
62 195593 : {}
63 :
64 51 : Writer::Writer(rtl::Reference< Bridge > const & bridge):
65 : Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
66 51 : stop_(false)
67 : {
68 : OSL_ASSERT(bridge.is());
69 51 : }
70 :
71 80 : 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)
76 : {
77 : OSL_ASSERT(!unblocked_.check());
78 : sendRequest(
79 : tid, oid, type, member, inArguments, false,
80 80 : css::uno::UnoInterfaceReference());
81 80 : }
82 :
83 73 : 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)
87 : {
88 : OSL_ASSERT(!unblocked_.check());
89 73 : sendReply(tid, member, false, exception, returnValue,outArguments);
90 73 : }
91 :
92 11855 : 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)
97 : {
98 11855 : css::uno::UnoInterfaceReference cc(current_context::get());
99 23710 : osl::MutexGuard g(mutex_);
100 11855 : queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
101 23710 : items_.set();
102 11855 : }
103 :
104 195593 : 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)
109 : {
110 195593 : osl::MutexGuard g(mutex_);
111 : queue_.push_back(
112 : Item(
113 : tid, member, setter, exception, returnValue, outArguments,
114 195593 : setCurrentContextMode));
115 195593 : items_.set();
116 195593 : }
117 :
118 51 : 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 51 : unblocked_.set();
123 51 : }
124 :
125 50 : void Writer::stop() {
126 : {
127 50 : osl::MutexGuard g(mutex_);
128 50 : stop_ = true;
129 : }
130 50 : unblocked_.set();
131 50 : items_.set();
132 50 : }
133 :
134 100 : Writer::~Writer() {}
135 :
136 51 : void Writer::execute() {
137 : try {
138 51 : unblocked_.wait();
139 : for (;;) {
140 207495 : items_.wait();
141 207494 : Item item;
142 : {
143 207494 : osl::MutexGuard g(mutex_);
144 207494 : if (stop_) {
145 98 : return;
146 : }
147 : OSL_ASSERT(!queue_.empty());
148 207446 : item = queue_.front();
149 207446 : queue_.pop_front();
150 207446 : if (queue_.empty()) {
151 205973 : items_.reset();
152 207446 : }
153 : }
154 207446 : if (item.request) {
155 : sendRequest(
156 : item.tid, item.oid, item.type, item.member, item.arguments,
157 35559 : (item.oid != "UrpProtocolProperties" &&
158 : !item.member.equals(
159 : css::uno::TypeDescription(
160 66331 : "com.sun.star.uno.XInterface::release")) &&
161 7066 : bridge_->isCurrentContextMode()),
162 11853 : item.currentContext);
163 : } else {
164 : sendReply(
165 : item.tid, item.member, item.setter, item.exception,
166 195593 : item.returnValue, item.arguments);
167 195591 : if (item.setCurrentContextMode) {
168 0 : bridge_->setCurrentContextMode();
169 : }
170 : }
171 207446 : }
172 2 : } 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 0 : } catch (const std::exception & e) {
177 : OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
178 : }
179 2 : bridge_->terminate(false);
180 2 : bridge_.clear();
181 : }
182 :
183 11933 : 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)
189 : {
190 : OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
191 11933 : css::uno::TypeDescription t(type);
192 11933 : sal_Int32 functionId = 0;
193 11933 : bool forceSynchronous = false;
194 11933 : member.makeComplete();
195 11933 : switch (member.get()->eTypeClass) {
196 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
197 : {
198 : typelib_InterfaceAttributeTypeDescription * atd =
199 : reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
200 903 : member.get());
201 : OSL_ASSERT(atd->pInterface != 0);
202 903 : if (!t.is()) {
203 903 : t = css::uno::TypeDescription(&atd->pInterface->aBase);
204 : }
205 903 : t.makeComplete();
206 : functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
207 903 : atd->aBase.nPosition];
208 903 : if (!inArguments.empty()) { // setter
209 0 : ++functionId;
210 : }
211 903 : break;
212 : }
213 : case typelib_TypeClass_INTERFACE_METHOD:
214 : {
215 : typelib_InterfaceMethodTypeDescription * mtd =
216 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
217 11030 : member.get());
218 : OSL_ASSERT(mtd->pInterface != 0);
219 11030 : if (!t.is()) {
220 6163 : t = css::uno::TypeDescription(&mtd->pInterface->aBase);
221 : }
222 11030 : t.makeComplete();
223 : functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
224 11030 : mtd->aBase.nPosition];
225 11030 : forceSynchronous = mtd->bOneWay &&
226 11030 : functionId != SPECIAL_FUNCTION_ID_RELEASE;
227 11030 : break;
228 : }
229 : default:
230 : OSL_ASSERT(false); // this cannot happen
231 0 : break;
232 : }
233 : OSL_ASSERT(functionId >= 0);
234 11933 : if (functionId > SAL_MAX_UINT16) {
235 : throw css::uno::RuntimeException(
236 : "function ID too large for URP",
237 0 : css::uno::Reference< css::uno::XInterface >());
238 : }
239 11933 : std::vector< unsigned char > buf;
240 11933 : bool newType = !(lastType_.is() && t.equals(lastType_));
241 11933 : bool newOid = oid != lastOid_;
242 11933 : bool newTid = tid != lastTid_;
243 11933 : if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
244 : // > 14 bit function ID
245 : {
246 : Marshal::write8(
247 : &buf,
248 : (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
249 : (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
250 5643 : (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 5643 : if (forceSynchronous) {
254 0 : Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
255 : }
256 5643 : if (functionId <= 0xFF) {
257 5643 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
258 : } else {
259 0 : Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
260 : }
261 5643 : if (newType) {
262 1796 : marshal_.writeType(&buf, t);
263 : }
264 5643 : if (newOid) {
265 2267 : marshal_.writeOid(&buf, oid);
266 : }
267 11286 : if (newTid) {
268 3228 : marshal_.writeTid(&buf, tid);
269 : }
270 6290 : } else if (functionId <= 0x3F) { // <= 6 bit function ID
271 6290 : Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
272 : // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
273 : } else {
274 : Marshal::write8(
275 0 : &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
276 : // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
277 0 : Marshal::write8(&buf, functionId & 0xFF);
278 : }
279 11933 : if (currentContextMode) {
280 7066 : css::uno::UnoInterfaceReference cc(currentContext);
281 : marshal_.writeValue(
282 : &buf,
283 : css::uno::TypeDescription(
284 : cppu::UnoType<
285 7066 : css::uno::Reference< css::uno::XCurrentContext > >::get()),
286 : BinaryAny(
287 : css::uno::TypeDescription(
288 : cppu::UnoType<
289 : css::uno::Reference<
290 7066 : css::uno::XCurrentContext > >::get()),
291 14132 : &cc.m_pUnoI));
292 : }
293 11933 : switch (member.get()->eTypeClass) {
294 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
295 903 : 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 0 : member.get())->
303 : pAttributeTypeRef),
304 0 : inArguments.front());
305 : }
306 903 : break;
307 : case typelib_TypeClass_INTERFACE_METHOD:
308 : {
309 : typelib_InterfaceMethodTypeDescription * mtd =
310 : reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
311 11030 : member.get());
312 11030 : std::vector< BinaryAny >::const_iterator i(inArguments.begin());
313 16961 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
314 5931 : if (mtd->pParams[j].bIn) {
315 : marshal_.writeValue(
316 : &buf,
317 5924 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
318 11848 : *i++);
319 : }
320 : }
321 : OSL_ASSERT(i == inArguments.end());
322 11030 : break;
323 : }
324 : default:
325 : OSL_ASSERT(false); // this cannot happen
326 0 : break;
327 : }
328 11933 : sendMessage(buf);
329 11933 : lastType_ = t;
330 11933 : lastOid_ = oid;
331 11933 : lastTid_ = tid;
332 11933 : }
333 :
334 195666 : 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)
339 : {
340 : OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
341 195666 : std::vector< unsigned char > buf;
342 195666 : bool newTid = tid != lastTid_;
343 195666 : Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
344 : // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
345 195666 : if (newTid) {
346 3080 : marshal_.writeTid(&buf, tid);
347 : }
348 195666 : if (exception) {
349 : marshal_.writeValue(
350 : &buf,
351 982 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
352 982 : returnValue);
353 : } else {
354 194684 : switch (member.get()->eTypeClass) {
355 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
356 4001 : if (!setter) {
357 : marshal_.writeValue(
358 : &buf,
359 : css::uno::TypeDescription(
360 : reinterpret_cast<
361 : typelib_InterfaceAttributeTypeDescription * >(
362 3790 : member.get())->
363 : pAttributeTypeRef),
364 3790 : returnValue);
365 : }
366 4001 : break;
367 : case typelib_TypeClass_INTERFACE_METHOD:
368 : {
369 : typelib_InterfaceMethodTypeDescription * mtd =
370 : reinterpret_cast<
371 : typelib_InterfaceMethodTypeDescription * >(
372 190683 : member.get());
373 : marshal_.writeValue(
374 : &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
375 190683 : returnValue);
376 : std::vector< BinaryAny >::const_iterator i(
377 190683 : outArguments.begin());
378 349568 : for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
379 158885 : if (mtd->pParams[j].bOut) {
380 : marshal_.writeValue(
381 : &buf,
382 101 : css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
383 202 : *i++);
384 : }
385 : }
386 : OSL_ASSERT(i == outArguments.end());
387 190683 : break;
388 : }
389 : default:
390 : OSL_ASSERT(false); // this cannot happen
391 0 : break;
392 : }
393 : }
394 195666 : sendMessage(buf);
395 195664 : lastTid_ = tid;
396 195666 : bridge_->decrementCalls();
397 195664 : }
398 :
399 207599 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
400 207599 : std::vector< unsigned char > header;
401 207599 : if (buffer.size() > SAL_MAX_UINT32) {
402 : throw css::uno::RuntimeException(
403 : "message too large for URP",
404 0 : css::uno::Reference< css::uno::XInterface >());
405 : }
406 207599 : Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
407 207599 : Marshal::write32(&header, 1);
408 : OSL_ASSERT(!buffer.empty());
409 207599 : unsigned char const * p = &buffer[0];
410 207599 : std::vector< unsigned char >::size_type n = buffer.size();
411 : OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
412 207599 : sal_Size k = SAL_MAX_INT32 - header.size();
413 207599 : if (n < k) {
414 207599 : k = static_cast< sal_Size >(n);
415 : }
416 : css::uno::Sequence< sal_Int8 > s(
417 415198 : static_cast< sal_Int32 >(header.size() + k));
418 : OSL_ASSERT(!header.empty());
419 : memcpy(
420 207599 : s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
421 : for (;;) {
422 207599 : memcpy(s.getArray() + s.getLength() - k, p, k);
423 : try {
424 207601 : bridge_->getConnection()->write(s);
425 2 : } catch (const css::io::IOException & e) {
426 2 : css::uno::Any exc(cppu::getCaughtException());
427 : throw css::lang::WrappedTargetRuntimeException(
428 4 : "Binary URP write raised IO exception: " + e.Message,
429 6 : css::uno::Reference< css::uno::XInterface >(), exc);
430 : }
431 207597 : n = static_cast< std::vector< unsigned char >::size_type >(n - k);
432 207597 : if (n == 0) {
433 207597 : break;
434 : }
435 0 : p += k;
436 0 : k = SAL_MAX_INT32;
437 0 : if (n < k) {
438 0 : k = static_cast< sal_Size >(n);
439 : }
440 0 : s.realloc(k);
441 207599 : }
442 207597 : }
443 :
444 : }
445 :
446 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|