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 <memory> 32 #include <vector> 33 34 #include "com/sun/star/connection/XConnection.hpp" 35 #include "com/sun/star/io/IOException.hpp" 36 #include "com/sun/star/uno/Any.hxx" 37 #include "com/sun/star/uno/Exception.hpp" 38 #include "com/sun/star/uno/Reference.hxx" 39 #include "com/sun/star/uno/RuntimeException.hpp" 40 #include "com/sun/star/uno/Sequence.hxx" 41 #include "com/sun/star/uno/Type.hxx" 42 #include "com/sun/star/uno/XCurrentContext.hpp" 43 #include "com/sun/star/uno/XInterface.hpp" 44 #include "cppu/unotype.hxx" 45 #include "osl/diagnose.h" 46 #include "rtl/byteseq.h" 47 #include "rtl/string.h" 48 #include "rtl/textenc.h" 49 #include "rtl/ustring.h" 50 #include "rtl/ustring.hxx" 51 #include "sal/types.h" 52 #include "typelib/typeclass.h" 53 #include "typelib/typedescription.h" 54 #include "typelib/typedescription.hxx" 55 #include "uno/lbnames.h" 56 57 #include "binaryany.hxx" 58 #include "bridge.hxx" 59 #include "incomingreply.hxx" 60 #include "incomingrequest.hxx" 61 #include "outgoingrequest.hxx" 62 #include "reader.hxx" 63 #include "specialfunctionids.hxx" 64 #include "unmarshal.hxx" 65 66 namespace binaryurp { 67 68 namespace { 69 70 namespace css = com::sun::star; 71 72 css::uno::Sequence< sal_Int8 > read( 73 css::uno::Reference< css::connection::XConnection > const & connection, 74 sal_uInt32 size, bool eofOk) 75 { 76 OSL_ASSERT(connection.is()); 77 if (size > SAL_MAX_INT32) { 78 throw css::uno::RuntimeException( 79 rtl::OUString( 80 RTL_CONSTASCII_USTRINGPARAM( 81 "binaryurp::Reader: block size too large")), 82 css::uno::Reference< css::uno::XInterface >()); 83 } 84 css::uno::Sequence< sal_Int8 > buf; 85 sal_Int32 n = connection->read(buf, static_cast< sal_Int32 >(size)); 86 if (n == 0 && eofOk) { 87 return css::uno::Sequence< sal_Int8 >(); 88 } 89 if (n != static_cast< sal_Int32 >(size)) { 90 throw css::io::IOException( 91 rtl::OUString( 92 RTL_CONSTASCII_USTRINGPARAM( 93 "binaryurp::Reader: premature end of input")), 94 css::uno::Reference< css::uno::XInterface >()); 95 } 96 OSL_ASSERT(buf.getLength() == static_cast< sal_Int32 >(size)); 97 return buf; 98 } 99 100 extern "C" void SAL_CALL request(void * pThreadSpecificData) { 101 OSL_ASSERT(pThreadSpecificData != 0); 102 std::auto_ptr< IncomingRequest >( 103 static_cast< IncomingRequest * >(pThreadSpecificData))-> 104 execute(); 105 } 106 107 } 108 109 Reader::Reader(rtl::Reference< Bridge > const & bridge): bridge_(bridge) { 110 OSL_ASSERT(bridge.is()); 111 acquire(); 112 } 113 114 Reader::~Reader() {} 115 116 void Reader::run() { 117 setName("binaryurpReader"); 118 try { 119 bridge_->sendRequestChangeRequest(); 120 css::uno::Reference< css::connection::XConnection > con( 121 bridge_->getConnection()); 122 for (;;) { 123 css::uno::Sequence< sal_Int8 > s(read(con, 8, true)); 124 if (s.getLength() == 0) { 125 break; 126 } 127 Unmarshal header(bridge_, state_, s); 128 sal_uInt32 size = header.read32(); 129 sal_uInt32 count = header.read32(); 130 header.done(); 131 if (count == 0) { 132 throw css::io::IOException( 133 rtl::OUString( 134 RTL_CONSTASCII_USTRINGPARAM( 135 "binaryurp::Reader: block with zero message count" 136 " received")), 137 css::uno::Reference< css::uno::XInterface >()); 138 } 139 Unmarshal block(bridge_, state_, read(con, size, false)); 140 for (sal_uInt32 i = 0; i != count; ++i) { 141 readMessage(block); 142 } 143 block.done(); 144 } 145 } catch (css::uno::Exception & e) { 146 OSL_TRACE( 147 OSL_LOG_PREFIX "caught UNO exception '%s'", 148 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 149 } catch (std::exception & e) { 150 OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); 151 } 152 bridge_->terminate(); 153 } 154 155 void Reader::onTerminated() { 156 release(); 157 } 158 159 void Reader::readMessage(Unmarshal & unmarshal) { 160 sal_uInt8 flags1 = unmarshal.read8(); 161 bool newType; 162 bool newOid; 163 bool newTid; 164 bool forceSynchronous; 165 sal_uInt16 functionId; 166 if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER 167 if ((flags1 & 0x40) == 0) { // bit 6: REQUEST 168 readReplyMessage(unmarshal, flags1); 169 return; 170 } 171 newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE 172 newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID 173 newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID 174 if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS 175 sal_uInt8 flags2 = unmarshal.read8(); 176 forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY 177 if (((flags2 & 0x40) != 0) != forceSynchronous) { 178 // bit 6: SYNCHRONOUS 179 throw css::uno::RuntimeException( 180 rtl::OUString( 181 RTL_CONSTASCII_USTRINGPARAM( 182 "URP: request message with MUSTREPLY != SYNCHRONOUS" 183 " received")), 184 css::uno::Reference< css::uno::XInterface >()); 185 } 186 } else { 187 forceSynchronous = false; 188 } 189 functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16 190 ? unmarshal.read16() : unmarshal.read8(); 191 } else { 192 newType = false; 193 newOid = false; 194 newTid = false; 195 forceSynchronous = false; 196 functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14 197 ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F; 198 } 199 css::uno::TypeDescription type; 200 if (newType) { 201 type = unmarshal.readType(); 202 lastType_ = type; 203 } else { 204 if (!lastType_.is()) { 205 throw css::uno::RuntimeException( 206 rtl::OUString( 207 RTL_CONSTASCII_USTRINGPARAM( 208 "URP: request message with NEWTYPE received when last" 209 " interface type has not yet been set")), 210 css::uno::Reference< css::uno::XInterface >()); 211 } 212 type = lastType_; 213 } 214 rtl::OUString oid; 215 if (newOid) { 216 oid = unmarshal.readOid(); 217 if (oid.getLength() == 0) { 218 throw css::io::IOException( 219 rtl::OUString( 220 RTL_CONSTASCII_USTRINGPARAM( 221 "binaryurp::Unmarshal: emtpy OID")), 222 css::uno::Reference< css::uno::XInterface >()); 223 } 224 lastOid_ = oid; 225 } else { 226 if (lastOid_.getLength() == 0) { 227 throw css::uno::RuntimeException( 228 rtl::OUString( 229 RTL_CONSTASCII_USTRINGPARAM( 230 "URP: request message with NEWOID received when last" 231 " OID has not yet been set")), 232 css::uno::Reference< css::uno::XInterface >()); 233 } 234 oid = lastOid_; 235 } 236 rtl::ByteSequence tid(getTid(unmarshal, newTid)); 237 lastTid_ = tid; 238 type.makeComplete(); 239 if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) { 240 throw css::uno::RuntimeException( 241 rtl::OUString( 242 RTL_CONSTASCII_USTRINGPARAM( 243 "URP: request message with non-interface interface type" 244 " received")), 245 css::uno::Reference< css::uno::XInterface >()); 246 } 247 typelib_InterfaceTypeDescription * itd = 248 reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()); 249 if (functionId >= itd->nMapFunctionIndexToMemberIndex) { 250 throw css::uno::RuntimeException( 251 rtl::OUString( 252 RTL_CONSTASCII_USTRINGPARAM( 253 "URP: request message with unknown function ID received")), 254 css::uno::Reference< css::uno::XInterface >()); 255 } 256 sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId]; 257 css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]); 258 memberTd.makeComplete(); 259 OSL_ASSERT(memberTd.is()); 260 bool protProps = bridge_->isProtocolPropertiesRequest(oid, type); 261 bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE && 262 bridge_->isCurrentContextMode(); 263 css::uno::UnoInterfaceReference cc; 264 if (ccMode) { 265 css::uno::TypeDescription t( 266 cppu::UnoType< css::uno::Reference< css::uno::XCurrentContext > >:: 267 get()); 268 cc.set( 269 *static_cast< uno_Interface ** >( 270 unmarshal.readValue(t).getValue(t))); 271 } 272 bool synchronous; 273 if (memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD && 274 (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( 275 memberTd.get())-> 276 bOneWay)) 277 { 278 synchronous = forceSynchronous; 279 } else { 280 if (forceSynchronous) { 281 throw css::uno::RuntimeException( 282 rtl::OUString( 283 RTL_CONSTASCII_USTRINGPARAM( 284 "URP: synchronous request message with non-oneway" 285 " function ID received")), 286 css::uno::Reference< css::uno::XInterface >()); 287 } 288 synchronous = true; 289 } 290 bool setter = false; 291 std::vector< BinaryAny > inArgs; 292 switch (memberTd.get()->eTypeClass) { 293 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 294 setter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId; 295 // pMapMemberIndexToFunctionIndex contains function index of 296 // attribute getter 297 if (setter) { 298 inArgs.push_back( 299 unmarshal.readValue( 300 css::uno::TypeDescription( 301 reinterpret_cast< 302 typelib_InterfaceAttributeTypeDescription * >( 303 memberTd.get())-> 304 pAttributeTypeRef))); 305 } 306 break; 307 case typelib_TypeClass_INTERFACE_METHOD: 308 { 309 typelib_InterfaceMethodTypeDescription * mtd = 310 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( 311 memberTd.get()); 312 for (sal_Int32 i = 0; i != mtd->nParams; ++i) { 313 if (mtd->pParams[i].bIn) { 314 inArgs.push_back( 315 unmarshal.readValue( 316 css::uno::TypeDescription( 317 mtd->pParams[i].pTypeRef))); 318 } 319 } 320 break; 321 } 322 default: 323 OSL_ASSERT(false); // this cannot happen 324 break; 325 } 326 bridge_->incrementCalls( 327 !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE); 328 if (protProps) { 329 switch (functionId) { 330 case SPECIAL_FUNCTION_ID_REQUEST_CHANGE: 331 bridge_->handleRequestChangeRequest(tid, inArgs); 332 break; 333 case SPECIAL_FUNCTION_ID_COMMIT_CHANGE: 334 bridge_->handleCommitChangeRequest(tid, inArgs); 335 break; 336 default: 337 throw css::uno::RuntimeException( 338 rtl::OUString( 339 RTL_CONSTASCII_USTRINGPARAM( 340 "URP: request message with UrpProtocolProperties OID" 341 " and unknown function ID received")), 342 css::uno::Reference< css::uno::XInterface >()); 343 } 344 } else { 345 css::uno::UnoInterfaceReference obj; 346 switch (functionId) { 347 case SPECIAL_FUNCTION_ID_QUERY_INTERFACE: 348 obj = bridge_->findStub(oid, type); 349 if (!obj.is()) { 350 OSL_ASSERT( 351 inArgs.size() == 1 352 && inArgs[0].getType().equals( 353 css::uno::TypeDescription( 354 cppu::UnoType< css::uno::Type >::get()))); 355 if (!(type.equals( 356 css::uno::TypeDescription( 357 cppu::UnoType< 358 css::uno::Reference< 359 css::uno::XInterface > >::get())) 360 && (css::uno::TypeDescription( 361 *static_cast< 362 typelib_TypeDescriptionReference ** >( 363 inArgs[0].getValue(inArgs[0].getType()))). 364 equals( 365 css::uno::TypeDescription( 366 cppu::UnoType< 367 css::uno::Reference< 368 css::uno::XInterface > >::get()))))) 369 { 370 throw css::uno::RuntimeException( 371 rtl::OUString( 372 RTL_CONSTASCII_USTRINGPARAM( 373 "URP: queryInterface request message with" 374 " unknown OID received")), 375 css::uno::Reference< css::uno::XInterface >()); 376 } 377 } 378 break; 379 case SPECIAL_FUNCTION_ID_RESERVED: 380 throw css::uno::RuntimeException( 381 rtl::OUString( 382 RTL_CONSTASCII_USTRINGPARAM( 383 "URP: request message with unknown function ID 1" 384 " received")), 385 css::uno::Reference< css::uno::XInterface >()); 386 case SPECIAL_FUNCTION_ID_RELEASE: 387 break; 388 default: 389 obj = bridge_->findStub(oid, type); 390 if (!obj.is()) { 391 throw css::uno::RuntimeException( 392 rtl::OUString( 393 RTL_CONSTASCII_USTRINGPARAM( 394 "URP: request message with unknown OID received")), 395 css::uno::Reference< css::uno::XInterface >()); 396 } 397 break; 398 } 399 std::auto_ptr< IncomingRequest > req( 400 new IncomingRequest( 401 bridge_, tid, oid, obj, type, functionId, synchronous, memberTd, 402 setter, inArgs, ccMode, cc)); 403 if (synchronous) { 404 bridge_->incrementActiveCalls(); 405 } 406 uno_threadpool_putJob( 407 bridge_->getThreadPool(), tid.getHandle(), req.get(), &request, 408 !synchronous); 409 req.release(); 410 } 411 } 412 413 void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) { 414 rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0)); 415 // bit 3: NEWTID 416 lastTid_ = tid; 417 OutgoingRequest req(bridge_->lastOutgoingRequest(tid)); 418 bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION 419 BinaryAny ret; 420 std::vector< BinaryAny > outArgs; 421 if (exc) { 422 ret = unmarshal.readValue( 423 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get())); 424 if (!typelib_typedescription_isAssignableFrom( 425 (css::uno::TypeDescription( 426 cppu::UnoType< css::uno::RuntimeException >::get()). 427 get()), 428 ret.getType().get())) 429 { 430 sal_Int32 n = 0; 431 typelib_TypeDescriptionReference ** p = 0; 432 switch (req.member.get()->eTypeClass) { 433 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 434 { 435 typelib_InterfaceAttributeTypeDescription * atd = 436 reinterpret_cast< 437 typelib_InterfaceAttributeTypeDescription * >( 438 req.member.get()); 439 n = req.setter ? atd->nSetExceptions : atd->nGetExceptions; 440 p = req.setter 441 ? atd->ppSetExceptions : atd->ppGetExceptions; 442 break; 443 } 444 case typelib_TypeClass_INTERFACE_METHOD: 445 { 446 typelib_InterfaceMethodTypeDescription * mtd = 447 reinterpret_cast< 448 typelib_InterfaceMethodTypeDescription * >( 449 req.member.get()); 450 n = mtd->nExceptions; 451 p = mtd->ppExceptions; 452 break; 453 } 454 default: 455 OSL_ASSERT(false); // this cannot happen 456 break; 457 } 458 bool ok = false; 459 for (sal_Int32 i = 0; i != n; ++i) { 460 if (typelib_typedescriptionreference_isAssignableFrom( 461 p[i], 462 reinterpret_cast< typelib_TypeDescriptionReference * >( 463 ret.getType().get()))) 464 { 465 ok = true; 466 break; 467 } 468 } 469 if (!ok) { 470 throw css::uno::RuntimeException( 471 rtl::OUString( 472 RTL_CONSTASCII_USTRINGPARAM( 473 "URP: reply message with bad exception type" 474 " received")), 475 css::uno::Reference< css::uno::XInterface >()); 476 } 477 } 478 } else { 479 switch (req.member.get()->eTypeClass) { 480 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 481 if (!req.setter) { 482 ret = unmarshal.readValue( 483 css::uno::TypeDescription( 484 reinterpret_cast< 485 typelib_InterfaceAttributeTypeDescription * >( 486 req.member.get())-> 487 pAttributeTypeRef)); 488 } 489 break; 490 case typelib_TypeClass_INTERFACE_METHOD: 491 { 492 typelib_InterfaceMethodTypeDescription * mtd = 493 reinterpret_cast< 494 typelib_InterfaceMethodTypeDescription * >( 495 req.member.get()); 496 ret = unmarshal.readValue( 497 css::uno::TypeDescription(mtd->pReturnTypeRef)); 498 for (sal_Int32 i = 0; i != mtd->nParams; ++i) { 499 if (mtd->pParams[i].bOut) { 500 outArgs.push_back( 501 unmarshal.readValue( 502 css::uno::TypeDescription( 503 mtd->pParams[i].pTypeRef))); 504 } 505 } 506 break; 507 } 508 default: 509 OSL_ASSERT(false); // this cannot happen 510 break; 511 } 512 } 513 switch (req.kind) { 514 case OutgoingRequest::KIND_NORMAL: 515 { 516 std::auto_ptr< IncomingReply > resp( 517 new IncomingReply(exc, ret, outArgs)); 518 uno_threadpool_putJob( 519 bridge_->getThreadPool(), tid.getHandle(), resp.get(), 0, 520 false); 521 resp.release(); 522 break; 523 } 524 case OutgoingRequest::KIND_REQUEST_CHANGE: 525 OSL_ASSERT(outArgs.empty()); 526 bridge_->handleRequestChangeReply(exc, ret); 527 break; 528 case OutgoingRequest::KIND_COMMIT_CHANGE: 529 OSL_ASSERT(outArgs.empty()); 530 bridge_->handleCommitChangeReply(exc, ret); 531 break; 532 default: 533 OSL_ASSERT(false); // this cannot happen 534 break; 535 } 536 } 537 538 rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const { 539 if (newTid) { 540 return unmarshal.readTid(); 541 } 542 if (lastTid_.getLength() == 0) { 543 throw css::uno::RuntimeException( 544 rtl::OUString( 545 RTL_CONSTASCII_USTRINGPARAM( 546 "URP: message with NEWTID received when last TID has not" 547 " yet been set")), 548 css::uno::Reference< css::uno::XInterface >()); 549 } 550 return lastTid_; 551 } 552 553 } 554