xref: /aoo41x/main/binaryurp/source/reader.cxx (revision cdf0e10c)
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