1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <cassert>
23 #include <exception>
24 #include <memory>
25 #include <vector>
26 
27 #include <com/sun/star/connection/XConnection.hpp>
28 #include <com/sun/star/io/IOException.hpp>
29 #include <com/sun/star/uno/Any.hxx>
30 #include <com/sun/star/uno/Exception.hpp>
31 #include <com/sun/star/uno/Reference.hxx>
32 #include <com/sun/star/uno/RuntimeException.hpp>
33 #include <com/sun/star/uno/Sequence.hxx>
34 #include <com/sun/star/uno/Type.hxx>
35 #include <com/sun/star/uno/XCurrentContext.hpp>
36 #include <com/sun/star/uno/XInterface.hpp>
37 #include <cppu/unotype.hxx>
38 #include <rtl/byteseq.h>
39 #include <rtl/ustring.hxx>
40 #include <sal/log.hxx>
41 #include <sal/types.h>
42 #include <typelib/typeclass.h>
43 #include <typelib/typedescription.h>
44 #include <typelib/typedescription.hxx>
45 
46 #include "binaryany.hxx"
47 #include "bridge.hxx"
48 #include "incomingreply.hxx"
49 #include "incomingrequest.hxx"
50 #include "outgoingrequest.hxx"
51 #include "reader.hxx"
52 #include "specialfunctionids.hxx"
53 #include "unmarshal.hxx"
54 
55 namespace binaryurp {
56 
57 namespace {
58 
read(css::uno::Reference<css::connection::XConnection> const & connection,sal_uInt32 size,bool eofOk)59 css::uno::Sequence< sal_Int8 > read(
60     css::uno::Reference< css::connection::XConnection > const & connection,
61     sal_uInt32 size, bool eofOk)
62 {
63     assert(connection.is());
64     if (size > SAL_MAX_INT32) {
65         throw css::uno::RuntimeException(
66             "binaryurp::Reader: block size too large");
67     }
68     css::uno::Sequence< sal_Int8 > buf;
69     sal_Int32 n = connection->read(buf, static_cast< sal_Int32 >(size));
70     if (n == 0 && eofOk) {
71         return css::uno::Sequence< sal_Int8 >();
72     }
73     if (n != static_cast< sal_Int32 >(size)) {
74         throw css::io::IOException(
75             "binaryurp::Reader: premature end of input");
76     }
77     assert(buf.getLength() == static_cast< sal_Int32 >(size));
78     return buf;
79 }
80 
request(void * pThreadSpecificData)81 extern "C" void request(void * pThreadSpecificData) {
82     assert(pThreadSpecificData != nullptr);
83     std::unique_ptr< IncomingRequest >(
84         static_cast< IncomingRequest * >(pThreadSpecificData))->
85         execute();
86 }
87 
88 }
89 
Reader(rtl::Reference<Bridge> const & bridge)90 Reader::Reader(rtl::Reference< Bridge > const & bridge):
91     Thread("binaryurpReader"), bridge_(bridge)
92 {
93     assert(bridge.is());
94 }
95 
~Reader()96 Reader::~Reader() {}
97 
execute()98 void Reader::execute() {
99     try {
100         bridge_->sendRequestChangeRequest();
101         css::uno::Reference< css::connection::XConnection > con(
102             bridge_->getConnection());
103         for (;;) {
104             css::uno::Sequence< sal_Int8 > s(read(con, 8, true));
105             if (!s.hasElements()) {
106                 break;
107             }
108             Unmarshal header(bridge_, state_, s);
109             sal_uInt32 size = header.read32();
110             sal_uInt32 count = header.read32();
111             header.done();
112             if (count == 0) {
113                 throw css::io::IOException(
114                     "binaryurp::Reader: block with zero message count received");
115             }
116             Unmarshal block(bridge_, state_, read(con, size, false));
117             for (sal_uInt32 i = 0; i != count; ++i) {
118                 readMessage(block);
119             }
120             block.done();
121         }
122     } catch (const css::uno::Exception & e) {
123         SAL_WARN("binaryurp", "caught UNO exception '" << e << '\'');
124     } catch (const std::exception & e) {
125         SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
126     }
127     bridge_->terminate(false);
128     bridge_.clear();
129 }
130 
readMessage(Unmarshal & unmarshal)131 void Reader::readMessage(Unmarshal & unmarshal) {
132     sal_uInt8 flags1 = unmarshal.read8();
133     bool newType;
134     bool newOid;
135     bool newTid;
136     bool forceSynchronous;
137     sal_uInt16 functionId;
138     if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER
139         if ((flags1 & 0x40) == 0) { // bit 6: REQUEST
140             readReplyMessage(unmarshal, flags1);
141             return;
142         }
143         newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE
144         newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID
145         newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID
146         if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS
147             sal_uInt8 flags2 = unmarshal.read8();
148             forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY
149             if (((flags2 & 0x40) != 0) != forceSynchronous) {
150                     // bit 6: SYNCHRONOUS
151                 throw css::uno::RuntimeException(
152                     "URP: request message with MUSTREPLY != SYNCHRONOUS"
153                     " received");
154             }
155         } else {
156             forceSynchronous = false;
157         }
158         functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16
159             ? unmarshal.read16() : unmarshal.read8();
160     } else {
161         newType = false;
162         newOid = false;
163         newTid = false;
164         forceSynchronous = false;
165         functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14
166             ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F;
167     }
168     css::uno::TypeDescription type;
169     if (newType) {
170         type = unmarshal.readType();
171         lastType_ = type;
172     } else {
173         if (!lastType_.is()) {
174             throw css::uno::RuntimeException(
175                 "URP: request message with NEWTYPE received when last"
176                 " interface type has not yet been set");
177         }
178         type = lastType_;
179     }
180     OUString oid;
181     if (newOid) {
182         oid = unmarshal.readOid();
183         if (oid.isEmpty()) {
184             throw css::io::IOException(
185                 "binaryurp::Unmarshal: empty OID");
186         }
187         lastOid_ = oid;
188     } else {
189         if (lastOid_.isEmpty()) {
190             throw css::uno::RuntimeException(
191                 "URP: request message with NEWOID received when last OID has"
192                 " not yet been set");
193         }
194         oid = lastOid_;
195     }
196     rtl::ByteSequence tid(getTid(unmarshal, newTid));
197     lastTid_ = tid;
198     type.makeComplete();
199     if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) {
200         throw css::uno::RuntimeException(
201             "URP: request message with non-interface interface type received");
202     }
203     typelib_InterfaceTypeDescription * itd =
204         reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get());
205     if (functionId >= itd->nMapFunctionIndexToMemberIndex) {
206         throw css::uno::RuntimeException(
207             "URP: request message with unknown function ID received");
208     }
209     sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId];
210     css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]);
211     memberTd.makeComplete();
212     assert(memberTd.is());
213     bool protProps = bridge_->isProtocolPropertiesRequest(oid, type);
214     bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE &&
215         bridge_->isCurrentContextMode();
216     css::uno::UnoInterfaceReference cc;
217     if (ccMode) {
218         css::uno::TypeDescription t(
219             cppu::UnoType<css::uno::XCurrentContext>::get());
220         cc.set(
221             *static_cast< uno_Interface ** >(
222                 unmarshal.readValue(t).getValue(t)));
223     }
224     bool oneWay =
225         memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD &&
226         (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
227             memberTd.get())->
228          bOneWay);
229     SAL_INFO_IF(
230         !oneWay && forceSynchronous, "binaryurp",
231         ("superfluous MUSTREPLY/SYNCHRONOUS ignored in request message with"
232          " non-oneway function ID"));
233     bool synchronous = !oneWay || forceSynchronous;
234     bool bSetter = false;
235     std::vector< BinaryAny > inArgs;
236     switch (memberTd.get()->eTypeClass) {
237     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
238         bSetter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId;
239             // pMapMemberIndexToFunctionIndex contains function index of
240             // attribute getter
241         if (bSetter) {
242             inArgs.push_back(
243                 unmarshal.readValue(
244                     css::uno::TypeDescription(
245                         reinterpret_cast<
246                             typelib_InterfaceAttributeTypeDescription * >(
247                                 memberTd.get())->
248                         pAttributeTypeRef)));
249         }
250         break;
251     case typelib_TypeClass_INTERFACE_METHOD:
252         {
253             typelib_InterfaceMethodTypeDescription * mtd =
254                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
255                     memberTd.get());
256             for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
257                 if (mtd->pParams[i].bIn) {
258                     inArgs.push_back(
259                         unmarshal.readValue(
260                             css::uno::TypeDescription(
261                                 mtd->pParams[i].pTypeRef)));
262                 }
263             }
264             break;
265         }
266     default:
267         assert(false); // this cannot happen
268         break;
269     }
270     bridge_->incrementCalls(
271         !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE);
272     if (protProps) {
273         switch (functionId) {
274         case SPECIAL_FUNCTION_ID_REQUEST_CHANGE:
275             bridge_->handleRequestChangeRequest(tid, inArgs);
276             break;
277         case SPECIAL_FUNCTION_ID_COMMIT_CHANGE:
278             bridge_->handleCommitChangeRequest(tid, inArgs);
279             break;
280         default:
281             throw css::uno::RuntimeException(
282                 "URP: request message with UrpProtocolProperties OID and"
283                 " unknown function ID received");
284         }
285     } else {
286         css::uno::UnoInterfaceReference obj;
287         switch (functionId) {
288         case SPECIAL_FUNCTION_ID_QUERY_INTERFACE:
289             obj = bridge_->findStub(oid, type);
290             if (!obj.is()) {
291                 assert(
292                     inArgs.size() == 1
293                     && inArgs[0].getType().equals(
294                         css::uno::TypeDescription(
295                             cppu::UnoType< css::uno::Type >::get())));
296                 if (!(type.equals(
297                           css::uno::TypeDescription(
298                               cppu::UnoType<
299                                   css::uno::Reference<
300                                       css::uno::XInterface > >::get()))
301                       && (css::uno::TypeDescription(
302                               *static_cast<
303                                   typelib_TypeDescriptionReference ** >(
304                                       inArgs[0].getValue(inArgs[0].getType()))).
305                           equals(
306                               css::uno::TypeDescription(
307                                   cppu::UnoType<
308                                       css::uno::Reference<
309                                           css::uno::XInterface > >::get())))))
310                 {
311                     throw css::uno::RuntimeException(
312                         "URP: queryInterface request message with unknown OID '"
313                         + oid + "' received");
314                 }
315             }
316             break;
317         case SPECIAL_FUNCTION_ID_RESERVED:
318             throw css::uno::RuntimeException(
319                 "URP: request message with unknown function ID 1 received");
320         case SPECIAL_FUNCTION_ID_RELEASE:
321             break;
322         default:
323             obj = bridge_->findStub(oid, type);
324             if (!obj.is()) {
325                 throw css::uno::RuntimeException(
326                     "URP: request message with unknown OID received");
327             }
328             break;
329         }
330         std::unique_ptr< IncomingRequest > req(
331             new IncomingRequest(
332                 bridge_, tid, oid, obj, type, functionId, synchronous, memberTd,
333                 bSetter, inArgs, ccMode, cc));
334         if (synchronous) {
335             bridge_->incrementActiveCalls();
336         }
337         uno_threadpool_putJob(
338             bridge_->getThreadPool(), tid.getHandle(), req.get(), &request,
339             !synchronous);
340         req.release();
341     }
342 }
343 
readReplyMessage(Unmarshal & unmarshal,sal_uInt8 flags1)344 void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) {
345     rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0));
346         // bit 3: NEWTID
347     lastTid_ = tid;
348     OutgoingRequest req(bridge_->lastOutgoingRequest(tid));
349     bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION
350     BinaryAny ret;
351     std::vector< BinaryAny > outArgs;
352     if (exc) {
353         ret = unmarshal.readValue(
354             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()));
355         if (!typelib_typedescription_isAssignableFrom(
356                 (css::uno::TypeDescription(
357                     cppu::UnoType< css::uno::RuntimeException >::get()).
358                  get()),
359                 ret.getType().get()))
360         {
361             sal_Int32 n = 0;
362             typelib_TypeDescriptionReference ** p = nullptr;
363             switch (req.member.get()->eTypeClass) {
364             case typelib_TypeClass_INTERFACE_ATTRIBUTE:
365                 {
366                     typelib_InterfaceAttributeTypeDescription * atd =
367                         reinterpret_cast<
368                             typelib_InterfaceAttributeTypeDescription * >(
369                                 req.member.get());
370                     n = req.setter ? atd->nSetExceptions : atd->nGetExceptions;
371                     p = req.setter
372                         ? atd->ppSetExceptions : atd->ppGetExceptions;
373                     break;
374                 }
375             case typelib_TypeClass_INTERFACE_METHOD:
376                 {
377                     typelib_InterfaceMethodTypeDescription * mtd =
378                         reinterpret_cast<
379                             typelib_InterfaceMethodTypeDescription * >(
380                                 req.member.get());
381                     n = mtd->nExceptions;
382                     p = mtd->ppExceptions;
383                     break;
384                 }
385             default:
386                 assert(false); // this cannot happen
387                 break;
388             }
389             bool bOk = false;
390             for (sal_Int32 i = 0; i != n; ++i) {
391                 if (typelib_typedescriptionreference_isAssignableFrom(
392                         p[i],
393                         reinterpret_cast< typelib_TypeDescriptionReference * >(
394                             ret.getType().get())))
395                 {
396                     bOk = true;
397                     break;
398                 }
399             }
400             if (!bOk) {
401                 throw css::uno::RuntimeException(
402                     "URP: reply message with bad exception type received");
403             }
404         }
405     } else {
406         switch (req.member.get()->eTypeClass) {
407         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
408             if (!req.setter) {
409                 ret = unmarshal.readValue(
410                     css::uno::TypeDescription(
411                         reinterpret_cast<
412                             typelib_InterfaceAttributeTypeDescription * >(
413                                 req.member.get())->
414                         pAttributeTypeRef));
415             }
416             break;
417         case typelib_TypeClass_INTERFACE_METHOD:
418             {
419                 typelib_InterfaceMethodTypeDescription * mtd =
420                     reinterpret_cast<
421                         typelib_InterfaceMethodTypeDescription * >(
422                             req.member.get());
423                 ret = unmarshal.readValue(
424                     css::uno::TypeDescription(mtd->pReturnTypeRef));
425                 for (sal_Int32 i = 0; i != mtd->nParams; ++i) {
426                     if (mtd->pParams[i].bOut) {
427                         outArgs.push_back(
428                             unmarshal.readValue(
429                                 css::uno::TypeDescription(
430                                     mtd->pParams[i].pTypeRef)));
431                     }
432                 }
433                 break;
434             }
435         default:
436             assert(false); // this cannot happen
437             break;
438         }
439     }
440     switch (req.kind) {
441     case OutgoingRequest::KIND_NORMAL:
442         {
443             std::unique_ptr< IncomingReply > resp(
444                 new IncomingReply(exc, ret, outArgs));
445             uno_threadpool_putJob(
446                 bridge_->getThreadPool(), tid.getHandle(), resp.get(), nullptr,
447                 false);
448             resp.release();
449             break;
450         }
451     case OutgoingRequest::KIND_REQUEST_CHANGE:
452         assert(outArgs.empty());
453         bridge_->handleRequestChangeReply(exc, ret);
454         break;
455     case OutgoingRequest::KIND_COMMIT_CHANGE:
456         assert(outArgs.empty());
457         bridge_->handleCommitChangeReply(exc, ret);
458         break;
459     default:
460         assert(false); // this cannot happen
461         break;
462     }
463 }
464 
getTid(Unmarshal & unmarshal,bool newTid) const465 rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const {
466     if (newTid) {
467         return unmarshal.readTid();
468     }
469     if (lastTid_.getLength() == 0) {
470         throw css::uno::RuntimeException(
471             "URP: message with NEWTID received when last TID has not yet been"
472             " set");
473     }
474     return lastTid_;
475 }
476 
477 }
478 
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
480