1 /*
2  * Copyright 2003-2021 The Music Player Daemon Project
3  * http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include "Manager.hxx"
21 #include "lib/fmt/ExceptionFormatter.hxx"
22 #include "event/Loop.hxx"
23 #include "util/DeleteDisposer.hxx"
24 #include "util/Domain.hxx"
25 #include "Log.hxx"
26 
27 #include <string.h>
28 
29 static constexpr Domain nfs_domain("nfs");
30 
31 void
OnNfsConnectionError(std::exception_ptr && e)32 NfsManager::ManagedConnection::OnNfsConnectionError(std::exception_ptr &&e) noexcept
33 {
34 	FmtError(nfs_domain, "NFS error on '{}:{}': {}",
35 		 GetServer(), GetExportName(), e);
36 
37 	/* defer deletion so the caller
38 	   (i.e. NfsConnection::OnSocketReady()) can still use this
39 	   object */
40 	manager.ScheduleDelete(*this);
41 }
42 
43 inline bool
operator ()(const LookupKey a,const ManagedConnection & b) const44 NfsManager::Compare::operator()(const LookupKey a,
45 				const ManagedConnection &b) const noexcept
46 {
47 	int result = strcmp(a.server, b.GetServer());
48 	if (result != 0)
49 		return result < 0;
50 
51 	result = strcmp(a.export_name, b.GetExportName());
52 	return result < 0;
53 }
54 
55 inline bool
operator ()(const ManagedConnection & a,const LookupKey b) const56 NfsManager::Compare::operator()(const ManagedConnection &a,
57 				const LookupKey b) const noexcept
58 {
59 	int result = strcmp(a.GetServer(), b.server);
60 	if (result != 0)
61 		return result < 0;
62 
63 	result = strcmp(a.GetExportName(), b.export_name);
64 	return result < 0;
65 }
66 
67 inline bool
operator ()(const ManagedConnection & a,const ManagedConnection & b) const68 NfsManager::Compare::operator()(const ManagedConnection &a,
69 				const ManagedConnection &b) const noexcept
70 {
71 	int result = strcmp(a.GetServer(), b.GetServer());
72 	if (result != 0)
73 		return result < 0;
74 
75 	result = strcmp(a.GetExportName(), b.GetExportName());
76 	return result < 0;
77 }
78 
~NfsManager()79 NfsManager::~NfsManager() noexcept
80 {
81 	assert(!GetEventLoop().IsAlive() || GetEventLoop().IsInside());
82 
83 	CollectGarbage();
84 
85 	connections.clear_and_dispose(DeleteDisposer());
86 }
87 
88 NfsConnection &
GetConnection(const char * server,const char * export_name)89 NfsManager::GetConnection(const char *server, const char *export_name) noexcept
90 {
91 	assert(server != nullptr);
92 	assert(export_name != nullptr);
93 	assert(GetEventLoop().IsInside());
94 
95 	Map::insert_commit_data hint;
96 	auto result = connections.insert_check(LookupKey{server, export_name},
97 					       Compare(), hint);
98 	if (result.second) {
99 		auto c = new ManagedConnection(*this, GetEventLoop(),
100 					       server, export_name);
101 		connections.insert_commit(*c, hint);
102 		return *c;
103 	} else {
104 		return *result.first;
105 	}
106 }
107 
108 void
CollectGarbage()109 NfsManager::CollectGarbage() noexcept
110 {
111 	assert(!GetEventLoop().IsAlive() || GetEventLoop().IsInside());
112 
113 	garbage.clear_and_dispose(DeleteDisposer());
114 }
115 
116 void
OnIdle()117 NfsManager::OnIdle() noexcept
118 {
119 	CollectGarbage();
120 }
121