aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2008-08-28 20:03:48 +0200
committerMax Kellermann <max@duempel.org>2008-08-28 20:03:48 +0200
commit61443c13e6c443eada93d15d85336ebcfe5ce581 (patch)
tree686081ae46afeebbb01c147441cf3034eb7cb328
parenta091c148e60a13c646ba562a53324604d6ad98b7 (diff)
downloadmpd-61443c13e6c443eada93d15d85336ebcfe5ce581.tar.gz
mpd-61443c13e6c443eada93d15d85336ebcfe5ce581.tar.xz
mpd-61443c13e6c443eada93d15d85336ebcfe5ce581.zip
client: allocate clients dynamically
Due to the large buffers in the client struct, the static client array eats several megabytes of RAM with a maximum of only 10 clients. Stop this waste and allocate each client struct from the heap.
-rw-r--r--src/client.c166
1 files changed, 76 insertions, 90 deletions
diff --git a/src/client.c b/src/client.c
index 9c18ca40e..54867044c 100644
--- a/src/client.c
+++ b/src/client.c
@@ -28,6 +28,7 @@
#include "myfprintf.h"
#include "os_compat.h"
#include "main_notify.h"
+#include "dlist.h"
#include "../config.h"
@@ -60,6 +61,8 @@ static struct strnode *list_cache_head;
static struct strnode *list_cache_tail;
struct client {
+ struct list_head siblings;
+
char buffer[CLIENT_MAX_BUFFER_LENGTH];
size_t bufferLength;
size_t bufferPos;
@@ -83,7 +86,8 @@ struct client {
size_t send_buf_alloc; /* bytes actually allocated */
};
-static struct client *clients;
+static LIST_HEAD(clients);
+static unsigned num_clients;
static void client_write_deferred(struct client *client);
@@ -129,7 +133,7 @@ static void set_send_buf_size(struct client *client)
static void client_init(struct client *client, int fd)
{
- assert(client->fd < 0);
+ static unsigned int next_client_num;
client->cmd_list_size = 0;
client->cmd_list_dup = 0;
@@ -144,6 +148,7 @@ static void client_init(struct client *client, int fd)
client->deferred_send = NULL;
client->expired = 0;
client->deferred_bytes = 0;
+ client->num = next_client_num++;
client->send_buf_used = 0;
client->permission = getDefaultPermissions();
@@ -212,10 +217,15 @@ out:
static void client_close(struct client *client)
{
struct sllnode *buf;
- if (client->fd < 0)
- return;
+
+ assert(client->fd >= 0);
+
xclose(client->fd);
- client->fd = -1;
+
+ assert(num_clients > 0);
+ assert(!list_empty(&clients));
+ list_del(&client->siblings);
+ --num_clients;
if (client->cmd_list) {
free_cmd_list(client->cmd_list);
@@ -231,18 +241,19 @@ static void client_close(struct client *client)
client->deferred_send = NULL;
}
+ if (client->send_buf)
+ free(client->send_buf);
+
SECURE("client %i: closed\n", client->num);
+ free(client);
}
void client_new(int fd, const struct sockaddr *addr)
{
- unsigned int i;
const char *hostname;
+ struct client *client;
- for (i = 0; i < client_max_connections
- && clients[i].fd >= 0; i++) /* nothing */ ;
-
- if (i == client_max_connections) {
+ if (num_clients >= client_max_connections) {
ERROR("Max Connections Reached!\n");
xclose(fd);
return;
@@ -281,8 +292,12 @@ void client_new(int fd, const struct sockaddr *addr)
default:
hostname = "unknown";
}
- SECURE("client %i: opened from %s\n", i, hostname);
- client_init(&(clients[i]), fd);
+
+ client = xcalloc(1, sizeof(*client));
+ list_add(&client->siblings, &clients);
+ ++num_clients;
+ client_init(client, fd);
+ SECURE("client %i: opened from %s\n", client->num, hostname);
}
static int client_process_line(struct client *client)
@@ -424,55 +439,52 @@ static int client_read(struct client *client)
static void client_manager_register_read_fd(fd_set * fds, int *fdmax)
{
- unsigned int i;
+ struct client *client;
FD_ZERO(fds);
addListenSocketsToFdSet(fds, fdmax);
- for (i = 0; i < client_max_connections; i++) {
- if (clients[i].fd >= 0 && !clients[i].expired
- && !clients[i].deferred_send) {
- FD_SET(clients[i].fd, fds);
- if (*fdmax < clients[i].fd)
- *fdmax = clients[i].fd;
+ list_for_each_entry(client, &clients, siblings) {
+ if (!client->expired && !client->deferred_send) {
+ FD_SET(client->fd, fds);
+ if (*fdmax < client->fd)
+ *fdmax = client->fd;
}
}
}
static void client_manager_register_write_fd(fd_set * fds, int *fdmax)
{
- unsigned int i;
+ struct client *client;
FD_ZERO(fds);
- for (i = 0; i < client_max_connections; i++) {
- if (clients[i].fd >= 0 && !clients[i].expired
- && clients[i].deferred_send) {
- FD_SET(clients[i].fd, fds);
- if (*fdmax < clients[i].fd)
- *fdmax = clients[i].fd;
+ list_for_each_entry(client, &clients, siblings) {
+ if (client->fd >= 0 && !client->expired
+ && client->deferred_send) {
+ FD_SET(client->fd, fds);
+ if (*fdmax < client->fd)
+ *fdmax = client->fd;
}
}
}
static void closeNextErroredInterface(void)
{
+ struct client *client, *n;
fd_set fds;
struct timeval tv;
- unsigned int i;
tv.tv_sec = 0;
tv.tv_usec = 0;
- for (i = 0; i < client_max_connections; i++) {
- if (clients[i].fd >= 0) {
- FD_ZERO(&fds);
- FD_SET(clients[i].fd, &fds);
- if (select(clients[i].fd + 1,
- &fds, NULL, NULL, &tv) < 0) {
- client_close(&clients[i]);
- return;
- }
+ list_for_each_entry_safe(client, n, &clients, siblings) {
+ FD_ZERO(&fds);
+ FD_SET(client->fd, &fds);
+ if (select(client->fd + 1,
+ &fds, NULL, NULL, &tv) < 0) {
+ client_close(client);
+ return;
}
}
}
@@ -482,7 +494,7 @@ int client_manager_io(void)
fd_set rfds;
fd_set wfds;
fd_set efds;
- unsigned int i;
+ struct client *client, *n;
int selret;
int fdmax;
@@ -514,19 +526,17 @@ int client_manager_io(void)
getConnections(&rfds);
- for (i = 0; i < client_max_connections; i++) {
- if (clients[i].fd >= 0
- && FD_ISSET(clients[i].fd, &rfds)) {
+ list_for_each_entry_safe(client, n, &clients, siblings) {
+ if (FD_ISSET(client->fd, &rfds)) {
if (COMMAND_RETURN_KILL ==
- client_read(&(clients[i]))) {
+ client_read(client)) {
return COMMAND_RETURN_KILL;
}
- clients[i].lastTime = time(NULL);
+ client->lastTime = time(NULL);
}
- if (clients[i].fd >= 0
- && FD_ISSET(clients[i].fd, &wfds)) {
- client_write_deferred(&clients[i]);
- clients[i].lastTime = time(NULL);
+ if (FD_ISSET(client->fd, &wfds)) {
+ client_write_deferred(client);
+ client->lastTime = time(NULL);
}
}
@@ -538,7 +548,6 @@ int client_manager_io(void)
void client_manager_init(void)
{
- unsigned int i;
char *test;
ConfigParam *param;
@@ -586,31 +595,19 @@ void client_manager_init(void)
client_max_output_buffer_size = tmp * 1024;
}
- clients = xmalloc(sizeof(clients[0]) * client_max_connections);
-
list_cache = xcalloc(client_list_cache_size, sizeof(struct strnode));
list_cache_head = &(list_cache[0]);
list_cache_tail = &(list_cache[client_list_cache_size - 1]);
-
- for (i = 0; i < client_max_connections; i++) {
- clients[i].fd = -1;
- clients[i].send_buf = NULL;
- clients[i].send_buf_size = 0;
- clients[i].send_buf_alloc = 0;
- clients[i].num = i;
- }
}
static void client_close_all(void)
{
- unsigned int i;
+ struct client *client, *n;
+
+ list_for_each_entry_safe(client, n, &clients, siblings)
+ client_close(client);
+ num_clients = 0;
- for (i = 0; i < client_max_connections; i++) {
- if (clients[i].fd >= 0)
- client_close(&(clients[i]));
- if (clients[i].send_buf)
- free(clients[i].send_buf);
- }
free(list_cache);
}
@@ -618,25 +615,21 @@ void client_manager_deinit(void)
{
client_close_all();
- free(clients);
-
client_max_connections = 0;
}
void client_manager_expire(void)
{
- unsigned int i;
-
- for (i = 0; i < client_max_connections; i++) {
- if (clients[i].fd >= 0) {
- if (clients[i].expired) {
- DEBUG("client %i: expired\n", i);
- client_close(&(clients[i]));
- } else if (time(NULL) - clients[i].lastTime >
- client_timeout) {
- DEBUG("client %i: timeout\n", i);
- client_close(&(clients[i]));
- }
+ struct client *client, *n;
+
+ list_for_each_entry_safe(client, n, &clients, siblings) {
+ if (client->expired) {
+ DEBUG("client %i: expired\n", client->num);
+ client_close(client);
+ } else if (time(NULL) - client->lastTime >
+ client_timeout) {
+ DEBUG("client %i: timeout\n", client->num);
+ client_close(client);
}
}
}
@@ -691,17 +684,11 @@ static void client_write_deferred(struct client *client)
static struct client *client_by_fd(int fd)
{
- static unsigned int i;
-
- assert(fd >= 0);
-
- if (i < client_max_connections && clients[i].fd >= 0 &&
- clients[i].fd == fd)
- return &clients[i];
+ struct client *client;
- for (i = 0; i < client_max_connections; i++)
- if (clients[i].fd == fd)
- return &clients[i];
+ list_for_each_entry(client, &clients, siblings)
+ if (client->fd == fd)
+ return client;
return NULL;
}
@@ -745,8 +732,7 @@ static void client_write_output(struct client *client)
ssize_t ret;
struct sllnode *buf;
- if (client->fd < 0 || client->expired ||
- !client->send_buf_used)
+ if (client->expired || !client->send_buf_used)
return;
if ((buf = client->deferred_send)) {