Client: use TimeoutMonitor to track connection timeout
Don't use a global loop over the whole client list.
This commit is contained in:
parent
cab84af72e
commit
b0bbb8b693
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user