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 : sal_Bool Mediator::WaitForMessage( sal_uLong nTimeOut )
110 : {
111 0 : if( ! m_pListener )
112 0 : return sal_False;
113 :
114 0 : size_t nItems = m_aMessageQueue.size();
115 :
116 0 : if( ! nTimeOut && nItems > 0 )
117 0 : return sal_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 sal_False;
129 : }
130 0 : return sal_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( sal_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 : bool bRun = true;
200 0 : while( schedule() && m_pMediator && bRun )
201 : {
202 : sal_uLong nHeader[ 3 ];
203 : int nBytes;
204 :
205 0 : if( ( nBytes = read( m_pMediator->m_nSocket, nHeader, sizeof( nHeader ) ) ) == sizeof( nHeader ) && nHeader[2] == MEDIATOR_MAGIC)
206 : {
207 0 : if( nHeader[ 0 ] == 0 && nHeader[ 1 ] == 0 )
208 0 : return;
209 0 : boost::scoped_array<char> pBuffer(new char[ nHeader[ 1 ] ]);
210 0 : if( m_pMediator && (sal_uLong)read( m_pMediator->m_nSocket, pBuffer.get(), nHeader[ 1 ] ) == nHeader[ 1 ] )
211 : {
212 0 : ::osl::MutexGuard aMyGuard( m_aMutex );
213 : {
214 : osl::MutexGuard
215 0 : aGuard( m_pMediator->m_aQueueMutex );
216 : MediatorMessage* pMessage =
217 0 : new MediatorMessage( nHeader[ 0 ], nHeader[ 1 ], pBuffer.get() );
218 0 : m_pMediator->m_aMessageQueue.push_back( pMessage );
219 : }
220 0 : m_pMediator->m_aNewMessageCdtn.set();
221 0 : m_pMediator->m_aNewMessageHdl.Call( m_pMediator );
222 : }
223 : else
224 : {
225 : SAL_WARN(
226 : "extensions.plugin",
227 : "got incomplete MediatorMessage: { " << nHeader[0] << ", "
228 : << nHeader[1] << ", ... }");
229 0 : bRun = false;
230 0 : }
231 : }
232 : else
233 : {
234 : SAL_WARN(
235 : "extensions.plugin",
236 : "got incomplete message header of " << nBytes
237 : << " bytes (nHeader = [" << nHeader[0] << ", " << nHeader[1]
238 : << "]), errno is " << errno);
239 0 : bRun = false;
240 : }
241 : }
242 : }
243 :
244 0 : void MediatorListener::onTerminated()
245 : {
246 0 : if( m_pMediator )
247 : {
248 0 : m_pMediator->m_aConnectionLostHdl.Call( m_pMediator );
249 0 : m_pMediator->m_pListener = NULL;
250 : }
251 0 : delete this;
252 0 : }
253 :
254 0 : sal_uLong MediatorMessage::ExtractULONG()
255 : {
256 0 : if( ! m_pRun )
257 0 : m_pRun = m_pBytes;
258 :
259 : SAL_WARN_IF(
260 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
261 : "overflow in MediatorMessage::ExtractULONG");
262 : sal_uLong nCount;
263 0 : memcpy( &nCount, m_pRun, sizeof( sal_uLong ) );
264 0 : m_pRun += sizeof( sal_uLong );
265 0 : return nCount;
266 : }
267 :
268 0 : void* MediatorMessage::GetBytes( sal_uLong& rBytes )
269 : {
270 0 : if( ! m_pRun )
271 0 : m_pRun = m_pBytes;
272 :
273 : SAL_WARN_IF(
274 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
275 : "overflow in MediatorMessage::GetBytes");
276 0 : sal_uLong nBytes = ExtractULONG();
277 :
278 0 : if( nBytes == 0 )
279 0 : return NULL;
280 :
281 : SAL_WARN_IF(
282 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
283 : "overflow in MediatorMessage::GetBytes");
284 0 : char* pBuffer = new char[ nBytes ];
285 0 : memcpy( pBuffer, m_pRun, nBytes );
286 0 : m_pRun += nBytes;
287 0 : rBytes = nBytes;
288 0 : return pBuffer;
289 : }
290 :
291 0 : char* MediatorMessage::GetString()
292 : {
293 0 : if( ! m_pRun )
294 0 : m_pRun = m_pBytes;
295 :
296 : SAL_WARN_IF(
297 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
298 : "overflow in MediatorMessage::GetString");
299 0 : sal_uLong nBytes = ExtractULONG();
300 :
301 0 : if( nBytes == 0 )
302 0 : return NULL;
303 :
304 : SAL_WARN_IF(
305 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
306 : "overflow in MediatorMessage::GetString");
307 0 : char* pBuffer = new char[ nBytes+1 ];
308 0 : memcpy( pBuffer, m_pRun, nBytes );
309 0 : pBuffer[ nBytes ] = 0;
310 0 : m_pRun += nBytes;
311 0 : return pBuffer;
312 : }
313 :
314 0 : sal_uInt32 MediatorMessage::GetUINT32()
315 : {
316 0 : if( ! m_pRun )
317 0 : m_pRun = m_pBytes;
318 :
319 : SAL_WARN_IF(
320 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
321 : "overflow in MediatorMessage::GetUINT32");
322 0 : sal_uLong nBytes = ExtractULONG();
323 : SAL_WARN_IF(
324 : nBytes != sizeof( sal_uInt32 ), "extensions.plugin",
325 : "no sal_uInt32 in MediatorMessage::GetUINT32");
326 : SAL_WARN_IF(
327 : (sal_uLong)(m_pRun - m_pBytes) >= m_nBytes, "extensions.plugin",
328 : "overflow in MediatorMessage::GetUINT32");
329 : sal_uInt32 nRet;
330 0 : memcpy( &nRet, m_pRun, sizeof( nRet ) );
331 0 : m_pRun += sizeof( sal_uInt32 );
332 0 : return nRet;
333 : }
334 :
335 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|