Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*************************************************************************
3 : *
4 : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : *
6 : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : *
8 : * OpenOffice.org - a multi-platform office productivity suite
9 : *
10 : * This file is part of OpenOffice.org.
11 : *
12 : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : * it under the terms of the GNU Lesser General Public License version 3
14 : * only, as published by the Free Software Foundation.
15 : *
16 : * OpenOffice.org is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU Lesser General Public License version 3 for more details
20 : * (a copy is included in the LICENSE file that accompanied this code).
21 : *
22 : * You should have received a copy of the GNU Lesser General Public License
23 : * version 3 along with OpenOffice.org. If not, see
24 : * <http://www.openoffice.org/license.html>
25 : * for a copy of the LGPLv3 License.
26 : *
27 : ************************************************************************/
28 :
29 : #include <errno.h>
30 : #include <unistd.h>
31 :
32 : #include <plugin/unx/mediator.hxx>
33 : #include <sal/log.hxx>
34 : #include <vcl/svapp.hxx>
35 : #include <boost/scoped_array.hpp>
36 :
37 : #define MEDIATOR_MAGIC 0xf7a8d2f4
38 :
39 0 : Mediator::Mediator( int nSocket ) :
40 : m_nSocket( nSocket ),
41 : m_pListener( NULL ),
42 : m_nCurrentID( 1 ),
43 0 : m_bValid( true )
44 : {
45 0 : m_pListener = new MediatorListener( this );
46 0 : m_pListener->create();
47 0 : }
48 :
49 0 : Mediator::~Mediator()
50 : {
51 0 : if( m_pListener )
52 : {
53 : {
54 0 : ::osl::MutexGuard aGuard( m_pListener->m_aMutex );
55 0 : m_pListener->m_pMediator = NULL;
56 : }
57 0 : m_pListener = NULL;
58 0 : if( m_bValid )
59 : {
60 : sal_uLong aHeader[3];
61 0 : aHeader[0] = 0;
62 0 : aHeader[1] = 0;
63 0 : aHeader[2] = MEDIATOR_MAGIC;
64 0 : ssize_t nToWrite = sizeof(aHeader);
65 0 : bool bSuccess = (nToWrite == write(m_nSocket, aHeader, nToWrite));
66 : SAL_WARN_IF(!bSuccess, "extensions.plugin", "short write");
67 : }
68 : // kick the thread out of its run method; it deletes itself
69 0 : close( m_nSocket );
70 : }
71 : else
72 0 : close( m_nSocket );
73 0 : for( std::vector< MediatorMessage* >::iterator it = m_aMessageQueue.begin();
74 0 : it != m_aMessageQueue.end(); ++it )
75 : {
76 0 : delete *it;
77 : }
78 0 : }
79 :
80 :
81 0 : sal_uLong Mediator::SendMessage( sal_uLong nBytes, const char* pBytes, sal_uLong nMessageID )
82 : {
83 0 : if( ! m_pListener )
84 0 : return 0;
85 :
86 0 : osl::MutexGuard aGuard( m_aSendMutex );
87 0 : if( ! nMessageID )
88 0 : nMessageID = m_nCurrentID;
89 :
90 0 : m_nCurrentID++;
91 0 : if( m_nCurrentID >= 1 << 24 ) // protection against overflow
92 0 : m_nCurrentID = 1;
93 :
94 0 : if( ! m_bValid )
95 0 : return nMessageID;
96 :
97 0 : boost::scoped_array<sal_uLong> pBuffer(new sal_uLong[ (nBytes/sizeof(sal_uLong)) + 4 ]);
98 0 : pBuffer[ 0 ] = nMessageID;
99 0 : pBuffer[ 1 ] = nBytes;
100 0 : pBuffer[ 2 ] = MEDIATOR_MAGIC;
101 0 : memcpy( &pBuffer[3], pBytes, (size_t)nBytes );
102 0 : ssize_t nToWrite = nBytes + 3*sizeof( sal_uLong );
103 0 : bool bSuccess = (nToWrite == write( m_nSocket, pBuffer.get(), nToWrite ));
104 : SAL_WARN_IF(!bSuccess, "extensions.plugin", "short write");
105 :
106 0 : return nMessageID;
107 : }
108 :
109 0 : bool Mediator::WaitForMessage( sal_uLong nTimeOut )
110 : {
111 0 : if( ! m_pListener )
112 0 : return false;
113 :
114 0 : size_t nItems = m_aMessageQueue.size();
115 :
116 0 : if( ! nTimeOut && nItems > 0 )
117 0 : return true;
118 :
119 : TimeValue aValue;
120 0 : aValue.Seconds = nTimeOut/1000;
121 0 : aValue.Nanosec = ( nTimeOut % 1000 ) * 1000;
122 :
123 0 : while( m_aMessageQueue.size() == nItems )
124 : {
125 0 : m_aNewMessageCdtn.wait( & aValue );
126 0 : m_aNewMessageCdtn.reset();
127 0 : if( nTimeOut && m_aMessageQueue.size() == nItems )
128 0 : return false;
129 : }
130 0 : return true;
131 : }
132 :
133 0 : MediatorMessage* Mediator::WaitForAnswer( sal_uLong nMessageID )
134 : {
135 0 : nMessageID &= 0x00ffffff;
136 0 : while( m_pListener )
137 : {
138 : {
139 0 : osl::MutexGuard aGuard( m_aQueueMutex );
140 0 : for( size_t i = 0; i < m_aMessageQueue.size(); i++ )
141 : {
142 0 : MediatorMessage* pMessage = m_aMessageQueue[ i ];
143 0 : sal_uLong nID = pMessage->m_nID;
144 0 : if( ( nID & 0xff000000 ) &&
145 0 : ( ( nID & 0x00ffffff ) == nMessageID ) )
146 : {
147 0 : m_aMessageQueue.erase( m_aMessageQueue.begin() + i );
148 0 : return pMessage;
149 : }
150 0 : }
151 : }
152 0 : WaitForMessage( 10 );
153 : }
154 0 : return NULL;
155 : }
156 :
157 0 : MediatorMessage* Mediator::GetNextMessage( bool bWait )
158 : {
159 0 : while( m_pListener )
160 : {
161 : {
162 : // guard must be after WaitForMessage, else the listener
163 : // cannot insert a new one -> deadlock
164 0 : osl::MutexGuard aGuard( m_aQueueMutex );
165 0 : for( size_t i = 0; i < m_aMessageQueue.size(); i++ )
166 : {
167 0 : MediatorMessage* pMessage = m_aMessageQueue[ i ];
168 0 : if( ! ( pMessage->m_nID & 0xff000000 ) )
169 : {
170 0 : m_aMessageQueue.erase( m_aMessageQueue.begin() + i );
171 0 : return pMessage;
172 : }
173 : }
174 0 : if( ! bWait )
175 0 : return NULL;
176 : }
177 0 : WaitForMessage();
178 : }
179 0 : return NULL;
180 : }
181 :
182 0 : MediatorMessage* Mediator::TransactMessage( sal_uLong nBytes, char* pBytes )
183 : {
184 0 : sal_uLong nID = SendMessage( nBytes, pBytes );
185 0 : return WaitForAnswer( nID );
186 : }
187 :
188 0 : MediatorListener::MediatorListener( Mediator* pMediator ) :
189 0 : m_pMediator( pMediator )
190 : {
191 0 : }
192 :
193 0 : MediatorListener::~MediatorListener()
194 : {
195 0 : }
196 :
197 0 : void MediatorListener::run()
198 : {
199 0 : osl_setThreadName("MediatorListener");
200 :
201 0 : bool bRun = true;
202 0 : while( schedule() && m_pMediator && bRun )
203 : {
204 : sal_uLong nHeader[ 3 ];
205 : int nBytes;
206 :
207 0 : if( ( nBytes = read( m_pMediator->m_nSocket, nHeader, sizeof( nHeader ) ) ) == sizeof( nHeader ) && nHeader[2] == MEDIATOR_MAGIC)
208 : {
209 0 : if( nHeader[ 0 ] == 0 && nHeader[ 1 ] == 0 )
210 0 : return;
211 0 : boost::scoped_array<char> pBuffer(new char[ nHeader[ 1 ] ]);
212 0 : if( m_pMediator && (sal_uLong)read( m_pMediator->m_nSocket, pBuffer.get(), nHeader[ 1 ] ) == nHeader[ 1 ] )
213 : {
214 0 : ::osl::MutexGuard aMyGuard( m_aMutex );
215 : {
216 : osl::MutexGuard
217 0 : aGuard( m_pMediator->m_aQueueMutex );
218 : MediatorMessage* pMessage =
219 0 : new MediatorMessage( nHeader[ 0 ], nHeader[ 1 ], pBuffer.get() );
220 0 : m_pMediator->m_aMessageQueue.push_back( pMessage );
221 : }
222 0 : m_pMediator->m_aNewMessageCdtn.set();
223 0 : m_pMediator->m_aNewMessageHdl.Call( m_pMediator );
224 : }
225 : else
226 : {
227 : SAL_WARN(
228 : "extensions.plugin",
229 : "got incomplete MediatorMessage: { " << nHeader[0] << ", "
230 : << nHeader[1] << ", ... }");
231 0 : bRun = false;
232 0 : }
233 : }
234 : else
235 : {
236 : SAL_WARN(
237 : "extensions.plugin",
238 : "got incomplete message header of " << nBytes
239 : << " bytes (nHeader = [" << nHeader[0] << ", " << nHeader[1]
240 : << "]), errno is " << errno);
241 0 : bRun = false;
242 : }
243 : }
244 : }
245 :
246 0 : void MediatorListener::onTerminated()
247 : {
248 0 : if( m_pMediator )
249 : {
250 0 : m_pMediator->m_aConnectionLostHdl.Call( m_pMediator );
251 0 : m_pMediator->m_pListener = NULL;
252 : }
253 0 : delete this;
254 0 : }
255 :
256 0 : sal_uLong MediatorMessage::ExtractULONG()
257 : {
258 0 : if( ! m_pRun )
259 0 : m_pRun = m_pBytes;
260 :
261 : SAL_WARN_IF(
262 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
263 : "overflow in MediatorMessage::ExtractULONG");
264 : sal_uLong nCount;
265 0 : memcpy( &nCount, m_pRun, sizeof( sal_uLong ) );
266 0 : m_pRun += sizeof( sal_uLong );
267 0 : return nCount;
268 : }
269 :
270 0 : void* MediatorMessage::GetBytes( sal_uLong& rBytes )
271 : {
272 0 : if( ! m_pRun )
273 0 : m_pRun = m_pBytes;
274 :
275 : SAL_WARN_IF(
276 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
277 : "overflow in MediatorMessage::GetBytes");
278 0 : sal_uLong nBytes = ExtractULONG();
279 :
280 0 : if( nBytes == 0 )
281 0 : return NULL;
282 :
283 : SAL_WARN_IF(
284 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
285 : "overflow in MediatorMessage::GetBytes");
286 0 : char* pBuffer = new char[ nBytes ];
287 0 : memcpy( pBuffer, m_pRun, nBytes );
288 0 : m_pRun += nBytes;
289 0 : rBytes = nBytes;
290 0 : return pBuffer;
291 : }
292 :
293 0 : char* MediatorMessage::GetString()
294 : {
295 0 : if( ! m_pRun )
296 0 : m_pRun = m_pBytes;
297 :
298 : SAL_WARN_IF(
299 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
300 : "overflow in MediatorMessage::GetString");
301 0 : sal_uLong nBytes = ExtractULONG();
302 :
303 0 : if( nBytes == 0 )
304 0 : return NULL;
305 :
306 : SAL_WARN_IF(
307 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
308 : "overflow in MediatorMessage::GetString");
309 0 : char* pBuffer = new char[ nBytes+1 ];
310 0 : memcpy( pBuffer, m_pRun, nBytes );
311 0 : pBuffer[ nBytes ] = 0;
312 0 : m_pRun += nBytes;
313 0 : return pBuffer;
314 : }
315 :
316 0 : sal_uInt32 MediatorMessage::GetUINT32()
317 : {
318 0 : if( ! m_pRun )
319 0 : m_pRun = m_pBytes;
320 :
321 : SAL_WARN_IF(
322 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
323 : "overflow in MediatorMessage::GetUINT32");
324 0 : sal_uLong nBytes = ExtractULONG();
325 : SAL_WARN_IF(
326 : nBytes != sizeof( sal_uInt32 ), "extensions.plugin",
327 : "no sal_uInt32 in MediatorMessage::GetUINT32");
328 : SAL_WARN_IF(
329 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
330 : "overflow in MediatorMessage::GetUINT32");
331 : sal_uInt32 nRet;
332 0 : memcpy( &nRet, m_pRun, sizeof( nRet ) );
333 0 : m_pRun += sizeof( sal_uInt32 );
334 0 : return nRet;
335 : }
336 :
337 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|