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