Commit b0bbb8b6 authored by Max Kellermann's avatar Max Kellermann

Client: use TimeoutMonitor to track connection timeout

Don't use a global loop over the whole client list.
parent cab84af7
...@@ -19,9 +19,6 @@ ...@@ -19,9 +19,6 @@
#include "config.h" #include "config.h"
#include "ClientInternal.hxx" #include "ClientInternal.hxx"
#include "ClientList.hxx"
static guint expire_source_id;
void void
Client::SetExpired() Client::SetExpired()
...@@ -29,54 +26,18 @@ Client::SetExpired() ...@@ -29,54 +26,18 @@ Client::SetExpired()
if (IsExpired()) if (IsExpired())
return; return;
client_schedule_expire();
BufferedSocket::Close(); BufferedSocket::Close();
TimeoutMonitor::Schedule(0);
} }
static void bool
client_check_expired_callback(Client *client, G_GNUC_UNUSED gpointer user_data) Client::OnTimeout()
{ {
if (client->IsExpired()) { if (!IsExpired()) {
g_debug("[%u] expired", client->num); assert(!idle_waiting);
client->Close(); g_debug("[%u] timeout", num);
} else if (!client->idle_waiting && /* idle clients
never expire */
(int)g_timer_elapsed(client->last_activity, NULL) >
client_timeout) {
g_debug("[%u] timeout", client->num);
client->Close();
} }
}
static void
client_manager_expire(void)
{
client_list_foreach(client_check_expired_callback, NULL);
}
/** Close();
* An idle event which calls client_manager_expire().
*/
static gboolean
client_manager_expire_event(G_GNUC_UNUSED gpointer data)
{
expire_source_id = 0;
client_manager_expire();
return false; return false;
} }
void
client_schedule_expire(void)
{
if (expire_source_id == 0)
/* delayed deletion */
expire_source_id = g_idle_add(client_manager_expire_event,
NULL);
}
void
client_deinit_expire(void)
{
if (expire_source_id != 0)
g_source_remove(expire_source_id);
}
...@@ -69,6 +69,4 @@ void client_manager_deinit(void) ...@@ -69,6 +69,4 @@ void client_manager_deinit(void)
client_close_all(); client_close_all();
client_max_connections = 0; client_max_connections = 0;
client_deinit_expire();
} }
...@@ -43,7 +43,8 @@ Client::IdleNotify() ...@@ -43,7 +43,8 @@ Client::IdleNotify()
} }
client_puts(this, "OK\n"); client_puts(this, "OK\n");
g_timer_start(last_activity);
TimeoutMonitor::ScheduleSeconds(client_timeout);
} }
void void
...@@ -83,6 +84,9 @@ Client::IdleWait(unsigned flags) ...@@ -83,6 +84,9 @@ Client::IdleWait(unsigned flags)
if (idle_flags & idle_subscriptions) { if (idle_flags & idle_subscriptions) {
IdleNotify(); IdleNotify();
return true; return true;
} else } else {
/* disable timeouts while in "idle" */
TimeoutMonitor::Cancel();
return false; return false;
}
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "ClientMessage.hxx" #include "ClientMessage.hxx"
#include "CommandListBuilder.hxx" #include "CommandListBuilder.hxx"
#include "event/BufferedSocket.hxx" #include "event/BufferedSocket.hxx"
#include "event/TimeoutMonitor.hxx"
#include "command.h" #include "command.h"
#include <set> #include <set>
...@@ -43,7 +44,7 @@ enum { ...@@ -43,7 +44,7 @@ enum {
struct Partition; struct Partition;
class Client final : private BufferedSocket { class Client final : private BufferedSocket, TimeoutMonitor {
public: public:
Partition &partition; Partition &partition;
struct playlist &playlist; struct playlist &playlist;
...@@ -54,11 +55,6 @@ public: ...@@ -54,11 +55,6 @@ public:
/** the uid of the client process, or -1 if unknown */ /** the uid of the client process, or -1 if unknown */
int uid; int uid;
/**
* How long since the last activity from this client?
*/
GTimer *last_activity;
CommandListBuilder cmd_list; CommandListBuilder cmd_list;
unsigned int num; /* client number */ unsigned int num; /* client number */
...@@ -91,7 +87,6 @@ public: ...@@ -91,7 +87,6 @@ public:
Client(EventLoop &loop, Partition &partition, Client(EventLoop &loop, Partition &partition,
int fd, int uid, int num); int fd, int uid, int num);
~Client();
bool IsConnected() const { bool IsConnected() const {
return BufferedSocket::IsDefined(); return BufferedSocket::IsDefined();
...@@ -125,6 +120,9 @@ private: ...@@ -125,6 +120,9 @@ private:
size_t length) override; size_t length) override;
virtual void OnSocketError(GError *error) override; virtual void OnSocketError(GError *error) override;
virtual void OnSocketClosed() override; virtual void OnSocketClosed() override;
/* virtual methods from class TimeoutMonitor */
virtual bool OnTimeout() override;
}; };
extern unsigned int client_max_connections; extern unsigned int client_max_connections;
...@@ -132,19 +130,6 @@ extern int client_timeout; ...@@ -132,19 +130,6 @@ 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;
/**
* Schedule an "expired" check for all clients: permanently delete
* clients which have been set "expired" with client_set_expired().
*/
void
client_schedule_expire(void);
/**
* Removes a scheduled "expired" check.
*/
void
client_deinit_expire(void);
enum command_return enum command_return
client_read(Client *client); client_read(Client *client);
......
...@@ -49,20 +49,16 @@ static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n"; ...@@ -49,20 +49,16 @@ static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
Client::Client(EventLoop &_loop, Partition &_partition, Client::Client(EventLoop &_loop, Partition &_partition,
int _fd, int _uid, int _num) int _fd, int _uid, int _num)
:BufferedSocket(_fd, _loop, 16384, client_max_output_buffer_size), :BufferedSocket(_fd, _loop, 16384, client_max_output_buffer_size),
TimeoutMonitor(_loop),
partition(_partition), partition(_partition),
playlist(partition.playlist), player_control(&partition.pc), playlist(partition.playlist), player_control(&partition.pc),
permission(getDefaultPermissions()), permission(getDefaultPermissions()),
uid(_uid), uid(_uid),
last_activity(g_timer_new()),
num(_num), num(_num),
idle_waiting(false), idle_flags(0), idle_waiting(false), idle_flags(0),
num_subscriptions(0) num_subscriptions(0)
{ {
} TimeoutMonitor::ScheduleSeconds(client_timeout);
Client::~Client()
{
g_timer_destroy(last_activity);
} }
void void
......
...@@ -28,13 +28,13 @@ ...@@ -28,13 +28,13 @@
BufferedSocket::InputResult BufferedSocket::InputResult
Client::OnSocketInput(const void *data, size_t length) Client::OnSocketInput(const void *data, size_t length)
{ {
g_timer_start(last_activity);
const char *p = (const char *)data; const char *p = (const char *)data;
const char *newline = (const char *)memchr(p, '\n', length); const char *newline = (const char *)memchr(p, '\n', length);
if (newline == NULL) if (newline == NULL)
return InputResult::MORE; return InputResult::MORE;
TimeoutMonitor::ScheduleSeconds(client_timeout);
char *line = g_strndup(p, newline - p); char *line = g_strndup(p, newline - p);
BufferedSocket::ConsumeInput(newline + 1 - p); BufferedSocket::ConsumeInput(newline + 1 - p);
......
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