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