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