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 49 bool isProtocolPropertyMessage(rtl::OUString const & oid) { 50 return oid.equalsAsciiL( 51 RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")); 52 } 53 54 } 55 56 Writer::Item::Item() {} 57 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 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 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 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 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 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 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 133 void Writer::unblock() { 134 // Assumes that osl::Condition::set works as a memory barrier, so that 135 // changes made by preceeding sendDirectRequest/Reply calls are visible to 136 // subsequent sendRequest/Reply calls: 137 unblocked_.set(); 138 } 139 140 void Writer::stop() { 141 { 142 osl::MutexGuard g(mutex_); 143 stop_ = true; 144 } 145 unblocked_.set(); 146 items_.set(); 147 } 148 149 Writer::~Writer() {} 150 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 202 void Writer::onTerminated() { 203 release(); 204 } 205 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.getLength() != 0 && 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 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 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