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
read(css::uno::Reference<css::connection::XConnection> const & connection,sal_uInt32 size,bool eofOk)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
request(void * pThreadSpecificData)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
Reader(rtl::Reference<Bridge> const & bridge)105 Reader::Reader(rtl::Reference< Bridge > const & bridge): bridge_(bridge) {
106 OSL_ASSERT(bridge.is());
107 acquire();
108 }
109
~Reader()110 Reader::~Reader() {}
111
run()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
onTerminated()151 void Reader::onTerminated() {
152 release();
153 }
154
readMessage(Unmarshal & unmarshal)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.isEmpty() ) {
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_.isEmpty() ) {
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
readReplyMessage(Unmarshal & unmarshal,sal_uInt8 flags1)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
getTid(Unmarshal & unmarshal,bool newTid) const534 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