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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_cppu.hxx"
26 
27 #include "Proxy.hxx"
28 
29 #include "sal/alloca.h"
30 #include "uno/dispatcher.h"
31 #include "typelib/typedescription.hxx"
32 #include "cppu/EnvDcp.hxx"
33 
34 
35 //#define LOG_LIFECYCLE_Proxy
36 #ifdef LOG_LIFECYCLE_Proxy
37 #  include <iostream>
38 #  define LOG_LIFECYCLE_Proxy_emit(x) x
39 
40 #else
41 #  define LOG_LIFECYCLE_Proxy_emit(x)
42 
43 #endif
44 
45 
46 using namespace com::sun::star;
47 
48 
relatesToInterface(typelib_TypeDescription * pTypeDescr)49 static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
50 	SAL_THROW( () )
51 {
52 	switch (pTypeDescr->eTypeClass)
53 	{
54 //  	case typelib_TypeClass_TYPEDEF:
55 	case typelib_TypeClass_SEQUENCE:
56 	{
57 		switch (((typelib_IndirectTypeDescription *)pTypeDescr)->pType->eTypeClass)
58 		{
59 		case typelib_TypeClass_INTERFACE:
60 		case typelib_TypeClass_UNION: // might relate to interface
61 		case typelib_TypeClass_ANY: // might relate to interface
62 			return true;
63 		case typelib_TypeClass_SEQUENCE:
64 		case typelib_TypeClass_STRUCT:
65 		case typelib_TypeClass_EXCEPTION:
66 		{
67 			typelib_TypeDescription * pTD = 0;
68 			TYPELIB_DANGER_GET( &pTD, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType );
69 			bool bRel = relatesToInterface( pTD );
70 			TYPELIB_DANGER_RELEASE( pTD );
71 			return bRel;
72 		}
73         default:
74             ;
75 		}
76 		return false;
77 	}
78 	case typelib_TypeClass_STRUCT:
79 	case typelib_TypeClass_EXCEPTION:
80 	{
81 		// ...optimized... to avoid getDescription() calls!
82 		typelib_CompoundTypeDescription * pComp    = (typelib_CompoundTypeDescription *)pTypeDescr;
83 		typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
84 		for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
85 		{
86 			switch (pTypes[nPos]->eTypeClass)
87 			{
88 			case typelib_TypeClass_INTERFACE:
89 			case typelib_TypeClass_UNION: // might relate to interface
90 			case typelib_TypeClass_ANY: // might relate to interface
91 				return true;
92 //  			case typelib_TypeClass_TYPEDEF:
93 			case typelib_TypeClass_SEQUENCE:
94 			case typelib_TypeClass_STRUCT:
95 			case typelib_TypeClass_EXCEPTION:
96 			{
97 				typelib_TypeDescription * pTD = 0;
98 				TYPELIB_DANGER_GET( &pTD, pTypes[nPos] );
99 				bool bRel = relatesToInterface( pTD );
100 				TYPELIB_DANGER_RELEASE( pTD );
101 				if (bRel)
102 					return true;
103 			}
104             default:
105                 ;
106 			}
107 		}
108 		if (pComp->pBaseTypeDescription)
109 			return relatesToInterface( (typelib_TypeDescription *)pComp->pBaseTypeDescription );
110 		break;
111 	}
112 	case typelib_TypeClass_UNION: // might relate to interface
113 	case typelib_TypeClass_ANY: // might relate to interface
114 	case typelib_TypeClass_INTERFACE:
115 		return true;
116 
117     default:
118         ;
119 	}
120 	return false;
121 }
122 
s_Proxy_dispatch(uno_Interface * pUnoI,typelib_TypeDescription const * pMemberType,void * pReturn,void * pArgs[],uno_Any ** ppException)123 extern "C" { static void SAL_CALL s_Proxy_dispatch(
124     uno_Interface                 * pUnoI,
125     typelib_TypeDescription const * pMemberType,
126     void                          * pReturn,
127     void                          * pArgs[],
128     uno_Any                      ** ppException)
129 	SAL_THROW_EXTERN_C()
130 {
131     Proxy * pThis = static_cast<Proxy *>(pUnoI);
132 
133     typelib_MethodParameter            param;
134     sal_Int32                          nParams = 0;
135     typelib_MethodParameter          * pParams = 0;
136     typelib_TypeDescriptionReference * pReturnTypeRef = 0;
137     // sal_Int32                          nOutParams = 0;
138 
139     switch (pMemberType->eTypeClass)
140     {
141     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
142         if (pReturn)
143         {
144             pReturnTypeRef =
145                 ((typelib_InterfaceAttributeTypeDescription *)
146                  pMemberType)->pAttributeTypeRef;
147             nParams = 0;
148             pParams = NULL;
149         }
150         else
151         {
152             param.pTypeRef = ((typelib_InterfaceAttributeTypeDescription *)
153                               pMemberType)->pAttributeTypeRef;
154             param.bIn = sal_True;
155             param.bOut = sal_False;
156             nParams = 1;
157             pParams = &param;
158         }
159         break;
160     case typelib_TypeClass_INTERFACE_METHOD:
161     {
162         typelib_InterfaceMethodTypeDescription * method_td =
163             (typelib_InterfaceMethodTypeDescription *) pMemberType;
164         pReturnTypeRef = method_td->pReturnTypeRef;
165         nParams = method_td->nParams;
166         pParams = method_td->pParams;
167         break;
168     }
169     default:
170         OSL_ENSURE( sal_False, "### illegal member typeclass!" );
171         abort();
172     }
173 
174     pThis->dispatch( pReturnTypeRef,
175                      pParams,
176                      nParams,
177                      pMemberType,
178                      pReturn,
179                      pArgs,
180                      ppException );
181 }}
182 
Proxy_free(uno_ExtEnvironment *,void * pProxy)183 extern "C" void SAL_CALL Proxy_free(uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
184 {
185     Proxy * pThis = static_cast<Proxy * >(reinterpret_cast<uno_Interface *>(pProxy));
186 	delete pThis;
187 }
188 
189 extern "C" {
s_Proxy_acquire(uno_Interface * pUnoI)190 static void SAL_CALL s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
191 {
192 	Proxy * pProxy = static_cast<Proxy *>(pUnoI);
193 	pProxy->acquire();
194 }
195 
s_Proxy_release(uno_Interface * pUnoI)196 static void SAL_CALL s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
197 {
198 	Proxy * pProxy = static_cast<Proxy *>(pUnoI);
199 	pProxy->release();
200 }
201 
s_acquireAndRegister_v(va_list * pParam)202 static void s_acquireAndRegister_v(va_list * pParam)
203 {
204 	uno_Interface                    * pUnoI      = va_arg(*pParam, uno_Interface *);
205 	rtl_uString                      * pOid       = va_arg(*pParam, rtl_uString *);
206 	typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
207 	uno_ExtEnvironment               * pEnv       = va_arg(*pParam, uno_ExtEnvironment *);
208 
209 	pUnoI->acquire(pUnoI);
210  	pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
211 }
212 }
213 
Proxy(uno::Mapping const & to_from,uno_Environment * pTo,uno_Environment * pFrom,uno_Interface * pUnoI,typelib_InterfaceTypeDescription * pTypeDescr,rtl::OUString const & rOId,cppu::helper::purpenv::ProbeFun * probeFun,void * pProbeContext)214 Proxy::Proxy(uno::Mapping                  const & to_from,
215 			 uno_Environment                     * pTo,
216 			 uno_Environment                     * pFrom,
217 			 uno_Interface                       * pUnoI,
218 			 typelib_InterfaceTypeDescription    * pTypeDescr,
219 			 rtl::OUString                 const & rOId,
220 			 cppu::helper::purpenv::ProbeFun     * probeFun,
221 			 void                                * pProbeContext
222 )
223     SAL_THROW(())
224 		: m_nRef         (1),
225 		  m_from         (pFrom),
226 		  m_to           (pTo),
227 		  m_from_to      (pFrom, pTo),
228 		  m_to_from      (to_from),
229 		  m_pUnoI        (pUnoI),
230 		  m_pTypeDescr   (pTypeDescr),
231 		  m_aOId         (rOId),
232 		  m_probeFun     (probeFun),
233 		  m_pProbeContext(pProbeContext)
234 {
235 	LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::Proxy(<>)", this));
236 
237     typelib_typedescription_acquire((typelib_TypeDescription *)m_pTypeDescr);
238     if (!((typelib_TypeDescription *)m_pTypeDescr)->bComplete)
239 		typelib_typedescription_complete((typelib_TypeDescription **)&m_pTypeDescr);
240 
241     OSL_ENSURE(((typelib_TypeDescription *)m_pTypeDescr)->bComplete, "### type is incomplete!");
242 
243 	uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
244 
245 	// uno_Interface
246     uno_Interface::acquire     = s_Proxy_acquire;
247     uno_Interface::release     = s_Proxy_release;
248     uno_Interface::pDispatcher = s_Proxy_dispatch;
249 }
250 
s_releaseAndRevoke_v(va_list * pParam)251 extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
252 {
253 	uno_ExtEnvironment * pEnv  = va_arg(*pParam, uno_ExtEnvironment *);
254 	uno_Interface      * pUnoI = va_arg(*pParam, uno_Interface *);
255 
256 	pEnv->revokeInterface(pEnv, reinterpret_cast<void *>(pUnoI));
257     pUnoI->release(pUnoI);
258 }}
259 
~Proxy()260 Proxy::~Proxy()
261 {
262 	LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::~Proxy()", this));
263 
264 	uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
265 
266 	typelib_typedescription_release((typelib_TypeDescription *)m_pTypeDescr);
267 }
268 
getAcquireMethod(void)269 static uno::TypeDescription getAcquireMethod(void)
270 {
271 	typelib_TypeDescriptionReference * type_XInterface =
272 		* typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
273 
274     typelib_TypeDescription * pTXInterfaceDescr = 0;
275     TYPELIB_DANGER_GET    (&pTXInterfaceDescr, type_XInterface);
276     uno::TypeDescription acquire(
277         reinterpret_cast< typelib_InterfaceTypeDescription * >(
278             pTXInterfaceDescr)->ppAllMembers[1]);
279     TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
280 
281 	return acquire;
282 }
283 
getReleaseMethod(void)284 static uno::TypeDescription getReleaseMethod(void)
285 {
286 	typelib_TypeDescriptionReference * type_XInterface =
287 		* typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
288 
289     typelib_TypeDescription * pTXInterfaceDescr = 0;
290     TYPELIB_DANGER_GET    (&pTXInterfaceDescr, type_XInterface);
291     uno::TypeDescription release(
292         reinterpret_cast< typelib_InterfaceTypeDescription * >(
293             pTXInterfaceDescr)->ppAllMembers[2]);
294     TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
295 
296     return release;
297 }
298 
299 static uno::TypeDescription s_acquireMethod(getAcquireMethod());
300 static uno::TypeDescription s_releaseMethod(getReleaseMethod());
301 
acquire(void)302 void Proxy::acquire(void)
303 {
304 	if (m_probeFun)
305 		m_probeFun(true,
306 				   this,
307 				   m_pProbeContext,
308 				   *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
309 				   NULL,
310 				   0,
311 				   s_acquireMethod.get(),
312 				   NULL,
313 				   NULL,
314 				   NULL);
315 
316     if (osl_incrementInterlockedCount(&m_nRef) == 1)
317     {
318         // rebirth of proxy zombie
319 		void * pThis = this;
320         m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv,
321 													  &pThis,
322 													  Proxy_free,
323 													  m_aOId.pData,
324 													  m_pTypeDescr);
325         OSL_ASSERT(pThis == this);
326     }
327 
328 	if (m_probeFun)
329 		m_probeFun(false,
330 				   this,
331 				   m_pProbeContext,
332 				   *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
333 				   NULL,
334 				   0,
335 				   s_acquireMethod.get(),
336 				   NULL,
337 				   NULL,
338 				   NULL);
339 
340 }
341 
release(void)342 void Proxy::release(void)
343 {
344 	cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
345 	void                            * pProbeContext = m_pProbeContext;
346 
347 	if (m_probeFun)
348 		m_probeFun(true,
349 				   this,
350 				   m_pProbeContext,
351 				   *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
352 				   NULL,
353 				   0,
354 				   s_releaseMethod.get(),
355 				   NULL,
356 				   NULL,
357 				   NULL);
358 
359     if (osl_decrementInterlockedCount(&m_nRef) == 0)
360         m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
361 
362 	if (probeFun)
363 		probeFun(false,
364 				 this,
365 				 pProbeContext,
366 				 *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
367 				 NULL,
368 				 0,
369 				 s_releaseMethod.get(),
370 				 NULL,
371 				 NULL,
372 				 NULL);
373 
374 }
375 
376 
377 extern "C" {
s_type_destructData_v(va_list * pParam)378 static void s_type_destructData_v(va_list * pParam)
379 {
380 	void * ret = va_arg(*pParam, void *);
381 	typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
382 
383 	uno_type_destructData(ret, pReturnTypeRef, 0);
384 }
385 
s_dispatcher_v(va_list * pParam)386 static void s_dispatcher_v(va_list * pParam)
387 {
388 	uno_Interface                 * pUnoI       = va_arg(*pParam, uno_Interface *);
389 	typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
390 	void                          * pReturn     = va_arg(*pParam, void *);
391 	void                         ** pArgs       = va_arg(*pParam, void **);
392 	uno_Any                      ** ppException = va_arg(*pParam, uno_Any **);
393 
394 	pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
395 }
396 }
397 
dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,typelib_MethodParameter * pParams,sal_Int32 nParams,typelib_TypeDescription const * pMemberType,void * pReturn,void * pArgs[],uno_Any ** ppException)398 void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,
399 					 typelib_MethodParameter          * pParams,
400 					 sal_Int32                          nParams,
401 					 typelib_TypeDescription    const * pMemberType,
402 					 void                             * pReturn,
403 					 void                             * pArgs[],
404 					 uno_Any                         ** ppException)
405 {
406 	if (m_probeFun)
407 		m_probeFun(true,
408 				   this,
409 				   m_pProbeContext,
410 				   pReturnTypeRef,
411 				   pParams,
412 				   nParams,
413 				   pMemberType,
414 				   pReturn,
415 				   pArgs,
416 				   ppException);
417 
418     void ** args = (void **) alloca( sizeof (void *) * nParams );
419 
420     typelib_TypeDescription * return_td = 0;
421     void * ret = pReturn;
422 	if (pReturnTypeRef)
423 	{
424 		TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
425 
426 		if (relatesToInterface(return_td))
427 			ret = alloca(return_td->nSize);
428 
429 		TYPELIB_DANGER_RELEASE(return_td);
430 	}
431 
432     for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
433     {
434         typelib_MethodParameter const & param = pParams[nPos];
435         typelib_TypeDescription * td = 0;
436         TYPELIB_DANGER_GET( &td, param.pTypeRef );
437         if (relatesToInterface(td))
438         {
439             args[nPos] = alloca(td->nSize);
440             if (param.bIn)
441             {
442                 uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
443             }
444         }
445         else
446         {
447             args[nPos] = pArgs[nPos];
448         }
449         TYPELIB_DANGER_RELEASE( td );
450     }
451 
452     uno_Any exc_data;
453     uno_Any * exc = &exc_data;
454 
455 	// do the UNO call...
456 	uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
457 
458     if (exc == 0)
459     {
460         for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
461         {
462             if (args[nPos] != pArgs[nPos])
463             {
464                 typelib_MethodParameter const & param = pParams[nPos];
465                 if (param.bOut)
466                 {
467                     if (param.bIn) // is inout
468                     {
469                         uno_type_destructData(pArgs[nPos], param.pTypeRef, 0);
470                     }
471                     uno_type_copyAndConvertData(pArgs[ nPos ],
472 												args[ nPos ],
473 												param.pTypeRef,
474 												m_to_from.get());
475                 }
476 				uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
477             }
478         }
479         if (ret != pReturn)
480         {
481             uno_type_copyAndConvertData(pReturn,
482 										ret,
483 										pReturnTypeRef,
484 										m_to_from.get());
485 
486 			uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
487         }
488 
489         *ppException = 0;
490     }
491     else // exception occured
492     {
493         for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
494         {
495             if (args[nPos] != pArgs[nPos])
496             {
497                 typelib_MethodParameter const & param = pParams[nPos];
498                 if (param.bIn)
499                 {
500 					uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
501                 }
502             }
503         }
504 
505         uno_type_any_constructAndConvert(*ppException,
506 										 exc->pData,
507 										 exc->pType,
508 										 m_to_from.get());
509 
510 		// FIXME: need to destruct in m_to
511 		uno_any_destruct(exc, 0);
512     }
513 
514 	if (m_probeFun)
515 		m_probeFun(false,
516 				   this,
517 				   m_pProbeContext,
518 				   pReturnTypeRef,
519 				   pParams,
520 				   nParams,
521 				   pMemberType,
522 				   pReturn,
523 				   pArgs,
524 				   ppException);
525 }
526 
527