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_ucb.hxx"
26 
27 #include <ne_locks.h>
28 #include <ne_uri.h>
29 #include "rtl/ustring.hxx"
30 #include "osl/time.h"
31 #include "osl/thread.hxx"
32 #include "SerfSession.hxx"
33 #include "SerfLockStore.hxx"
34 
35 using namespace http_dav_ucp;
36 
37 namespace http_dav_ucp {
38 
39 class TickerThread : public osl::Thread
40 {
41     bool m_bFinish;
42     SerfLockStore & m_rLockStore;
43 
44 public:
45 
46     TickerThread( SerfLockStore & rLockStore )
47     : osl::Thread(), m_bFinish( false ), m_rLockStore( rLockStore ) {}
48 
49     void finish() { m_bFinish = true; }
50 
51 protected:
52 
53     virtual void SAL_CALL run();
54 };
55 
56 } // namespace http_dav_ucp
57 
58 // -------------------------------------------------------------------
59 void TickerThread::run()
60 {
61     OSL_TRACE( "TickerThread: start." );
62 
63     // we have to go through the loop more often to be able to finish ~quickly
64     const int nNth = 25;
65 
66     int nCount = nNth;
67     while ( !m_bFinish )
68     {
69         if ( nCount-- <= 0 )
70         {
71             m_rLockStore.refreshLocks();
72             nCount = nNth;
73         }
74 
75         TimeValue aTV;
76         aTV.Seconds = 0;
77         aTV.Nanosec = 1000000000 / nNth;
78         wait( aTV );
79     }
80 
81     OSL_TRACE( "TickerThread: stop." );
82 }
83 
84 // -------------------------------------------------------------------
85 SerfLockStore::SerfLockStore()
86     : m_pSerfLockStore( ne_lockstore_create() ),
87       m_pTickerThread( 0 )
88 {
89     OSL_ENSURE( m_pSerfLockStore, "Unable to create neon lock store!" );
90 }
91 
92 // -------------------------------------------------------------------
93 SerfLockStore::~SerfLockStore()
94 {
95     stopTicker();
96 
97     // release active locks, if any.
98     OSL_ENSURE( m_aLockInfoMap.size() == 0,
99                 "SerfLockStore::~SerfLockStore - Releasing active locks!" );
100 
101     LockInfoMap::const_iterator it( m_aLockInfoMap.begin() );
102     const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
103     while ( it != end )
104     {
105         SerfLock * pLock = (*it).first;
106         (*it).second.xSession->UNLOCK( pLock );
107 
108         ne_lockstore_remove( m_pSerfLockStore, pLock );
109         ne_lock_destroy( pLock );
110 
111         ++it;
112     }
113 
114     ne_lockstore_destroy( m_pSerfLockStore );
115 }
116 
117 // -------------------------------------------------------------------
118 void SerfLockStore::startTicker()
119 {
120     osl::MutexGuard aGuard( m_aMutex );
121 
122     if ( !m_pTickerThread )
123     {
124         m_pTickerThread = new TickerThread( *this );
125         m_pTickerThread->create();
126     }
127 }
128 
129 // -------------------------------------------------------------------
130 void SerfLockStore::stopTicker()
131 {
132     osl::MutexGuard aGuard( m_aMutex );
133 
134     if ( m_pTickerThread )
135     {
136         m_pTickerThread->finish();
137         m_pTickerThread->join();
138         delete m_pTickerThread;
139         m_pTickerThread = 0;
140     }
141 }
142 
143 // -------------------------------------------------------------------
144 void SerfLockStore::registerSession( HttpSession * pHttpSession )
145 {
146     osl::MutexGuard aGuard( m_aMutex );
147 
148     ne_lockstore_register( m_pSerfLockStore, pHttpSession );
149 }
150 
151 // -------------------------------------------------------------------
152 SerfLock * SerfLockStore::findByUri( rtl::OUString const & rUri )
153 {
154     osl::MutexGuard aGuard( m_aMutex );
155 
156     ne_uri aUri;
157     ne_uri_parse( rtl::OUStringToOString(
158         rUri, RTL_TEXTENCODING_UTF8 ).getStr(), &aUri );
159     return ne_lockstore_findbyuri( m_pSerfLockStore, &aUri );
160 }
161 
162 // -------------------------------------------------------------------
163 void SerfLockStore::addLock( SerfLock * pLock,
164                              rtl::Reference< SerfSession > const & xSession,
165                              sal_Int32 nLastChanceToSendRefreshRequest )
166 {
167     osl::MutexGuard aGuard( m_aMutex );
168 
169     ne_lockstore_add( m_pSerfLockStore, pLock );
170     m_aLockInfoMap[ pLock ]
171         = LockInfo( xSession, nLastChanceToSendRefreshRequest );
172 
173     startTicker();
174 }
175 
176 // -------------------------------------------------------------------
177 void SerfLockStore::updateLock( SerfLock * pLock,
178                                 sal_Int32 nLastChanceToSendRefreshRequest )
179 {
180     osl::MutexGuard aGuard( m_aMutex );
181 
182     LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) );
183     OSL_ENSURE( it != m_aLockInfoMap.end(),
184                 "SerfLockStore::updateLock: lock not found!" );
185 
186     if ( it != m_aLockInfoMap.end() )
187     {
188         (*it).second.nLastChanceToSendRefreshRequest
189             = nLastChanceToSendRefreshRequest;
190     }
191 }
192 
193 // -------------------------------------------------------------------
194 void SerfLockStore::removeLock( SerfLock * pLock )
195 {
196     osl::MutexGuard aGuard( m_aMutex );
197 
198     m_aLockInfoMap.erase( pLock );
199     ne_lockstore_remove( m_pSerfLockStore, pLock );
200 
201     if ( m_aLockInfoMap.size() == 0 )
202         stopTicker();
203 }
204 
205 // -------------------------------------------------------------------
206 void SerfLockStore::refreshLocks()
207 {
208     osl::MutexGuard aGuard( m_aMutex );
209 
210     LockInfoMap::iterator it( m_aLockInfoMap.begin() );
211     const LockInfoMap::const_iterator end( m_aLockInfoMap.end() );
212     while ( it != end )
213     {
214         LockInfo & rInfo = (*it).second;
215         if ( rInfo.nLastChanceToSendRefreshRequest != -1 )
216         {
217             // 30 seconds or less remaining until lock expires?
218             TimeValue t1;
219             osl_getSystemTime( &t1 );
220             if ( rInfo.nLastChanceToSendRefreshRequest - 30
221                      <= sal_Int32( t1.Seconds ) )
222             {
223                 // refresh the lock.
224                 sal_Int32 nlastChanceToSendRefreshRequest = -1;
225                 if ( rInfo.xSession->LOCK(
226                          (*it).first,
227                          /* out param */ nlastChanceToSendRefreshRequest ) )
228                 {
229                     rInfo.nLastChanceToSendRefreshRequest
230                         = nlastChanceToSendRefreshRequest;
231                 }
232                 else
233                 {
234                     // refresh failed. stop auto-refresh.
235                     rInfo.nLastChanceToSendRefreshRequest = -1;
236                 }
237             }
238         }
239         ++it;
240     }
241 }
242