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 "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()
|
|||||||
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
|
Close();
|
||||||
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();
|
|
||||||
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)
|
|||||||
client_close_all();
|
client_close_all();
|
||||||
|
|
||||||
client_max_connections = 0;
|
client_max_connections = 0;
|
||||||
|
|
||||||
client_deinit_expire();
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
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:
|
|||||||
/** 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:
|
|||||||
|
|
||||||
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:
|
|||||||
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;
|
|||||||
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";
|
|||||||
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 @@
|
|||||||
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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user