1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "sal/config.h"
25
26 #include <exception>
27 #include <vector>
28
29 #include "com/sun/star/connection/XConnection.hpp"
30 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
31 #include "com/sun/star/uno/XCurrentContext.hpp"
32 #include "cppuhelper/exc_hlp.hxx"
33 #include "osl/mutex.hxx"
34 #include "rtl/memory.h"
35 #include "uno/dispatcher.hxx"
36
37 #include "binaryany.hxx"
38 #include "bridge.hxx"
39 #include "currentcontext.hxx"
40 #include "specialfunctionids.hxx"
41 #include "writer.hxx"
42
43 namespace binaryurp {
44
45 namespace {
46
47 namespace css = com::sun::star;
48
isProtocolPropertyMessage(rtl::OUString const & oid)49 bool isProtocolPropertyMessage(rtl::OUString const & oid) {
50 return oid.equalsAsciiL(
51 RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties"));
52 }
53
54 }
55
Item()56 Writer::Item::Item() {}
57
Item(rtl::ByteSequence const & theTid,rtl::OUString const & theOid,css::uno::TypeDescription const & theType,css::uno::TypeDescription const & theMember,std::vector<BinaryAny> const & inArguments,css::uno::UnoInterfaceReference const & theCurrentContext)58 Writer::Item::Item(
59 rtl::ByteSequence const & theTid, rtl::OUString const & theOid,
60 css::uno::TypeDescription const & theType,
61 css::uno::TypeDescription const & theMember,
62 std::vector< BinaryAny > const & inArguments,
63 css::uno::UnoInterfaceReference const & theCurrentContext):
64 request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
65 arguments(inArguments), currentContext(theCurrentContext)
66 {}
67
Item(rtl::ByteSequence const & theTid,css::uno::TypeDescription const & theMember,bool theSetter,bool theException,BinaryAny const & theReturnValue,std::vector<BinaryAny> const & outArguments,bool theSetCurrentContextMode)68 Writer::Item::Item(
69 rtl::ByteSequence const & theTid,
70 css::uno::TypeDescription const & theMember, bool theSetter,
71 bool theException, BinaryAny const & theReturnValue,
72 std::vector< BinaryAny > const & outArguments,
73 bool theSetCurrentContextMode):
74 request(false), tid(theTid), member(theMember), setter(theSetter),
75 arguments(outArguments), exception(theException),
76 returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
77 {}
78
Writer(rtl::Reference<Bridge> const & bridge)79 Writer::Writer(rtl::Reference< Bridge > const & bridge):
80 bridge_(bridge), marshal_(bridge, state_), stop_(false)
81 {
82 OSL_ASSERT(bridge.is());
83 acquire();
84 }
85
sendDirectRequest(rtl::ByteSequence const & tid,rtl::OUString const & oid,css::uno::TypeDescription const & type,css::uno::TypeDescription const & member,std::vector<BinaryAny> const & inArguments)86 void Writer::sendDirectRequest(
87 rtl::ByteSequence const & tid, rtl::OUString const & oid,
88 css::uno::TypeDescription const & type,
89 css::uno::TypeDescription const & member,
90 std::vector< BinaryAny > const & inArguments)
91 {
92 OSL_ASSERT(!unblocked_.check());
93 sendRequest(
94 tid, oid, type, member, inArguments, false,
95 css::uno::UnoInterfaceReference());
96 }
97
sendDirectReply(rtl::ByteSequence const & tid,css::uno::TypeDescription const & member,bool exception,BinaryAny const & returnValue,std::vector<BinaryAny> const & outArguments)98 void Writer::sendDirectReply(
99 rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
100 bool exception, BinaryAny const & returnValue,
101 std::vector< BinaryAny > const & outArguments)
102 {
103 OSL_ASSERT(!unblocked_.check());
104 sendReply(tid, member, false, exception, returnValue,outArguments);
105 }
106
queueRequest(rtl::ByteSequence const & tid,rtl::OUString const & oid,css::uno::TypeDescription const & type,css::uno::TypeDescription const & member,std::vector<BinaryAny> const & inArguments)107 void Writer::queueRequest(
108 rtl::ByteSequence const & tid, rtl::OUString const & oid,
109 css::uno::TypeDescription const & type,
110 css::uno::TypeDescription const & member,
111 std::vector< BinaryAny > const & inArguments)
112 {
113 css::uno::UnoInterfaceReference cc(current_context::get());
114 osl::MutexGuard g(mutex_);
115 queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
116 items_.set();
117 }
118
queueReply(rtl::ByteSequence const & tid,com::sun::star::uno::TypeDescription const & member,bool setter,bool exception,BinaryAny const & returnValue,std::vector<BinaryAny> const & outArguments,bool setCurrentContextMode)119 void Writer::queueReply(
120 rtl::ByteSequence const & tid,
121 com::sun::star::uno::TypeDescription const & member, bool setter,
122 bool exception, BinaryAny const & returnValue,
123 std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
124 {
125 osl::MutexGuard g(mutex_);
126 queue_.push_back(
127 Item(
128 tid, member, setter, exception, returnValue, outArguments,
129 setCurrentContextMode));
130 items_.set();
131 }
132
unblock()133 void Writer::unblock() {
134 // Assumes that osl::Condition::set works as a memory barrier, so that
135 // changes made by preceding sendDirectRequest/Reply calls are visible to
136 // subsequent sendRequest/Reply calls:
137 unblocked_.set();
138 }
139
stop()140 void Writer::stop() {
141 {
142 osl::MutexGuard g(mutex_);
143 stop_ = true;
144 }
145 unblocked_.set();
146 items_.set();
147 }
148
~Writer()149 Writer::~Writer() {}
150
run()151 void Writer::run() {
152 setName("binaryurpWriter");
153 try {
154 unblocked_.wait();
155 for (;;) {
156 items_.wait();
157 Item item;
158 {
159 osl::MutexGuard g(mutex_);
160 if (stop_) {
161 return;
162 }
163 OSL_ASSERT(!queue_.empty());
164 item = queue_.front();
165 queue_.pop_front();
166 if (queue_.empty()) {
167 items_.reset();
168 }
169 }
170 if (item.request) {
171 sendRequest(
172 item.tid, item.oid, item.type, item.member, item.arguments,
173 (!item.oid.equalsAsciiL(
174 RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")) &&
175 !item.member.equals(
176 css::uno::TypeDescription(
177 rtl::OUString(
178 RTL_CONSTASCII_USTRINGPARAM(
179 "com.sun.star.uno.XInterface::"
180 "release")))) &&
181 bridge_->isCurrentContextMode()),
182 item.currentContext);
183 } else {
184 sendReply(
185 item.tid, item.member, item.setter, item.exception,
186 item.returnValue, item.arguments);
187 if (item.setCurrentContextMode) {
188 bridge_->setCurrentContextMode();
189 }
190 }
191 }
192 } catch (css::uno::Exception & e) {
193 OSL_TRACE(
194 OSL_LOG_PREFIX "caught UNO exception '%s'",
195 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
196 } catch (std::exception & e) {
197 OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
198 }
199 bridge_->terminate();
200 }
201
onTerminated()202 void Writer::onTerminated() {
203 release();
204 }
205
sendRequest(rtl::ByteSequence const & tid,rtl::OUString const & oid,css::uno::TypeDescription const & type,css::uno::TypeDescription const & member,std::vector<BinaryAny> const & inArguments,bool currentContextMode,css::uno::UnoInterfaceReference const & currentContext)206 void Writer::sendRequest(
207 rtl::ByteSequence const & tid, rtl::OUString const & oid,
208 css::uno::TypeDescription const & type,
209 css::uno::TypeDescription const & member,
210 std::vector< BinaryAny > const & inArguments, bool currentContextMode,
211 css::uno::UnoInterfaceReference const & currentContext)
212 {
213 OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
214 css::uno::TypeDescription t(type);
215 sal_Int32 functionId = 0;
216 bool forceSynchronous = false;
217 member.makeComplete();
218 switch (member.get()->eTypeClass) {
219 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
220 {
221 typelib_InterfaceAttributeTypeDescription * atd =
222 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
223 member.get());
224 OSL_ASSERT(atd->pInterface != 0);
225 if (!t.is()) {
226 t = css::uno::TypeDescription(&atd->pInterface->aBase);
227 }
228 t.makeComplete();
229 functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
230 atd->aBase.nPosition];
231 if (!inArguments.empty()) { // setter
232 ++functionId;
233 }
234 break;
235 }
236 case typelib_TypeClass_INTERFACE_METHOD:
237 {
238 typelib_InterfaceMethodTypeDescription * mtd =
239 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
240 member.get());
241 OSL_ASSERT(mtd->pInterface != 0);
242 if (!t.is()) {
243 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
244 }
245 t.makeComplete();
246 functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
247 mtd->aBase.nPosition];
248 forceSynchronous = mtd->bOneWay &&
249 functionId != SPECIAL_FUNCTION_ID_RELEASE;
250 break;
251 }
252 default:
253 OSL_ASSERT(false); // this cannot happen
254 break;
255 }
256 OSL_ASSERT(functionId >= 0);
257 if (functionId > SAL_MAX_UINT16) {
258 throw css::uno::RuntimeException(
259 rtl::OUString(
260 RTL_CONSTASCII_USTRINGPARAM("function ID too large for URP")),
261 css::uno::Reference< css::uno::XInterface >());
262 }
263 std::vector< unsigned char > buf;
264 bool newType = !(lastType_.is() && t.equals(lastType_));
265 bool newOid = oid != lastOid_;
266 bool newTid = tid != lastTid_;
267 if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
268 // > 14 bit function ID
269 {
270 Marshal::write8(
271 &buf,
272 (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
273 (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
274 (forceSynchronous ? 0x01 : 0)));
275 // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
276 // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
277 if (forceSynchronous) {
278 Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
279 }
280 if (functionId <= 0xFF) {
281 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
282 } else {
283 Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
284 }
285 if (newType) {
286 marshal_.writeType(&buf, t);
287 }
288 if (newOid) {
289 marshal_.writeOid(&buf, oid);
290 }
291 if (newTid) {
292 marshal_.writeTid(&buf, tid);
293 }
294 } else if (functionId <= 0x3F) { // <= 6 bit function ID
295 Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
296 // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
297 } else {
298 Marshal::write8(
299 &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
300 // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
301 Marshal::write8(&buf, functionId & 0xFF);
302 }
303 if (currentContextMode) {
304 css::uno::UnoInterfaceReference cc(currentContext);
305 marshal_.writeValue(
306 &buf,
307 css::uno::TypeDescription(
308 cppu::UnoType<
309 css::uno::Reference< css::uno::XCurrentContext > >::get()),
310 BinaryAny(
311 css::uno::TypeDescription(
312 cppu::UnoType<
313 css::uno::Reference<
314 css::uno::XCurrentContext > >::get()),
315 &cc.m_pUnoI));
316 }
317 switch (member.get()->eTypeClass) {
318 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
319 if (!inArguments.empty()) { // setter
320 OSL_ASSERT(inArguments.size() == 1);
321 marshal_.writeValue(
322 &buf,
323 css::uno::TypeDescription(
324 reinterpret_cast<
325 typelib_InterfaceAttributeTypeDescription * >(
326 member.get())->
327 pAttributeTypeRef),
328 inArguments.front());
329 }
330 break;
331 case typelib_TypeClass_INTERFACE_METHOD:
332 {
333 typelib_InterfaceMethodTypeDescription * mtd =
334 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
335 member.get());
336 std::vector< BinaryAny >::const_iterator i(inArguments.begin());
337 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
338 if (mtd->pParams[j].bIn) {
339 marshal_.writeValue(
340 &buf,
341 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
342 *i++);
343 }
344 }
345 OSL_ASSERT(i == inArguments.end());
346 break;
347 }
348 default:
349 OSL_ASSERT(false); // this cannot happen
350 break;
351 }
352 sendMessage(buf);
353 lastType_ = t;
354 lastOid_ = oid;
355 lastTid_ = tid;
356 }
357
sendReply(rtl::ByteSequence const & tid,com::sun::star::uno::TypeDescription const & member,bool setter,bool exception,BinaryAny const & returnValue,std::vector<BinaryAny> const & outArguments)358 void Writer::sendReply(
359 rtl::ByteSequence const & tid,
360 com::sun::star::uno::TypeDescription const & member, bool setter,
361 bool exception, BinaryAny const & returnValue,
362 std::vector< BinaryAny > const & outArguments)
363 {
364 OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
365 std::vector< unsigned char > buf;
366 bool newTid = tid != lastTid_;
367 Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
368 // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
369 if (newTid) {
370 marshal_.writeTid(&buf, tid);
371 }
372 if (exception) {
373 marshal_.writeValue(
374 &buf,
375 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
376 returnValue);
377 } else {
378 switch (member.get()->eTypeClass) {
379 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
380 if (!setter) {
381 marshal_.writeValue(
382 &buf,
383 css::uno::TypeDescription(
384 reinterpret_cast<
385 typelib_InterfaceAttributeTypeDescription * >(
386 member.get())->
387 pAttributeTypeRef),
388 returnValue);
389 }
390 break;
391 case typelib_TypeClass_INTERFACE_METHOD:
392 {
393 typelib_InterfaceMethodTypeDescription * mtd =
394 reinterpret_cast<
395 typelib_InterfaceMethodTypeDescription * >(
396 member.get());
397 marshal_.writeValue(
398 &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
399 returnValue);
400 std::vector< BinaryAny >::const_iterator i(
401 outArguments.begin());
402 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
403 if (mtd->pParams[j].bOut) {
404 marshal_.writeValue(
405 &buf,
406 css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
407 *i++);
408 }
409 }
410 OSL_ASSERT(i == outArguments.end());
411 break;
412 }
413 default:
414 OSL_ASSERT(false); // this cannot happen
415 break;
416 }
417 }
418 sendMessage(buf);
419 lastTid_ = tid;
420 bridge_->decrementCalls();
421 }
422
sendMessage(std::vector<unsigned char> const & buffer)423 void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
424 std::vector< unsigned char > header;
425 if (buffer.size() > SAL_MAX_UINT32) {
426 throw css::uno::RuntimeException(
427 rtl::OUString(
428 RTL_CONSTASCII_USTRINGPARAM("message too large for URP")),
429 css::uno::Reference< css::uno::XInterface >());
430 }
431 Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
432 Marshal::write32(&header, 1);
433 OSL_ASSERT(!buffer.empty());
434 unsigned char const * p = &buffer[0];
435 std::vector< unsigned char >::size_type n = buffer.size();
436 OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
437 sal_Size k = SAL_MAX_INT32 - header.size();
438 if (n < k) {
439 k = static_cast< sal_Size >(n);
440 }
441 css::uno::Sequence< sal_Int8 > s(
442 static_cast< sal_Int32 >(header.size() + k));
443 OSL_ASSERT(!header.empty());
444 rtl_copyMemory(
445 s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
446 for (;;) {
447 rtl_copyMemory(s.getArray() + s.getLength() - k, p, k);
448 try {
449 bridge_->getConnection()->write(s);
450 } catch (css::io::IOException & e) {
451 css::uno::Any exc(cppu::getCaughtException());
452 throw css::lang::WrappedTargetRuntimeException(
453 (rtl::OUString(
454 RTL_CONSTASCII_USTRINGPARAM(
455 "Binary URP write raised IO exception: ")) +
456 e.Message),
457 css::uno::Reference< css::uno::XInterface >(), exc);
458 }
459 n = static_cast< std::vector< unsigned char >::size_type >(n - k);
460 if (n == 0) {
461 break;
462 }
463 p += k;
464 k = SAL_MAX_INT32;
465 if (n < k) {
466 k = static_cast< sal_Size >(n);
467 }
468 s.realloc(k);
469 }
470 }
471
472 }
473