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