Commit 601495fa authored by Max Kellermann's avatar Max Kellermann

ClientList: convert to a class

parent 19986337
...@@ -222,7 +222,7 @@ src_mpd_SOURCES = \ ...@@ -222,7 +222,7 @@ src_mpd_SOURCES = \
src/ClientEvent.cxx \ src/ClientEvent.cxx \
src/ClientExpire.cxx \ src/ClientExpire.cxx \
src/ClientGlobal.cxx \ src/ClientGlobal.cxx \
src/ClientIdle.cxx src/ClientIdle.hxx \ src/ClientIdle.cxx \
src/ClientList.cxx src/ClientList.hxx \ src/ClientList.cxx src/ClientList.hxx \
src/ClientNew.cxx \ src/ClientNew.cxx \
src/ClientProcess.cxx \ src/ClientProcess.cxx \
......
...@@ -31,7 +31,6 @@ struct Partition; ...@@ -31,7 +31,6 @@ struct Partition;
class Client; class Client;
void client_manager_init(void); void client_manager_init(void);
void client_manager_deinit(void);
void void
client_new(EventLoop &loop, Partition &partition, client_new(EventLoop &loop, Partition &partition,
......
...@@ -25,12 +25,9 @@ ...@@ -25,12 +25,9 @@
#include <assert.h> #include <assert.h>
#define CLIENT_TIMEOUT_DEFAULT (60) #define CLIENT_TIMEOUT_DEFAULT (60)
#define CLIENT_MAX_CONNECTIONS_DEFAULT (10)
#define CLIENT_MAX_COMMAND_LIST_DEFAULT (2048*1024) #define CLIENT_MAX_COMMAND_LIST_DEFAULT (2048*1024)
#define CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024) #define CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
/* set this to zero to indicate we have no possible clients */
unsigned int client_max_connections;
int client_timeout; int client_timeout;
size_t client_max_command_list_size; size_t client_max_command_list_size;
size_t client_max_output_buffer_size; size_t client_max_output_buffer_size;
...@@ -39,9 +36,6 @@ void client_manager_init(void) ...@@ -39,9 +36,6 @@ void client_manager_init(void)
{ {
client_timeout = config_get_positive(CONF_CONN_TIMEOUT, client_timeout = config_get_positive(CONF_CONN_TIMEOUT,
CLIENT_TIMEOUT_DEFAULT); CLIENT_TIMEOUT_DEFAULT);
client_max_connections =
config_get_positive(CONF_MAX_CONN,
CLIENT_MAX_CONNECTIONS_DEFAULT);
client_max_command_list_size = client_max_command_list_size =
config_get_positive(CONF_MAX_COMMAND_LIST_SIZE, config_get_positive(CONF_MAX_COMMAND_LIST_SIZE,
CLIENT_MAX_COMMAND_LIST_DEFAULT / 1024) CLIENT_MAX_COMMAND_LIST_DEFAULT / 1024)
...@@ -52,10 +46,3 @@ void client_manager_init(void) ...@@ -52,10 +46,3 @@ void client_manager_init(void)
CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT / 1024) CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT / 1024)
* 1024; * 1024;
} }
void client_manager_deinit(void)
{
client_list_close_all();
client_max_connections = 0;
}
...@@ -18,9 +18,7 @@ ...@@ -18,9 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "ClientIdle.hxx"
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include "ClientList.hxx"
#include "Idle.hxx" #include "Idle.hxx"
#include <assert.h> #include <assert.h>
...@@ -58,21 +56,6 @@ Client::IdleAdd(unsigned flags) ...@@ -58,21 +56,6 @@ Client::IdleAdd(unsigned flags)
IdleNotify(); IdleNotify();
} }
static void
client_idle_callback(Client *client, gpointer user_data)
{
unsigned flags = GPOINTER_TO_UINT(user_data);
client->IdleAdd(flags);
}
void client_manager_idle_add(unsigned flags)
{
assert(flags != 0);
client_list_foreach(client_idle_callback, GUINT_TO_POINTER(flags));
}
bool bool
Client::IdleWait(unsigned flags) Client::IdleWait(unsigned flags)
{ {
......
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_CLIENT_IDLE_HXX
#define MPD_CLIENT_IDLE_HXX
/**
* Adds the specified idle flags to all clients and immediately sends
* notifications to all waiting clients.
*/
void
client_manager_idle_add(unsigned flags);
#endif
...@@ -125,7 +125,6 @@ private: ...@@ -125,7 +125,6 @@ private:
virtual bool OnTimeout() override; virtual bool OnTimeout() override;
}; };
extern unsigned int client_max_connections;
extern int client_timeout; extern int client_timeout;
extern size_t client_max_command_list_size; extern size_t client_max_command_list_size;
extern size_t client_max_output_buffer_size; extern size_t client_max_output_buffer_size;
......
...@@ -21,51 +21,36 @@ ...@@ -21,51 +21,36 @@
#include "ClientList.hxx" #include "ClientList.hxx"
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include <list>
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
static std::list<Client *> clients;
static unsigned num_clients;
bool
client_list_is_full(void)
{
return num_clients >= client_max_connections;
}
void void
client_list_add(Client *client) ClientList::Remove(Client &client)
{ {
clients.push_front(client); assert(size > 0);
++num_clients; assert(!list.empty());
}
void auto i = std::find(list.begin(), list.end(), &client);
client_list_foreach(void (*callback)(Client *client, void *ctx), void *ctx) assert(i != list.end());
{ list.erase(i);
for (Client *client : clients) --size;
callback(client, ctx);
} }
void void
client_list_remove(Client *client) ClientList::CloseAll()
{ {
assert(num_clients > 0); while (!list.empty())
assert(!clients.empty()); list.front()->Close();
auto i = std::find(clients.begin(), clients.end(), client); assert(size == 0);
assert(i != clients.end());
clients.erase(i);
--num_clients;
} }
void void
client_list_close_all() ClientList::IdleAdd(unsigned flags)
{ {
while (!clients.empty()) assert(flags != 0);
clients.front()->Close();
assert(num_clients == 0); for (const auto &client : list)
client->IdleAdd(flags);
} }
...@@ -20,21 +20,42 @@ ...@@ -20,21 +20,42 @@
#ifndef MPD_CLIENT_LIST_HXX #ifndef MPD_CLIENT_LIST_HXX
#define MPD_CLIENT_LIST_HXX #define MPD_CLIENT_LIST_HXX
#include <list>
class Client; class Client;
bool class ClientList {
client_list_is_full(void); const unsigned max_size;
unsigned size;
std::list<Client *> list;
public:
ClientList(unsigned _max_size)
:max_size(_max_size), size(0) {}
std::list<Client *>::iterator begin() {
return list.begin();
}
std::list<Client *>::iterator end() {
return list.end();
}
bool IsFull() const {
return size >= max_size;
}
void void Add(Client &client) {
client_list_add(Client *client); list.push_front(&client);
++size;
}
void void Remove(Client &client);
client_list_foreach(void (*callback)(Client *client, void *ctx), void *ctx);
void void CloseAll();
client_list_remove(Client *client);
void void IdleAdd(unsigned flags);
client_list_close_all(); };
#endif #endif
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include "ClientList.hxx" #include "ClientList.hxx"
#include "Partition.hxx" #include "Partition.hxx"
#include "Main.hxx"
#include "fd_util.h" #include "fd_util.h"
extern "C" { extern "C" {
#include "resolver.h" #include "resolver.h"
...@@ -95,7 +96,7 @@ client_new(EventLoop &loop, Partition &partition, ...@@ -95,7 +96,7 @@ client_new(EventLoop &loop, Partition &partition,
} }
#endif /* HAVE_WRAP */ #endif /* HAVE_WRAP */
if (client_list_is_full()) { if (client_list->IsFull()) {
g_warning("Max Connections Reached!"); g_warning("Max Connections Reached!");
close_socket(fd); close_socket(fd);
return; return;
...@@ -106,7 +107,7 @@ client_new(EventLoop &loop, Partition &partition, ...@@ -106,7 +107,7 @@ client_new(EventLoop &loop, Partition &partition,
(void)send(fd, GREETING, sizeof(GREETING) - 1, 0); (void)send(fd, GREETING, sizeof(GREETING) - 1, 0);
client_list_add(client); client_list->Add(*client);
remote = sockaddr_to_string(sa, sa_length, NULL); remote = sockaddr_to_string(sa, sa_length, NULL);
g_log(G_LOG_DOMAIN, LOG_LEVEL_SECURE, g_log(G_LOG_DOMAIN, LOG_LEVEL_SECURE,
...@@ -117,7 +118,7 @@ client_new(EventLoop &loop, Partition &partition, ...@@ -117,7 +118,7 @@ client_new(EventLoop &loop, Partition &partition,
void void
Client::Close() Client::Close()
{ {
client_list_remove(this); client_list->Remove(*this);
SetExpired(); SetExpired();
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "config.h" #include "config.h"
#include "ClientSubscribe.hxx" #include "ClientSubscribe.hxx"
#include "ClientIdle.hxx"
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include "Idle.hxx" #include "Idle.hxx"
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
#include "DatabaseSimple.hxx" #include "DatabaseSimple.hxx"
#include "Permission.hxx" #include "Permission.hxx"
#include "Listen.hxx" #include "Listen.hxx"
#include "ClientIdle.hxx"
#include "Client.hxx" #include "Client.hxx"
#include "ClientList.hxx"
#include "AllCommands.hxx" #include "AllCommands.hxx"
#include "Partition.hxx" #include "Partition.hxx"
#include "Volume.hxx" #include "Volume.hxx"
...@@ -99,6 +99,8 @@ enum { ...@@ -99,6 +99,8 @@ enum {
GThread *main_task; GThread *main_task;
EventLoop *main_loop; EventLoop *main_loop;
ClientList *client_list;
Partition *global_partition; Partition *global_partition;
static StateFile *state_file; static StateFile *state_file;
...@@ -330,7 +332,7 @@ idle_event_emitted(void) ...@@ -330,7 +332,7 @@ idle_event_emitted(void)
clients */ clients */
unsigned flags = idle_get(); unsigned flags = idle_get();
if (flags != 0) if (flags != 0)
client_manager_idle_add(flags); client_list->IdleAdd(flags);
} }
/** /**
...@@ -401,6 +403,9 @@ int mpd_main(int argc, char *argv[]) ...@@ -401,6 +403,9 @@ int mpd_main(int argc, char *argv[])
main_task = g_thread_self(); main_task = g_thread_self();
main_loop = new EventLoop(EventLoop::Default()); main_loop = new EventLoop(EventLoop::Default());
const unsigned max_clients = config_get_positive(CONF_MAX_CONN, 10);
client_list = new ClientList(max_clients);
success = listen_global_init(&error); success = listen_global_init(&error);
if (!success) { if (!success) {
g_warning("%s", error->message); g_warning("%s", error->message);
...@@ -532,8 +537,8 @@ int mpd_main(int argc, char *argv[]) ...@@ -532,8 +537,8 @@ int mpd_main(int argc, char *argv[])
pc_kill(&global_partition->pc); pc_kill(&global_partition->pc);
finishZeroconf(); finishZeroconf();
client_manager_deinit();
listen_global_finish(); listen_global_finish();
delete client_list;
start = clock(); start = clock();
DatabaseGlobalDeinit(); DatabaseGlobalDeinit();
......
...@@ -28,6 +28,8 @@ extern GThread *main_task; ...@@ -28,6 +28,8 @@ extern GThread *main_task;
extern EventLoop *main_loop; extern EventLoop *main_loop;
extern class ClientList *client_list;
extern struct Partition *global_partition; extern struct Partition *global_partition;
/** /**
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "ClientSubscribe.hxx" #include "ClientSubscribe.hxx"
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include "ClientList.hxx" #include "ClientList.hxx"
#include "Main.hxx"
#include "protocol/Result.hxx" #include "protocol/Result.hxx"
#include "protocol/ArgParser.hxx" #include "protocol/ArgParser.hxx"
...@@ -73,31 +74,18 @@ handle_unsubscribe(Client *client, G_GNUC_UNUSED int argc, char *argv[]) ...@@ -73,31 +74,18 @@ handle_unsubscribe(Client *client, G_GNUC_UNUSED int argc, char *argv[])
} }
} }
struct channels_context {
std::set<std::string> channels;
};
static void
collect_channels(Client *client, gpointer user_data)
{
struct channels_context *context =
(struct channels_context *)user_data;
context->channels.insert(client->subscriptions.begin(),
client->subscriptions.end());
}
enum command_return enum command_return
handle_channels(Client *client, handle_channels(Client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{ {
assert(argc == 1); assert(argc == 1);
struct channels_context context; std::set<std::string> channels;
for (const auto &c : *client_list)
client_list_foreach(collect_channels, &context); channels.insert(c->subscriptions.begin(),
c->subscriptions.end());
for (const auto &channel : context.channels) for (const auto &channel : channels)
client_printf(client, "channel: %s\n", channel.c_str()); client_printf(client, "channel: %s\n", channel.c_str());
return COMMAND_RETURN_OK; return COMMAND_RETURN_OK;
...@@ -120,27 +108,6 @@ handle_read_messages(Client *client, ...@@ -120,27 +108,6 @@ handle_read_messages(Client *client,
return COMMAND_RETURN_OK; return COMMAND_RETURN_OK;
} }
struct send_message_context {
ClientMessage msg;
bool sent;
template<typename T, typename U>
send_message_context(T &&_channel, U &&_message)
:msg(std::forward<T>(_channel), std::forward<U>(_message)),
sent(false) {}
};
static void
send_message(Client *client, gpointer user_data)
{
struct send_message_context *context =
(struct send_message_context *)user_data;
if (client_push_message(client, context->msg))
context->sent = true;
}
enum command_return enum command_return
handle_send_message(Client *client, handle_send_message(Client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
...@@ -153,11 +120,13 @@ handle_send_message(Client *client, ...@@ -153,11 +120,13 @@ handle_send_message(Client *client,
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
struct send_message_context context(argv[1], argv[2]); bool sent = false;
const ClientMessage msg(argv[1], argv[2]);
client_list_foreach(send_message, &context); for (const auto &c : *client_list)
if (client_push_message(c, msg))
sent = true;
if (context.sent) if (sent)
return COMMAND_RETURN_OK; return COMMAND_RETURN_OK;
else { else {
command_error(client, ACK_ERROR_NO_EXIST, command_error(client, ACK_ERROR_NO_EXIST,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment