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_webdav.hxx"
26
27 #include <rtl/ustring.hxx>
28 #include <osl/time.h>
29 #include <osl/thread.hxx>
30 #include "CurlTypes.hxx"
31 #include "CurlSession.hxx"
32 #include "CurlLockStore.hxx"
33
34 using namespace http_dav_ucp;
35
36 namespace http_dav_ucp {
37
38 class TickerThread : public osl::Thread
39 {
40 bool m_bFinish;
41 CurlLockStore & m_rLockStore;
42
43 public:
44
TickerThread(CurlLockStore & rLockStore)45 TickerThread( CurlLockStore & rLockStore )
46 : osl::Thread(), m_bFinish( false ), m_rLockStore( rLockStore ) {}
47
finish()48 void finish() { m_bFinish = true; }
49
50 protected:
51
52 virtual void SAL_CALL run();
53 };
54
55 } // namespace http_dav_ucp
56
57 // -------------------------------------------------------------------
run()58 void TickerThread::run()
59 {
60 OSL_TRACE( "TickerThread::run: start." );
61
62 // we have to go through the loop more often to be able to finish ~quickly
63 const int nNth = 25;
64
65 int nCount = nNth;
66 while ( !m_bFinish )
67 {
68 if ( nCount-- <= 0 )
69 {
70 m_rLockStore.refreshLocks();
71 nCount = nNth;
72 }
73
74 TimeValue aTV;
75 aTV.Seconds = 0;
76 aTV.Nanosec = 1000000000 / nNth;
77 wait( aTV );
78 }
79
80 OSL_TRACE( "TickerThread: stop." );
81 }
82
83 // -------------------------------------------------------------------
CurlLockStore()84 CurlLockStore::CurlLockStore()
85 : m_pTickerThread( 0 )
86 {
87 }
88
89 // -------------------------------------------------------------------
~CurlLockStore()90 CurlLockStore::~CurlLockStore()
91 {
92 stopTicker();
93
94 // release active locks, if any.
95 OSL_ENSURE( m_aLockInfoMap.size() == 0,
96 "CurlLockStore::~CurlLockStore - Releasing active locks!" );
97
98 LockInfoMap::const_iterator it( m_aLockInfoMap.begin() );
99 const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
100 while ( it != end )
101 {
102 CurlLock * pLock = (*it).first;
103 try
104 {
105 (*it).second.xSession->UNLOCK( pLock );
106 (*it).second.xSession->release();
107 }
108 catch (DAVException & )
109 {}
110 ++it;
111 }
112 }
113
114 // -------------------------------------------------------------------
startTicker()115 void CurlLockStore::startTicker()
116 {
117 osl::MutexGuard aGuard( m_aMutex );
118
119 if ( !m_pTickerThread )
120 {
121 m_pTickerThread = new TickerThread( *this );
122 m_pTickerThread->create();
123 }
124 }
125
126 // -------------------------------------------------------------------
stopTicker()127 void CurlLockStore::stopTicker()
128 {
129 osl::MutexGuard aGuard( m_aMutex );
130
131 if ( m_pTickerThread )
132 {
133 m_pTickerThread->finish();
134 m_pTickerThread->join();
135 delete m_pTickerThread;
136 m_pTickerThread = 0;
137 }
138 }
139
140 #if 0 //not currently used
141 // -------------------------------------------------------------------
142 void CurlLockStore::registerSession( CurlSession /* aSession */ )
143 {
144 osl::MutexGuard aGuard( m_aMutex );
145
146 }
147 #endif
148
149 // -------------------------------------------------------------------
findByUri(rtl::OUString const & rUri)150 CurlLock * CurlLockStore::findByUri( rtl::OUString const & rUri)
151 {
152 osl::MutexGuard aGuard( m_aMutex );
153
154 LockInfoMap::const_iterator it( m_aLockInfoMap.begin() );
155 const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
156
157 while ( it != end )
158 {
159 CurlLock * pLock = (*it).first;
160 if( pLock->getResourceUri().equals( rUri ) )
161 {
162 return pLock;
163 }
164 ++it;
165 }
166
167 return static_cast<CurlLock*>(0);
168 }
169
170 // -------------------------------------------------------------------
addLock(CurlLock * pLock,rtl::Reference<CurlSession> const & xSession,sal_Int32 nLastChanceToSendRefreshRequest)171 void CurlLockStore::addLock( CurlLock * pLock,
172 rtl::Reference< CurlSession > const & xSession,
173 sal_Int32 nLastChanceToSendRefreshRequest )
174 {
175 osl::MutexGuard aGuard( m_aMutex );
176
177 m_aLockInfoMap[ pLock ]
178 = LockInfo( xSession, nLastChanceToSendRefreshRequest );
179 //acquire this session, needed to manage the lock refresh
180 xSession->acquire();
181
182 #if OSL_DEBUG_LEVEL > 0
183 rtl::OUString aOwner;
184 pLock->getLock().Owner >>= aOwner;
185 rtl::OUString aToken;
186 aToken = pLock->getLock().LockTokens[0];
187 OSL_TRACE("CurlLockStore::addLock: new lock added aOwner '%s', token '%s'",
188 rtl::OUStringToOString(aOwner, RTL_TEXTENCODING_UTF8).getStr(),
189 rtl::OUStringToOString(aToken, RTL_TEXTENCODING_UTF8).getStr() );
190 #endif
191 startTicker();
192 }
193
194 #if 0 //not currently used
195 // -------------------------------------------------------------------
196 void CurlLockStore::updateLock( CurlLock * pLock,
197 sal_Int32 nLastChanceToSendRefreshRequest )
198 {
199 osl::MutexGuard aGuard( m_aMutex );
200
201 LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) );
202 OSL_ENSURE( it != m_aLockInfoMap.end(),
203 "CurlLockStore::updateLock: lock not found!" );
204
205 if ( it != m_aLockInfoMap.end() )
206 {
207 (*it).second.nLastChanceToSendRefreshRequest
208 = nLastChanceToSendRefreshRequest;
209 }
210 }
211 #endif
212
213 // -------------------------------------------------------------------
removeLock(CurlLock * pLock)214 void CurlLockStore::removeLock( CurlLock * pLock )
215 {
216 osl::MutexGuard aGuard( m_aMutex );
217
218 LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) );
219 if(it != m_aLockInfoMap.end())
220 {
221 LockInfo & rInfo = (*it).second;
222 rInfo.xSession->release();
223 m_aLockInfoMap.erase( pLock );
224 //the caller should deallocate CurlLock class after the call!
225 if ( m_aLockInfoMap.size() == 0 )
226 stopTicker();
227 }
228 }
229
230 // -------------------------------------------------------------------
refreshLocks()231 void CurlLockStore::refreshLocks()
232 {
233 osl::MutexGuard aGuard( m_aMutex );
234
235 LockInfoMap::iterator it( m_aLockInfoMap.begin() );
236 const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
237 while ( it != end )
238 {
239 LockInfo & rInfo = (*it).second;
240 if ( rInfo.nLastChanceToSendRefreshRequest != -1 )
241 {
242 // 30 seconds or less remaining until lock expires?
243 TimeValue t1;
244 osl_getSystemTime( &t1 );
245 if ( rInfo.nLastChanceToSendRefreshRequest - 30
246 <= sal_Int32( t1.Seconds ) )
247 {
248 // refresh the lock.
249 #if OSL_DEBUG_LEVEL > 0
250 ucb::Lock aLock = (*it).first->getLock();
251 rtl::OUString aOwner;
252 aLock.Owner >>= aOwner;
253 rtl::OUString aToken;
254 aToken = aLock.LockTokens[0];
255 OSL_TRACE( "CurlLockStore::refreshLocks: refresh started for lock: aOwner '%s', token '%s'",
256 rtl::OUStringToOString(aOwner, RTL_TEXTENCODING_UTF8).getStr(),
257 rtl::OUStringToOString(aToken, RTL_TEXTENCODING_UTF8).getStr() );
258 #endif
259 sal_Int32 nlastChanceToSendRefreshRequest = -1;
260 try
261 {
262 rInfo.xSession->LOCK( (*it).first,
263 /* out param */ nlastChanceToSendRefreshRequest );
264 rInfo.nLastChanceToSendRefreshRequest
265 = nlastChanceToSendRefreshRequest;
266 #if OSL_DEBUG_LEVEL > 0
267 OSL_TRACE( "Lock '%s' successfully refreshed." ,
268 rtl::OUStringToOString(aToken, RTL_TEXTENCODING_UTF8).getStr() );
269 #endif
270 }
271 catch ( DAVException & e )
272 {
273 // refresh failed. stop auto-refresh.
274 // TODO i126305 discuss:
275 // probably not a good idea to stop the refresh?
276 // may be just ignore and go on, it's possible the net is temporary down?
277 rInfo.nLastChanceToSendRefreshRequest = -1;
278 #if OSL_DEBUG_LEVEL > 0
279 OSL_TRACE( "CurlLockStore::refreshLocks: Lock '%s' not refreshed! (error: DAVException.mStatusCode %d)",
280 rtl::OUStringToOString(aToken, RTL_TEXTENCODING_UTF8).getStr(), e.getStatus() );
281 #endif
282 }
283 }
284 }
285 ++it;
286 }
287 }
288