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