aboutsummaryrefslogtreecommitdiff
path: root/include/usermanager.h
blob: 9c824f3f7f5f8883d5a06ebc45a745f2eda59fc0 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 * InspIRCd -- Internet Relay Chat Daemon
 *
 *   Copyright (C) 2015 Adam <Adam@anope.org>
 *   Copyright (C) 2012-2016 Attila Molnar <attilamolnar@hush.com>
 *   Copyright (C) 2012-2013, 2017, 2019-2023 Sadie Powell <sadie@witchery.services>
 *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
 *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
 *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
 *
 * This file is part of InspIRCd.  InspIRCd is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, version 2.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#pragma once

#include <list>

/** A mapping of user nicks or uuids to their User object. */
typedef std::unordered_map<std::string, User*, irc::insensitive, irc::StrHashComp> UserMap;

class CoreExport UserManager final
{
public:
	struct CloneCounts final
	{
		unsigned int global = 0;
		unsigned int local = 0;
	};

	/** Container that maps IP addresses to clone counts
	 */
	typedef std::map<irc::sockets::cidr_mask, CloneCounts> CloneMap;

	/** Sequence container in which each element is a User*
	 */
	typedef std::vector<User*> OperList;

	/** A list containing users who are on a services server. */
	typedef std::vector<User*> ServiceList;

	/** A list holding local users
	*/
	typedef insp::intrusive_list<LocalUser> LocalList;

private:
	/** Map of IP addresses for clone counting
	 */
	CloneMap clonemap;

	/** A CloneCounts that contains zero for both local and global
	 */
	const CloneCounts zeroclonecounts;

	/** Local client list, a list containing only local clients
	 */
	LocalList local_users;

	/** Last used already sent id, used when sending messages to neighbors to help determine whether the message has
	 * been sent to a particular user or not. See User::ForEachNeighbor() for more info.
	 */
	uint64_t already_sent_id = 0;

public:
	/** Constructor, initializes variables
	 */
	UserManager();

	/** Destructor, destroys all users in clientlist
	 */
	~UserManager();

	/** Nickname string -> User* map. Contains all users, including partially connected ones.
	 */
	UserMap clientlist;

	/** UUID -> User* map. Contains all users, including partially connected ones.
	 */
	UserMap uuidlist;

	/** Oper list, a vector containing all local and remote opered users
	 */
	OperList all_opers;

	/** A list of users on services servers. */
	ServiceList all_services;

	/** Number of local unknown (not fully connected) users. */
	size_t unknown_count = 0;

	/** Perform background user events for all local users such as PING checks, connection timeouts,
	 * penalty management and recvq processing for users who have data in their recvq due to throttling.
	 */
	void DoBackgroundUserStuff();

	/** Handle a client connection.
	 * Creates a new LocalUser object, inserts it into the appropriate containers,
	 * initializes it as not fully connected, and adds it to the socket engine.
	 *
	 * The new user may immediately be quit after being created, for example if the user limit
	 * is reached or if the user is banned.
	 * @param socket File descriptor of the connection
	 * @param via Listener socket that this user connected to
	 * @param client The IP address and client port of the user
	 * @param server The server IP address and port used by the user
	 */
	void AddUser(int socket, ListenSocket* via, const irc::sockets::sockaddrs& client, const irc::sockets::sockaddrs& server) ATTR_NOT_NULL(3);

	/** Disconnect a user gracefully.
	 * When this method returns the user provided will be quit, but the User object will continue to be valid and will be deleted at the end of the current main loop iteration.
	 * @param user The user to remove
	 * @param quitreason The quit reason to show to normal users
	 * @param operreason The quit reason to show to opers, can be NULL if same as quitreason
	 */
	void QuitUser(User* user, const std::string& quitreason, const std::string* operreason = nullptr) ATTR_NOT_NULL(2);

	/** Add a user to the clone map
	 * @param user The user to add
	 */
	void AddClone(User* user) ATTR_NOT_NULL(2);

	/** Remove all clone counts from the user, you should
	 * use this if you change the user's IP address
	 * after they have fully connected.
	 * @param user The user to remove
	 */
	void RemoveCloneCounts(User* user) ATTR_NOT_NULL(2);

	/** Rebuild clone counts. Required when \<cidr> settings change.
	 */
	void RehashCloneCounts();

	/** Return the number of local and global clones of this user
	 * @param user The user to get the clone counts for
	 * @return The clone counts of this user. The returned reference is volatile - you
	 * must assume that it becomes invalid as soon as you call any function other than
	 * your own.
	 */
	const CloneCounts& GetCloneCounts(User* user) const ATTR_NOT_NULL(2);

	/** Return a map containing IP addresses and their clone counts
	 * @return The clone count map
	 */
	const CloneMap& GetCloneMap() const { return clonemap; }

	/** Return a count of local unknown (not fully connected) users.
	 * @return The number of local unknown (not fully connected) users.
	 */
	size_t UnknownUserCount() const { return this->unknown_count; }

	/** Return a count of users on a services servers.
	 * @return The number of users on services servers.
	 */
	size_t ServiceCount() const { return this->all_services.size(); }

	/** Return a count of fully connected connections on this server.
	 * @return The number of fully connected users on this server.
	 */
	size_t LocalUserCount() const { return this->local_users.size() - this->UnknownUserCount(); }

	/** Return a count of fully connected connections on the network.
	 * @return The number of fully connected users on the network.
	 */
	size_t GlobalUserCount() const { return this->clientlist.size() - this->UnknownUserCount() - this->ServiceCount(); }

	/** Get a hash map containing all users, keyed by their nickname
	 * @return A hash map mapping nicknames to User pointers
	 */
	UserMap& GetUsers() { return clientlist; }

	/** Get a list containing all local users
	 * @return A const list of local users
	 */
	const LocalList& GetLocalUsers() const { return local_users; }

	/** Retrieves the next already sent id, guaranteed to be not equal to any user's already_sent field
	 * @return Next already_sent id
	 */
	uint64_t NextAlreadySentId();

	/** Find a user by their nickname or UUID.
	 * IMPORTANT: You probably want to use FindNick or FindUUID instead of this.
	 * @param nickuuid The nickname or UUID of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	User* Find(const std::string& nickuuid, bool fullyconnected = false);

	/** Find a local user by their nickname or UUID.
	 * IMPORTANT: You probably want to use FindNick or FindUUID instead of this.
	 * @param nickuuid The nickname or UUID of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	template<typename T>
	std::enable_if_t<std::is_same_v<T, LocalUser>, T*> Find(const std::string& nickuuid, bool fullyconnected = false)
	{
		return IS_LOCAL(Find(nickuuid, fullyconnected));
	}

	/** Find a remote user by their nickname or UUID.
	 * IMPORTANT: You probably want to use FindNick or FindUUID instead of this.
	 * @param nickuuid The nickname or UUID of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	template<typename T>
	std::enable_if_t<std::is_same_v<T, RemoteUser>, T*> Find(const std::string& nickuuid, bool fullyconnected = false)
	{
		return IS_REMOTE(Find(nickuuid, fullyconnected));
	}

	/** Find a user by their nickname.
	 * @param nick The nickname of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	User* FindNick(const std::string& nick, bool fullyconnected = false);

	/** Find a local user by their nickname.
	 * @param nick The nickname of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	template<typename T>
	std::enable_if_t<std::is_same_v<T, LocalUser>, T*> FindNick(const std::string& nick, bool fullyconnected = false)
	{
		return IS_LOCAL(FindNick(nick, fullyconnected));
	}

	/** Find a remote user by their nickname.
	 * @param nick The nickname of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	template<typename T>
	std::enable_if_t<std::is_same_v<T, RemoteUser>, T*> FindNick(const std::string& nick, bool fullyconnected = false)
	{
		return IS_REMOTE(FindNick(nick, fullyconnected));
	}

	/** Find a user by their UUID.
	 * @param uuid The UUID of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	User* FindUUID(const std::string& uuid, bool fullyconnected = false);

	/** Find a local user by their UUID.
	 * @param uuid The UUID of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	template<typename T>
	std::enable_if_t<std::is_same_v<T, LocalUser>, T*> FindUUID(const std::string& uuid, bool fullyconnected = false)
	{
		return IS_LOCAL(FindUUID(uuid, fullyconnected));
	}

	/** Find a remote user by their UUID.
	 * @param uuid The UUID of the user to find.
	 * @param fullyconnected Whether to only return users who are fully connected to the server.
	 * @return If the user was found then a pointer to a User object; otherwise, nullptr.
	 */
	template<typename T>
	std::enable_if_t<std::is_same_v<T, RemoteUser>, T*> FindUUID(const std::string& uuid, bool fullyconnected = false)
	{
		return IS_REMOTE(FindUUID(uuid, fullyconnected));
	}
};