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