1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/ustring.hxx>
22 #include <sal/log.hxx>
24 #include <osl/thread.hxx>
25 #include <salhelper/thread.hxx>
27 #include <com/sun/star/ucb/LockScope.hpp>
30 #include "CurlSession.hxx"
31 #include "SerfLockStore.hxx"
33 using namespace http_dav_ucp
;
35 namespace http_dav_ucp
{
37 class TickerThread
: public salhelper::Thread
40 SerfLockStore
& m_rLockStore
;
44 explicit TickerThread( SerfLockStore
& rLockStore
)
45 : Thread( "WebDavTickerThread" ), m_bFinish( false ),
46 m_rLockStore( rLockStore
) {}
48 void finish() { m_bFinish
= true; }
52 virtual void execute();
55 } // namespace http_dav_ucp
58 void TickerThread::execute()
60 osl_setThreadName("http_dav_ucp::TickerThread");
62 SAL_INFO("ucb.ucp.webdav", "TickerThread: start." );
64 // we have to go through the loop more often to be able to finish ~quickly
72 m_rLockStore
.refreshLocks();
76 std::this_thread::sleep_for( std::chrono::milliseconds(1000/25) );
79 SAL_INFO("ucb.ucp.webdav", "TickerThread: stop." );
83 SerfLockStore::SerfLockStore()
88 SerfLockStore::~SerfLockStore()
90 std::unique_lock
aGuard(m_aMutex
);
92 aGuard
.lock(); // actually no threads should even try to access members now
94 // release active locks, if any.
95 SAL_WARN_IF( !m_aLockInfoMap
.empty(), "ucb.ucp.webdav",
96 "SerfLockStore::~SerfLockStore - Releasing active locks!" );
98 for ( auto& rLockInfo
: m_aLockInfoMap
)
100 rLockInfo
.second
.m_xSession
->NonInteractive_UNLOCK(rLockInfo
.first
);
104 void SerfLockStore::startTicker()
106 std::unique_lock
aGuard( m_aMutex
);
108 if ( !m_pTickerThread
.is() )
110 m_pTickerThread
= new TickerThread( *this );
111 m_pTickerThread
->launch();
116 void SerfLockStore::stopTicker(std::unique_lock
<std::mutex
> & rGuard
)
118 rtl::Reference
<TickerThread
> pTickerThread
;
120 if (m_pTickerThread
.is())
122 m_pTickerThread
->finish(); // needs mutex
123 // the TickerThread may run refreshLocks() at most once after this
124 pTickerThread
= m_pTickerThread
;
125 m_pTickerThread
.clear();
130 if (pTickerThread
.is() && pTickerThread
->getIdentifier() != osl::Thread::getCurrentIdentifier())
132 pTickerThread
->join(); // without m_aMutex locked (to prevent deadlock)
137 SerfLockStore::getLockTokenForURI(OUString
const& rURI
, css::ucb::Lock
const*const pLock
)
139 assert(rURI
.startsWith("http://") || rURI
.startsWith("https://"));
141 std::unique_lock
aGuard( m_aMutex
);
143 auto const it(m_aLockInfoMap
.find(rURI
));
145 if (it
== m_aLockInfoMap
.end())
149 if (!pLock
) // any lock will do
151 return &it
->second
.m_sToken
;
153 // 0: EXCLUSIVE 1: SHARED
154 if (it
->second
.m_Lock
.Scope
== ucb::LockScope_SHARED
&& pLock
->Scope
== ucb::LockScope_EXCLUSIVE
)
158 assert(it
->second
.m_Lock
.Type
== pLock
->Type
); // only WRITE possible
159 if (it
->second
.m_Lock
.Depth
< pLock
->Depth
)
163 // Only own locks are expected in the lock store, but depending on the
164 // server it->second.m_Lock.Owner may contain the string this UCP passed in
165 // the LOCK request, or a user identifier generated by the server (happens
166 // with Sharepoint), so just ignore it here.
168 return &it
->second
.m_sToken
;
171 void SerfLockStore::addLock( const OUString
& rURI
,
172 ucb::Lock
const& rLock
,
173 const OUString
& sToken
,
174 rtl::Reference
<CurlSession
> const & xSession
,
175 sal_Int32 nLastChanceToSendRefreshRequest
)
177 assert(rURI
.startsWith("http://") || rURI
.startsWith("https://"));
179 std::unique_lock
aGuard( m_aMutex
);
181 m_aLockInfoMap
[ rURI
]
182 = LockInfo(sToken
, rLock
, xSession
, nLastChanceToSendRefreshRequest
);
189 void SerfLockStore::removeLock(const OUString
& rURI
)
191 std::unique_lock
aGuard( m_aMutex
);
193 removeLockImpl(aGuard
, rURI
);
196 void SerfLockStore::removeLockImpl(std::unique_lock
<std::mutex
> & rGuard
, const OUString
& rURI
)
198 assert(rURI
.startsWith("http://") || rURI
.startsWith("https://"));
200 m_aLockInfoMap
.erase(rURI
);
202 if ( m_aLockInfoMap
.empty() )
208 void SerfLockStore::refreshLocks()
210 std::unique_lock
aGuard( m_aMutex
);
212 ::std::vector
<OUString
> authFailedLocks
;
214 for ( auto& rLockInfo
: m_aLockInfoMap
)
216 LockInfo
& rInfo
= rLockInfo
.second
;
217 if ( rInfo
.m_nLastChanceToSendRefreshRequest
!= -1 )
219 // 30 seconds or less remaining until lock expires?
221 osl_getSystemTime( &t1
);
222 if ( rInfo
.m_nLastChanceToSendRefreshRequest
- 30
223 <= sal_Int32( t1
.Seconds
) )
226 sal_Int32 nlastChanceToSendRefreshRequest
= -1;
227 bool isAuthFailed(false);
228 if (rInfo
.m_xSession
->NonInteractive_LOCK(
229 rLockInfo
.first
, rLockInfo
.second
.m_sToken
,
230 nlastChanceToSendRefreshRequest
,
233 rInfo
.m_nLastChanceToSendRefreshRequest
234 = nlastChanceToSendRefreshRequest
;
240 authFailedLocks
.push_back(rLockInfo
.first
);
242 // refresh failed. stop auto-refresh.
243 rInfo
.m_nLastChanceToSendRefreshRequest
= -1;
249 for (auto const& rLock
: authFailedLocks
)
251 removeLockImpl(aGuard
, rLock
);
255 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */