From 779bf2b2d99c6bd468821dd1f177a94300593861 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:02:20 +0200 Subject: imported list.h from the Linux kernel sources linux/list.h is a nice doubly linked list library - it is lightweight and powerful at the same time. It will be useful later, when we begin to allocate client structures dynamically. Import it, and strip out all the stuff which we are not going to use. --- src/Makefile.am | 1 + src/dlist.h | 484 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 485 insertions(+) create mode 100644 src/dlist.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 70306c125..63e17dda3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ mpd_headers = \ inputStream_http_auth.h \ interface.h \ list.h \ + dlist.h \ listen.h \ log.h \ ls.h \ diff --git a/src/dlist.h b/src/dlist.h new file mode 100644 index 000000000..6123d7136 --- /dev/null +++ b/src/dlist.h @@ -0,0 +1,484 @@ +/* the Music Player Daemon (MPD) + * This project's homepage is: http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This source was imported from the Linux kernel. It is licensed + * GPLv2 only. + * + */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +#else +extern void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next); +#endif + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} +#else +extern void list_add(struct list_head *new, struct list_head *head); +#endif + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +#else +extern void list_del(struct list_head *entry); +#endif + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type*)ptr) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +#endif -- cgit v1.2.3 From bd801d6d2ed4b71255dc314f56b8c87220b29853 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:02:43 +0200 Subject: renamed interface.c to client.c I don't believe "interface" is a good name for something like "connection by a client to MPD", let's call it "client". This is the first patch in the series which changes the name, beginning with the file name. --- src/Makefile.am | 4 +- src/client.c | 794 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/client.h | 32 +++ src/directory.c | 2 +- src/interface.c | 794 -------------------------------------------------------- src/interface.h | 32 --- src/listen.c | 2 +- src/main.c | 2 +- src/myfprintf.c | 2 +- 9 files changed, 832 insertions(+), 832 deletions(-) create mode 100644 src/client.c create mode 100644 src/client.h delete mode 100644 src/interface.c delete mode 100644 src/interface.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 63e17dda3..66eea5fff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,7 +49,7 @@ mpd_headers = \ inputStream_file.h \ inputStream_http.h \ inputStream_http_auth.h \ - interface.h \ + client.h \ list.h \ dlist.h \ listen.h \ @@ -112,7 +112,7 @@ mpd_SOURCES = \ inputStream.c \ inputStream_file.c \ inputStream_http.c \ - interface.c \ + client.c \ ioops.c \ list.c \ listen.c \ diff --git a/src/client.c b/src/client.c new file mode 100644 index 000000000..a6ca85497 --- /dev/null +++ b/src/client.c @@ -0,0 +1,794 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) + * This project's homepage is: http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "client.h" +#include "command.h" +#include "conf.h" +#include "log.h" +#include "listen.h" +#include "permission.h" +#include "sllist.h" +#include "utils.h" +#include "ioops.h" +#include "myfprintf.h" +#include "os_compat.h" +#include "main_notify.h" + +#include "../config.h" + +#define GREETING "OK MPD " PROTOCOL_VERSION "\n" + +#define INTERFACE_MAX_BUFFER_LENGTH (40960) +#define INTERFACE_LIST_MODE_BEGIN "command_list_begin" +#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin" +#define INTERFACE_LIST_MODE_END "command_list_end" +#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE (4096) +#define INTERFACE_TIMEOUT_DEFAULT (60) +#define INTERFACE_MAX_CONNECTIONS_DEFAULT (10) +#define INTERFACE_MAX_COMMAND_LIST_DEFAULT (2048*1024) +#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024) + +/* set this to zero to indicate we have no possible interfaces */ +static unsigned int interface_max_connections; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */ +static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT; +static size_t interface_max_command_list_size = + INTERFACE_MAX_COMMAND_LIST_DEFAULT; +static size_t interface_max_output_buffer_size = + INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT; + +/* maybe make conf option for this, or... 32 might be good enough */ +static long int interface_list_cache_size = 32; + +/* shared globally between all interfaces: */ +static struct strnode *list_cache; +static struct strnode *list_cache_head; +static struct strnode *list_cache_tail; + +typedef struct _Interface { + char buffer[INTERFACE_MAX_BUFFER_LENGTH]; + size_t bufferLength; + size_t bufferPos; + int fd; /* file descriptor */ + int permission; + time_t lastTime; + struct strnode *cmd_list; /* for when in list mode */ + struct strnode *cmd_list_tail; /* for when in list mode */ + int cmd_list_OK; /* print OK after each command execution */ + size_t cmd_list_size; /* mem cmd_list consumes */ + int cmd_list_dup; /* has the cmd_list been copied to private space? */ + struct sllnode *deferred_send; /* for output if client is slow */ + size_t deferred_bytes; /* mem deferred_send consumes */ + int expired; /* set whether this interface should be closed on next + check of old interfaces */ + unsigned int num; /* interface number */ + + char *send_buf; + size_t send_buf_used; /* bytes used this instance */ + size_t send_buf_size; /* bytes usable this instance */ + size_t send_buf_alloc; /* bytes actually allocated */ +} Interface; + +static Interface *interfaces; + +static void flushInterfaceBuffer(Interface * interface); + +static void printInterfaceOutBuffer(Interface * interface); + +#ifdef SO_SNDBUF +static size_t get_default_snd_buf_size(Interface * interface) +{ + int new_size; + socklen_t sockOptLen = sizeof(int); + + if (getsockopt(interface->fd, SOL_SOCKET, SO_SNDBUF, + (char *)&new_size, &sockOptLen) < 0) { + DEBUG("problem getting sockets send buffer size\n"); + return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; + } + if (new_size > 0) + return (size_t)new_size; + DEBUG("sockets send buffer size is not positive\n"); + return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; +} +#else /* !SO_SNDBUF */ +static size_t get_default_snd_buf_size(Interface * interface) +{ + return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; +} +#endif /* !SO_SNDBUF */ + +static void set_send_buf_size(Interface * interface) +{ + size_t new_size = get_default_snd_buf_size(interface); + if (interface->send_buf_size != new_size) { + interface->send_buf_size = new_size; + /* don't resize to get smaller, only bigger */ + if (interface->send_buf_alloc < new_size) { + if (interface->send_buf) + free(interface->send_buf); + interface->send_buf = xmalloc(new_size); + interface->send_buf_alloc = new_size; + } + } +} + +static void openInterface(Interface * interface, int fd) +{ + assert(interface->fd < 0); + + interface->cmd_list_size = 0; + interface->cmd_list_dup = 0; + interface->cmd_list_OK = -1; + interface->bufferLength = 0; + interface->bufferPos = 0; + interface->fd = fd; + set_nonblocking(fd); + interface->lastTime = time(NULL); + interface->cmd_list = NULL; + interface->cmd_list_tail = NULL; + interface->deferred_send = NULL; + interface->expired = 0; + interface->deferred_bytes = 0; + interface->send_buf_used = 0; + + interface->permission = getDefaultPermissions(); + set_send_buf_size(interface); + + xwrite(fd, GREETING, strlen(GREETING)); +} + +static void free_cmd_list(struct strnode *list) +{ + struct strnode *tmp = list; + + while (tmp) { + struct strnode *next = tmp->next; + if (tmp >= list_cache_head && tmp <= list_cache_tail) { + /* inside list_cache[] array */ + tmp->data = NULL; + tmp->next = NULL; + } else + free(tmp); + tmp = next; + } +} + +static void cmd_list_clone(Interface * interface) +{ + struct strnode *new = dup_strlist(interface->cmd_list); + free_cmd_list(interface->cmd_list); + interface->cmd_list = new; + interface->cmd_list_dup = 1; + + /* new tail */ + while (new && new->next) + new = new->next; + interface->cmd_list_tail = new; +} + +static void new_cmd_list_ptr(Interface * interface, char *s, const int size) +{ + int i; + struct strnode *new; + + if (!interface->cmd_list_dup) { + for (i = interface_list_cache_size - 1; i >= 0; --i) { + if (list_cache[i].data) + continue; + new = &(list_cache[i]); + new->data = s; + /* implied in free_cmd_list() and init: */ + /* last->next->next = NULL; */ + goto out; + } + } + + /* allocate from the heap */ + new = interface->cmd_list_dup ? new_strnode_dup(s, size) + : new_strnode(s); +out: + if (interface->cmd_list) { + interface->cmd_list_tail->next = new; + interface->cmd_list_tail = new; + } else + interface->cmd_list = interface->cmd_list_tail = new; +} + +static void closeInterface(Interface * interface) +{ + struct sllnode *buf; + if (interface->fd < 0) + return; + xclose(interface->fd); + interface->fd = -1; + + if (interface->cmd_list) { + free_cmd_list(interface->cmd_list); + interface->cmd_list = NULL; + } + + if ((buf = interface->deferred_send)) { + do { + struct sllnode *prev = buf; + buf = buf->next; + free(prev); + } while (buf); + interface->deferred_send = NULL; + } + + SECURE("interface %i: closed\n", interface->num); +} + +void openAInterface(int fd, const struct sockaddr *addr) +{ + unsigned int i; + + for (i = 0; i < interface_max_connections + && interfaces[i].fd >= 0; i++) /* nothing */ ; + + if (i == interface_max_connections) { + ERROR("Max Connections Reached!\n"); + xclose(fd); + } else { + const char *hostname; + switch (addr->sa_family) { +#ifdef HAVE_TCP + case AF_INET: + hostname = (const char *)inet_ntoa(((const struct sockaddr_in *) + addr)->sin_addr); + if (!hostname) + hostname = "error getting ipv4 address"; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + { + static char host[INET6_ADDRSTRLEN + 1]; + memset(host, 0, INET6_ADDRSTRLEN + 1); + if (inet_ntop(AF_INET6, (const void *) + &(((const struct sockaddr_in6 *)addr)-> + sin6_addr), host, + INET6_ADDRSTRLEN)) { + hostname = (const char *)host; + } else { + hostname = "error getting ipv6 address"; + } + } + break; +#endif +#endif /* HAVE_TCP */ +#ifdef HAVE_UN + case AF_UNIX: + hostname = "local connection"; + break; +#endif /* HAVE_UN */ + default: + hostname = "unknown"; + } + SECURE("interface %i: opened from %s\n", i, hostname); + openInterface(&(interfaces[i]), fd); + } +} + +static int processLineOfInput(Interface * interface) +{ + int ret = 1; + char *line = interface->buffer + interface->bufferPos; + + if (interface->cmd_list_OK >= 0) { + if (strcmp(line, INTERFACE_LIST_MODE_END) == 0) { + DEBUG("interface %i: process command " + "list\n", interface->num); + ret = processListOfCommands(interface->fd, + &(interface->permission), + &(interface->expired), + interface->cmd_list_OK, + interface->cmd_list); + DEBUG("interface %i: process command " + "list returned %i\n", interface->num, ret); + if (ret == 0) + commandSuccess(interface->fd); + else if (ret == COMMAND_RETURN_CLOSE + || interface->expired) + closeInterface(interface); + + printInterfaceOutBuffer(interface); + free_cmd_list(interface->cmd_list); + interface->cmd_list = NULL; + interface->cmd_list_OK = -1; + } else { + size_t len = strlen(line) + 1; + interface->cmd_list_size += len; + if (interface->cmd_list_size > + interface_max_command_list_size) { + ERROR("interface %i: command " + "list size (%lu) is " + "larger than the max " + "(%lu)\n", + interface->num, + (unsigned long)interface->cmd_list_size, + (unsigned long) + interface_max_command_list_size); + closeInterface(interface); + ret = COMMAND_RETURN_CLOSE; + } else + new_cmd_list_ptr(interface, line, len); + } + } else { + if (strcmp(line, INTERFACE_LIST_MODE_BEGIN) == 0) { + interface->cmd_list_OK = 0; + ret = 1; + } else if (strcmp(line, INTERFACE_LIST_OK_MODE_BEGIN) == 0) { + interface->cmd_list_OK = 1; + ret = 1; + } else { + DEBUG("interface %i: process command \"%s\"\n", + interface->num, line); + ret = processCommand(interface->fd, + &(interface->permission), line); + DEBUG("interface %i: command returned %i\n", + interface->num, ret); + if (ret == 0) + commandSuccess(interface->fd); + else if (ret == COMMAND_RETURN_CLOSE + || interface->expired) { + closeInterface(interface); + } + printInterfaceOutBuffer(interface); + } + } + + return ret; +} + +static int processBytesRead(Interface * interface, int bytesRead) +{ + int ret = 0; + char *buf_tail = &(interface->buffer[interface->bufferLength - 1]); + + while (bytesRead > 0) { + interface->bufferLength++; + bytesRead--; + buf_tail++; + if (*buf_tail == '\n') { + *buf_tail = '\0'; + if (interface->bufferLength > interface->bufferPos) { + if (*(buf_tail - 1) == '\r') + *(buf_tail - 1) = '\0'; + } + ret = processLineOfInput(interface); + if (interface->expired) + return ret; + interface->bufferPos = interface->bufferLength; + } + if (interface->bufferLength == INTERFACE_MAX_BUFFER_LENGTH) { + if (interface->bufferPos == 0) { + ERROR("interface %i: buffer overflow\n", + interface->num); + closeInterface(interface); + return 1; + } + if (interface->cmd_list_OK >= 0 && + interface->cmd_list && + !interface->cmd_list_dup) + cmd_list_clone(interface); + assert(interface->bufferLength >= interface->bufferPos + && "bufferLength >= bufferPos"); + interface->bufferLength -= interface->bufferPos; + memmove(interface->buffer, + interface->buffer + interface->bufferPos, + interface->bufferLength); + interface->bufferPos = 0; + } + if (ret == COMMAND_RETURN_KILL || ret == COMMAND_RETURN_CLOSE) { + return ret; + } + + } + + return ret; +} + +static int interfaceReadInput(Interface * interface) +{ + int bytesRead; + + bytesRead = read(interface->fd, + interface->buffer + interface->bufferLength, + INTERFACE_MAX_BUFFER_LENGTH - interface->bufferLength); + + if (bytesRead > 0) + return processBytesRead(interface, bytesRead); + else if (bytesRead == 0 || (bytesRead < 0 && errno != EINTR)) { + closeInterface(interface); + } else + return 0; + + return 1; +} + +static void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds, + int *fdmax) +{ + unsigned int i; + + FD_ZERO(fds); + addListenSocketsToFdSet(fds, fdmax); + + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd >= 0 && !interfaces[i].expired + && !interfaces[i].deferred_send) { + FD_SET(interfaces[i].fd, fds); + if (*fdmax < interfaces[i].fd) + *fdmax = interfaces[i].fd; + } + } +} + +static void addInterfacesForBufferFlushToFdSet(fd_set * fds, int *fdmax) +{ + unsigned int i; + + FD_ZERO(fds); + + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd >= 0 && !interfaces[i].expired + && interfaces[i].deferred_send) { + FD_SET(interfaces[i].fd, fds); + if (*fdmax < interfaces[i].fd) + *fdmax = interfaces[i].fd; + } + } +} + +static void closeNextErroredInterface(void) +{ + fd_set fds; + struct timeval tv; + unsigned int i; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd >= 0) { + FD_ZERO(&fds); + FD_SET(interfaces[i].fd, &fds); + if (select(interfaces[i].fd + 1, + &fds, NULL, NULL, &tv) < 0) { + closeInterface(&interfaces[i]); + return; + } + } + } +} + +int doIOForInterfaces(void) +{ + fd_set rfds; + fd_set wfds; + fd_set efds; + unsigned int i; + int selret; + int fdmax; + + while (1) { + fdmax = 0; + + FD_ZERO( &efds ); + addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax); + addInterfacesForBufferFlushToFdSet(&wfds, &fdmax); + + registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); + + selret = select(fdmax + 1, &rfds, &wfds, &efds, NULL); + if (selret < 0 && errno == EINTR) + break; + + registered_IO_consume_fds(&selret, &rfds, &wfds, &efds); + + if (selret == 0) + break; + + if (selret < 0) { + closeNextErroredInterface(); + continue; + } + + getConnections(&rfds); + + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd >= 0 + && FD_ISSET(interfaces[i].fd, &rfds)) { + if (COMMAND_RETURN_KILL == + interfaceReadInput(&(interfaces[i]))) { + return COMMAND_RETURN_KILL; + } + interfaces[i].lastTime = time(NULL); + } + if (interfaces[i].fd >= 0 + && FD_ISSET(interfaces[i].fd, &wfds)) { + flushInterfaceBuffer(&interfaces[i]); + interfaces[i].lastTime = time(NULL); + } + } + + break; + } + + return 1; +} + +void initInterfaces(void) +{ + unsigned int i; + char *test; + ConfigParam *param; + + param = getConfigParam(CONF_CONN_TIMEOUT); + + if (param) { + interface_timeout = strtol(param->value, &test, 10); + if (*test != '\0' || interface_timeout <= 0) { + FATAL("connection timeout \"%s\" is not a positive " + "integer, line %i\n", CONF_CONN_TIMEOUT, + param->line); + } + } + + param = getConfigParam(CONF_MAX_CONN); + + if (param) { + interface_max_connections = strtol(param->value, &test, 10); + if (*test != '\0' || interface_max_connections <= 0) { + FATAL("max connections \"%s\" is not a positive integer" + ", line %i\n", param->value, param->line); + } + } else + interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT; + + param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE); + + if (param) { + long tmp = strtol(param->value, &test, 10); + if (*test != '\0' || tmp <= 0) { + FATAL("max command list size \"%s\" is not a positive " + "integer, line %i\n", param->value, param->line); + } + interface_max_command_list_size = tmp * 1024; + } + + param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE); + + if (param) { + long tmp = strtol(param->value, &test, 10); + if (*test != '\0' || tmp <= 0) { + FATAL("max output buffer size \"%s\" is not a positive " + "integer, line %i\n", param->value, param->line); + } + interface_max_output_buffer_size = tmp * 1024; + } + + interfaces = xmalloc(sizeof(Interface) * interface_max_connections); + + list_cache = xcalloc(interface_list_cache_size, sizeof(struct strnode)); + list_cache_head = &(list_cache[0]); + list_cache_tail = &(list_cache[interface_list_cache_size - 1]); + + for (i = 0; i < interface_max_connections; i++) { + interfaces[i].fd = -1; + interfaces[i].send_buf = NULL; + interfaces[i].send_buf_size = 0; + interfaces[i].send_buf_alloc = 0; + interfaces[i].num = i; + } +} + +static void closeAllInterfaces(void) +{ + unsigned int i; + + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd >= 0) + closeInterface(&(interfaces[i])); + if (interfaces[i].send_buf) + free(interfaces[i].send_buf); + } + free(list_cache); +} + +void freeAllInterfaces(void) +{ + closeAllInterfaces(); + + free(interfaces); + + interface_max_connections = 0; +} + +void closeOldInterfaces(void) +{ + unsigned int i; + + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd >= 0) { + if (interfaces[i].expired) { + DEBUG("interface %i: expired\n", i); + closeInterface(&(interfaces[i])); + } else if (time(NULL) - interfaces[i].lastTime > + interface_timeout) { + DEBUG("interface %i: timeout\n", i); + closeInterface(&(interfaces[i])); + } + } + } +} + +static void flushInterfaceBuffer(Interface * interface) +{ + struct sllnode *buf; + ssize_t ret = 0; + + buf = interface->deferred_send; + while (buf) { + ret = write(interface->fd, buf->data, buf->size); + if (ret < 0) + break; + else if ((size_t)ret < buf->size) { + assert(interface->deferred_bytes >= (size_t)ret); + interface->deferred_bytes -= ret; + buf->data = (char *)buf->data + ret; + buf->size -= ret; + } else { + struct sllnode *tmp = buf; + size_t decr = (buf->size + sizeof(struct sllnode)); + + assert(interface->deferred_bytes >= decr); + interface->deferred_bytes -= decr; + buf = buf->next; + free(tmp); + interface->deferred_send = buf; + } + interface->lastTime = time(NULL); + } + + if (!interface->deferred_send) { + DEBUG("interface %i: buffer empty %lu\n", interface->num, + (unsigned long)interface->deferred_bytes); + assert(interface->deferred_bytes == 0); + } else if (ret < 0 && errno != EAGAIN && errno != EINTR) { + /* cause interface to close */ + DEBUG("interface %i: problems flushing buffer\n", + interface->num); + buf = interface->deferred_send; + do { + struct sllnode *prev = buf; + buf = buf->next; + free(prev); + } while (buf); + interface->deferred_send = NULL; + interface->deferred_bytes = 0; + interface->expired = 1; + } +} + +int interfacePrintWithFD(int fd, const char *buffer, size_t buflen) +{ + static unsigned int i; + size_t copylen; + Interface *interface; + + assert(fd >= 0); + + if (i >= interface_max_connections || + interfaces[i].fd < 0 || interfaces[i].fd != fd) { + for (i = 0; i < interface_max_connections; i++) { + if (interfaces[i].fd == fd) + break; + } + if (i == interface_max_connections) + return -1; + } + + /* if fd isn't found or interfaces is going to be closed, do nothing */ + if (interfaces[i].expired) + return 0; + + interface = interfaces + i; + + while (buflen > 0 && !interface->expired) { + size_t left; + + assert(interface->send_buf_size >= interface->send_buf_used); + left = interface->send_buf_size - interface->send_buf_used; + + copylen = buflen > left ? left : buflen; + memcpy(interface->send_buf + interface->send_buf_used, buffer, + copylen); + buflen -= copylen; + interface->send_buf_used += copylen; + buffer += copylen; + if (interface->send_buf_used >= interface->send_buf_size) + printInterfaceOutBuffer(interface); + } + + return 0; +} + +static void printInterfaceOutBuffer(Interface * interface) +{ + ssize_t ret; + struct sllnode *buf; + + if (interface->fd < 0 || interface->expired || + !interface->send_buf_used) + return; + + if ((buf = interface->deferred_send)) { + interface->deferred_bytes += sizeof(struct sllnode) + + interface->send_buf_used; + if (interface->deferred_bytes > + interface_max_output_buffer_size) { + ERROR("interface %i: output buffer size (%lu) is " + "larger than the max (%lu)\n", + interface->num, + (unsigned long)interface->deferred_bytes, + (unsigned long)interface_max_output_buffer_size); + /* cause interface to close */ + interface->expired = 1; + do { + struct sllnode *prev = buf; + buf = buf->next; + free(prev); + } while (buf); + interface->deferred_send = NULL; + interface->deferred_bytes = 0; + } else { + while (buf->next) + buf = buf->next; + buf->next = new_sllnode(interface->send_buf, + interface->send_buf_used); + } + } else { + if ((ret = write(interface->fd, interface->send_buf, + interface->send_buf_used)) < 0) { + if (errno == EAGAIN || errno == EINTR) { + interface->deferred_send = + new_sllnode(interface->send_buf, + interface->send_buf_used); + } else { + DEBUG("interface %i: problems writing\n", + interface->num); + interface->expired = 1; + return; + } + } else if ((size_t)ret < interface->send_buf_used) { + interface->deferred_send = + new_sllnode(interface->send_buf + ret, + interface->send_buf_used - ret); + } + if (interface->deferred_send) { + DEBUG("interface %i: buffer created\n", interface->num); + interface->deferred_bytes = + interface->deferred_send->size + + sizeof(struct sllnode); + } + } + + interface->send_buf_used = 0; +} + diff --git a/src/client.h b/src/client.h new file mode 100644 index 000000000..c83381319 --- /dev/null +++ b/src/client.h @@ -0,0 +1,32 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) + * This project's homepage is: http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef INTERFACE_H +#define INTERFACE_H + +#include "os_compat.h" + +void initInterfaces(void); +void openAInterface(int fd, const struct sockaddr *addr); +void freeAllInterfaces(void); +void closeOldInterfaces(void); +int interfacePrintWithFD(int fd, const char *buffer, size_t len); + +int doIOForInterfaces(void); + +#endif diff --git a/src/directory.c b/src/directory.c index 94a55d664..6f3409356 100644 --- a/src/directory.c +++ b/src/directory.c @@ -20,7 +20,7 @@ #include "command.h" #include "conf.h" -#include "interface.h" +#include "client.h" #include "listen.h" #include "log.h" #include "ls.h" diff --git a/src/interface.c b/src/interface.c deleted file mode 100644 index 83e0084b5..000000000 --- a/src/interface.c +++ /dev/null @@ -1,794 +0,0 @@ -/* the Music Player Daemon (MPD) - * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) - * This project's homepage is: http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "interface.h" -#include "command.h" -#include "conf.h" -#include "log.h" -#include "listen.h" -#include "permission.h" -#include "sllist.h" -#include "utils.h" -#include "ioops.h" -#include "myfprintf.h" -#include "os_compat.h" -#include "main_notify.h" - -#include "../config.h" - -#define GREETING "OK MPD " PROTOCOL_VERSION "\n" - -#define INTERFACE_MAX_BUFFER_LENGTH (40960) -#define INTERFACE_LIST_MODE_BEGIN "command_list_begin" -#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin" -#define INTERFACE_LIST_MODE_END "command_list_end" -#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE (4096) -#define INTERFACE_TIMEOUT_DEFAULT (60) -#define INTERFACE_MAX_CONNECTIONS_DEFAULT (10) -#define INTERFACE_MAX_COMMAND_LIST_DEFAULT (2048*1024) -#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024) - -/* set this to zero to indicate we have no possible interfaces */ -static unsigned int interface_max_connections; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */ -static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT; -static size_t interface_max_command_list_size = - INTERFACE_MAX_COMMAND_LIST_DEFAULT; -static size_t interface_max_output_buffer_size = - INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT; - -/* maybe make conf option for this, or... 32 might be good enough */ -static long int interface_list_cache_size = 32; - -/* shared globally between all interfaces: */ -static struct strnode *list_cache; -static struct strnode *list_cache_head; -static struct strnode *list_cache_tail; - -typedef struct _Interface { - char buffer[INTERFACE_MAX_BUFFER_LENGTH]; - size_t bufferLength; - size_t bufferPos; - int fd; /* file descriptor */ - int permission; - time_t lastTime; - struct strnode *cmd_list; /* for when in list mode */ - struct strnode *cmd_list_tail; /* for when in list mode */ - int cmd_list_OK; /* print OK after each command execution */ - size_t cmd_list_size; /* mem cmd_list consumes */ - int cmd_list_dup; /* has the cmd_list been copied to private space? */ - struct sllnode *deferred_send; /* for output if client is slow */ - size_t deferred_bytes; /* mem deferred_send consumes */ - int expired; /* set whether this interface should be closed on next - check of old interfaces */ - unsigned int num; /* interface number */ - - char *send_buf; - size_t send_buf_used; /* bytes used this instance */ - size_t send_buf_size; /* bytes usable this instance */ - size_t send_buf_alloc; /* bytes actually allocated */ -} Interface; - -static Interface *interfaces; - -static void flushInterfaceBuffer(Interface * interface); - -static void printInterfaceOutBuffer(Interface * interface); - -#ifdef SO_SNDBUF -static size_t get_default_snd_buf_size(Interface * interface) -{ - int new_size; - socklen_t sockOptLen = sizeof(int); - - if (getsockopt(interface->fd, SOL_SOCKET, SO_SNDBUF, - (char *)&new_size, &sockOptLen) < 0) { - DEBUG("problem getting sockets send buffer size\n"); - return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; - } - if (new_size > 0) - return (size_t)new_size; - DEBUG("sockets send buffer size is not positive\n"); - return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; -} -#else /* !SO_SNDBUF */ -static size_t get_default_snd_buf_size(Interface * interface) -{ - return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; -} -#endif /* !SO_SNDBUF */ - -static void set_send_buf_size(Interface * interface) -{ - size_t new_size = get_default_snd_buf_size(interface); - if (interface->send_buf_size != new_size) { - interface->send_buf_size = new_size; - /* don't resize to get smaller, only bigger */ - if (interface->send_buf_alloc < new_size) { - if (interface->send_buf) - free(interface->send_buf); - interface->send_buf = xmalloc(new_size); - interface->send_buf_alloc = new_size; - } - } -} - -static void openInterface(Interface * interface, int fd) -{ - assert(interface->fd < 0); - - interface->cmd_list_size = 0; - interface->cmd_list_dup = 0; - interface->cmd_list_OK = -1; - interface->bufferLength = 0; - interface->bufferPos = 0; - interface->fd = fd; - set_nonblocking(fd); - interface->lastTime = time(NULL); - interface->cmd_list = NULL; - interface->cmd_list_tail = NULL; - interface->deferred_send = NULL; - interface->expired = 0; - interface->deferred_bytes = 0; - interface->send_buf_used = 0; - - interface->permission = getDefaultPermissions(); - set_send_buf_size(interface); - - xwrite(fd, GREETING, strlen(GREETING)); -} - -static void free_cmd_list(struct strnode *list) -{ - struct strnode *tmp = list; - - while (tmp) { - struct strnode *next = tmp->next; - if (tmp >= list_cache_head && tmp <= list_cache_tail) { - /* inside list_cache[] array */ - tmp->data = NULL; - tmp->next = NULL; - } else - free(tmp); - tmp = next; - } -} - -static void cmd_list_clone(Interface * interface) -{ - struct strnode *new = dup_strlist(interface->cmd_list); - free_cmd_list(interface->cmd_list); - interface->cmd_list = new; - interface->cmd_list_dup = 1; - - /* new tail */ - while (new && new->next) - new = new->next; - interface->cmd_list_tail = new; -} - -static void new_cmd_list_ptr(Interface * interface, char *s, const int size) -{ - int i; - struct strnode *new; - - if (!interface->cmd_list_dup) { - for (i = interface_list_cache_size - 1; i >= 0; --i) { - if (list_cache[i].data) - continue; - new = &(list_cache[i]); - new->data = s; - /* implied in free_cmd_list() and init: */ - /* last->next->next = NULL; */ - goto out; - } - } - - /* allocate from the heap */ - new = interface->cmd_list_dup ? new_strnode_dup(s, size) - : new_strnode(s); -out: - if (interface->cmd_list) { - interface->cmd_list_tail->next = new; - interface->cmd_list_tail = new; - } else - interface->cmd_list = interface->cmd_list_tail = new; -} - -static void closeInterface(Interface * interface) -{ - struct sllnode *buf; - if (interface->fd < 0) - return; - xclose(interface->fd); - interface->fd = -1; - - if (interface->cmd_list) { - free_cmd_list(interface->cmd_list); - interface->cmd_list = NULL; - } - - if ((buf = interface->deferred_send)) { - do { - struct sllnode *prev = buf; - buf = buf->next; - free(prev); - } while (buf); - interface->deferred_send = NULL; - } - - SECURE("interface %i: closed\n", interface->num); -} - -void openAInterface(int fd, const struct sockaddr *addr) -{ - unsigned int i; - - for (i = 0; i < interface_max_connections - && interfaces[i].fd >= 0; i++) /* nothing */ ; - - if (i == interface_max_connections) { - ERROR("Max Connections Reached!\n"); - xclose(fd); - } else { - const char *hostname; - switch (addr->sa_family) { -#ifdef HAVE_TCP - case AF_INET: - hostname = (const char *)inet_ntoa(((const struct sockaddr_in *) - addr)->sin_addr); - if (!hostname) - hostname = "error getting ipv4 address"; - break; -#ifdef HAVE_IPV6 - case AF_INET6: - { - static char host[INET6_ADDRSTRLEN + 1]; - memset(host, 0, INET6_ADDRSTRLEN + 1); - if (inet_ntop(AF_INET6, (const void *) - &(((const struct sockaddr_in6 *)addr)-> - sin6_addr), host, - INET6_ADDRSTRLEN)) { - hostname = (const char *)host; - } else { - hostname = "error getting ipv6 address"; - } - } - break; -#endif -#endif /* HAVE_TCP */ -#ifdef HAVE_UN - case AF_UNIX: - hostname = "local connection"; - break; -#endif /* HAVE_UN */ - default: - hostname = "unknown"; - } - SECURE("interface %i: opened from %s\n", i, hostname); - openInterface(&(interfaces[i]), fd); - } -} - -static int processLineOfInput(Interface * interface) -{ - int ret = 1; - char *line = interface->buffer + interface->bufferPos; - - if (interface->cmd_list_OK >= 0) { - if (strcmp(line, INTERFACE_LIST_MODE_END) == 0) { - DEBUG("interface %i: process command " - "list\n", interface->num); - ret = processListOfCommands(interface->fd, - &(interface->permission), - &(interface->expired), - interface->cmd_list_OK, - interface->cmd_list); - DEBUG("interface %i: process command " - "list returned %i\n", interface->num, ret); - if (ret == 0) - commandSuccess(interface->fd); - else if (ret == COMMAND_RETURN_CLOSE - || interface->expired) - closeInterface(interface); - - printInterfaceOutBuffer(interface); - free_cmd_list(interface->cmd_list); - interface->cmd_list = NULL; - interface->cmd_list_OK = -1; - } else { - size_t len = strlen(line) + 1; - interface->cmd_list_size += len; - if (interface->cmd_list_size > - interface_max_command_list_size) { - ERROR("interface %i: command " - "list size (%lu) is " - "larger than the max " - "(%lu)\n", - interface->num, - (unsigned long)interface->cmd_list_size, - (unsigned long) - interface_max_command_list_size); - closeInterface(interface); - ret = COMMAND_RETURN_CLOSE; - } else - new_cmd_list_ptr(interface, line, len); - } - } else { - if (strcmp(line, INTERFACE_LIST_MODE_BEGIN) == 0) { - interface->cmd_list_OK = 0; - ret = 1; - } else if (strcmp(line, INTERFACE_LIST_OK_MODE_BEGIN) == 0) { - interface->cmd_list_OK = 1; - ret = 1; - } else { - DEBUG("interface %i: process command \"%s\"\n", - interface->num, line); - ret = processCommand(interface->fd, - &(interface->permission), line); - DEBUG("interface %i: command returned %i\n", - interface->num, ret); - if (ret == 0) - commandSuccess(interface->fd); - else if (ret == COMMAND_RETURN_CLOSE - || interface->expired) { - closeInterface(interface); - } - printInterfaceOutBuffer(interface); - } - } - - return ret; -} - -static int processBytesRead(Interface * interface, int bytesRead) -{ - int ret = 0; - char *buf_tail = &(interface->buffer[interface->bufferLength - 1]); - - while (bytesRead > 0) { - interface->bufferLength++; - bytesRead--; - buf_tail++; - if (*buf_tail == '\n') { - *buf_tail = '\0'; - if (interface->bufferLength > interface->bufferPos) { - if (*(buf_tail - 1) == '\r') - *(buf_tail - 1) = '\0'; - } - ret = processLineOfInput(interface); - if (interface->expired) - return ret; - interface->bufferPos = interface->bufferLength; - } - if (interface->bufferLength == INTERFACE_MAX_BUFFER_LENGTH) { - if (interface->bufferPos == 0) { - ERROR("interface %i: buffer overflow\n", - interface->num); - closeInterface(interface); - return 1; - } - if (interface->cmd_list_OK >= 0 && - interface->cmd_list && - !interface->cmd_list_dup) - cmd_list_clone(interface); - assert(interface->bufferLength >= interface->bufferPos - && "bufferLength >= bufferPos"); - interface->bufferLength -= interface->bufferPos; - memmove(interface->buffer, - interface->buffer + interface->bufferPos, - interface->bufferLength); - interface->bufferPos = 0; - } - if (ret == COMMAND_RETURN_KILL || ret == COMMAND_RETURN_CLOSE) { - return ret; - } - - } - - return ret; -} - -static int interfaceReadInput(Interface * interface) -{ - int bytesRead; - - bytesRead = read(interface->fd, - interface->buffer + interface->bufferLength, - INTERFACE_MAX_BUFFER_LENGTH - interface->bufferLength); - - if (bytesRead > 0) - return processBytesRead(interface, bytesRead); - else if (bytesRead == 0 || (bytesRead < 0 && errno != EINTR)) { - closeInterface(interface); - } else - return 0; - - return 1; -} - -static void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds, - int *fdmax) -{ - unsigned int i; - - FD_ZERO(fds); - addListenSocketsToFdSet(fds, fdmax); - - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0 && !interfaces[i].expired - && !interfaces[i].deferred_send) { - FD_SET(interfaces[i].fd, fds); - if (*fdmax < interfaces[i].fd) - *fdmax = interfaces[i].fd; - } - } -} - -static void addInterfacesForBufferFlushToFdSet(fd_set * fds, int *fdmax) -{ - unsigned int i; - - FD_ZERO(fds); - - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0 && !interfaces[i].expired - && interfaces[i].deferred_send) { - FD_SET(interfaces[i].fd, fds); - if (*fdmax < interfaces[i].fd) - *fdmax = interfaces[i].fd; - } - } -} - -static void closeNextErroredInterface(void) -{ - fd_set fds; - struct timeval tv; - unsigned int i; - - tv.tv_sec = 0; - tv.tv_usec = 0; - - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0) { - FD_ZERO(&fds); - FD_SET(interfaces[i].fd, &fds); - if (select(interfaces[i].fd + 1, - &fds, NULL, NULL, &tv) < 0) { - closeInterface(&interfaces[i]); - return; - } - } - } -} - -int doIOForInterfaces(void) -{ - fd_set rfds; - fd_set wfds; - fd_set efds; - unsigned int i; - int selret; - int fdmax; - - while (1) { - fdmax = 0; - - FD_ZERO( &efds ); - addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax); - addInterfacesForBufferFlushToFdSet(&wfds, &fdmax); - - registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); - - selret = select(fdmax + 1, &rfds, &wfds, &efds, NULL); - if (selret < 0 && errno == EINTR) - break; - - registered_IO_consume_fds(&selret, &rfds, &wfds, &efds); - - if (selret == 0) - break; - - if (selret < 0) { - closeNextErroredInterface(); - continue; - } - - getConnections(&rfds); - - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0 - && FD_ISSET(interfaces[i].fd, &rfds)) { - if (COMMAND_RETURN_KILL == - interfaceReadInput(&(interfaces[i]))) { - return COMMAND_RETURN_KILL; - } - interfaces[i].lastTime = time(NULL); - } - if (interfaces[i].fd >= 0 - && FD_ISSET(interfaces[i].fd, &wfds)) { - flushInterfaceBuffer(&interfaces[i]); - interfaces[i].lastTime = time(NULL); - } - } - - break; - } - - return 1; -} - -void initInterfaces(void) -{ - unsigned int i; - char *test; - ConfigParam *param; - - param = getConfigParam(CONF_CONN_TIMEOUT); - - if (param) { - interface_timeout = strtol(param->value, &test, 10); - if (*test != '\0' || interface_timeout <= 0) { - FATAL("connection timeout \"%s\" is not a positive " - "integer, line %i\n", CONF_CONN_TIMEOUT, - param->line); - } - } - - param = getConfigParam(CONF_MAX_CONN); - - if (param) { - interface_max_connections = strtol(param->value, &test, 10); - if (*test != '\0' || interface_max_connections <= 0) { - FATAL("max connections \"%s\" is not a positive integer" - ", line %i\n", param->value, param->line); - } - } else - interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT; - - param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE); - - if (param) { - long tmp = strtol(param->value, &test, 10); - if (*test != '\0' || tmp <= 0) { - FATAL("max command list size \"%s\" is not a positive " - "integer, line %i\n", param->value, param->line); - } - interface_max_command_list_size = tmp * 1024; - } - - param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE); - - if (param) { - long tmp = strtol(param->value, &test, 10); - if (*test != '\0' || tmp <= 0) { - FATAL("max output buffer size \"%s\" is not a positive " - "integer, line %i\n", param->value, param->line); - } - interface_max_output_buffer_size = tmp * 1024; - } - - interfaces = xmalloc(sizeof(Interface) * interface_max_connections); - - list_cache = xcalloc(interface_list_cache_size, sizeof(struct strnode)); - list_cache_head = &(list_cache[0]); - list_cache_tail = &(list_cache[interface_list_cache_size - 1]); - - for (i = 0; i < interface_max_connections; i++) { - interfaces[i].fd = -1; - interfaces[i].send_buf = NULL; - interfaces[i].send_buf_size = 0; - interfaces[i].send_buf_alloc = 0; - interfaces[i].num = i; - } -} - -static void closeAllInterfaces(void) -{ - unsigned int i; - - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0) - closeInterface(&(interfaces[i])); - if (interfaces[i].send_buf) - free(interfaces[i].send_buf); - } - free(list_cache); -} - -void freeAllInterfaces(void) -{ - closeAllInterfaces(); - - free(interfaces); - - interface_max_connections = 0; -} - -void closeOldInterfaces(void) -{ - unsigned int i; - - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0) { - if (interfaces[i].expired) { - DEBUG("interface %i: expired\n", i); - closeInterface(&(interfaces[i])); - } else if (time(NULL) - interfaces[i].lastTime > - interface_timeout) { - DEBUG("interface %i: timeout\n", i); - closeInterface(&(interfaces[i])); - } - } - } -} - -static void flushInterfaceBuffer(Interface * interface) -{ - struct sllnode *buf; - ssize_t ret = 0; - - buf = interface->deferred_send; - while (buf) { - ret = write(interface->fd, buf->data, buf->size); - if (ret < 0) - break; - else if ((size_t)ret < buf->size) { - assert(interface->deferred_bytes >= (size_t)ret); - interface->deferred_bytes -= ret; - buf->data = (char *)buf->data + ret; - buf->size -= ret; - } else { - struct sllnode *tmp = buf; - size_t decr = (buf->size + sizeof(struct sllnode)); - - assert(interface->deferred_bytes >= decr); - interface->deferred_bytes -= decr; - buf = buf->next; - free(tmp); - interface->deferred_send = buf; - } - interface->lastTime = time(NULL); - } - - if (!interface->deferred_send) { - DEBUG("interface %i: buffer empty %lu\n", interface->num, - (unsigned long)interface->deferred_bytes); - assert(interface->deferred_bytes == 0); - } else if (ret < 0 && errno != EAGAIN && errno != EINTR) { - /* cause interface to close */ - DEBUG("interface %i: problems flushing buffer\n", - interface->num); - buf = interface->deferred_send; - do { - struct sllnode *prev = buf; - buf = buf->next; - free(prev); - } while (buf); - interface->deferred_send = NULL; - interface->deferred_bytes = 0; - interface->expired = 1; - } -} - -int interfacePrintWithFD(int fd, const char *buffer, size_t buflen) -{ - static unsigned int i; - size_t copylen; - Interface *interface; - - assert(fd >= 0); - - if (i >= interface_max_connections || - interfaces[i].fd < 0 || interfaces[i].fd != fd) { - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd == fd) - break; - } - if (i == interface_max_connections) - return -1; - } - - /* if fd isn't found or interfaces is going to be closed, do nothing */ - if (interfaces[i].expired) - return 0; - - interface = interfaces + i; - - while (buflen > 0 && !interface->expired) { - size_t left; - - assert(interface->send_buf_size >= interface->send_buf_used); - left = interface->send_buf_size - interface->send_buf_used; - - copylen = buflen > left ? left : buflen; - memcpy(interface->send_buf + interface->send_buf_used, buffer, - copylen); - buflen -= copylen; - interface->send_buf_used += copylen; - buffer += copylen; - if (interface->send_buf_used >= interface->send_buf_size) - printInterfaceOutBuffer(interface); - } - - return 0; -} - -static void printInterfaceOutBuffer(Interface * interface) -{ - ssize_t ret; - struct sllnode *buf; - - if (interface->fd < 0 || interface->expired || - !interface->send_buf_used) - return; - - if ((buf = interface->deferred_send)) { - interface->deferred_bytes += sizeof(struct sllnode) - + interface->send_buf_used; - if (interface->deferred_bytes > - interface_max_output_buffer_size) { - ERROR("interface %i: output buffer size (%lu) is " - "larger than the max (%lu)\n", - interface->num, - (unsigned long)interface->deferred_bytes, - (unsigned long)interface_max_output_buffer_size); - /* cause interface to close */ - interface->expired = 1; - do { - struct sllnode *prev = buf; - buf = buf->next; - free(prev); - } while (buf); - interface->deferred_send = NULL; - interface->deferred_bytes = 0; - } else { - while (buf->next) - buf = buf->next; - buf->next = new_sllnode(interface->send_buf, - interface->send_buf_used); - } - } else { - if ((ret = write(interface->fd, interface->send_buf, - interface->send_buf_used)) < 0) { - if (errno == EAGAIN || errno == EINTR) { - interface->deferred_send = - new_sllnode(interface->send_buf, - interface->send_buf_used); - } else { - DEBUG("interface %i: problems writing\n", - interface->num); - interface->expired = 1; - return; - } - } else if ((size_t)ret < interface->send_buf_used) { - interface->deferred_send = - new_sllnode(interface->send_buf + ret, - interface->send_buf_used - ret); - } - if (interface->deferred_send) { - DEBUG("interface %i: buffer created\n", interface->num); - interface->deferred_bytes = - interface->deferred_send->size - + sizeof(struct sllnode); - } - } - - interface->send_buf_used = 0; -} - diff --git a/src/interface.h b/src/interface.h deleted file mode 100644 index c83381319..000000000 --- a/src/interface.h +++ /dev/null @@ -1,32 +0,0 @@ -/* the Music Player Daemon (MPD) - * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) - * This project's homepage is: http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef INTERFACE_H -#define INTERFACE_H - -#include "os_compat.h" - -void initInterfaces(void); -void openAInterface(int fd, const struct sockaddr *addr); -void freeAllInterfaces(void); -void closeOldInterfaces(void); -int interfacePrintWithFD(int fd, const char *buffer, size_t len); - -int doIOForInterfaces(void); - -#endif diff --git a/src/listen.c b/src/listen.c index 2b9b38619..4adebb66a 100644 --- a/src/listen.c +++ b/src/listen.c @@ -17,7 +17,7 @@ */ #include "listen.h" -#include "interface.h" +#include "client.h" #include "conf.h" #include "log.h" #include "utils.h" diff --git a/src/main.c b/src/main.c index 9d75fadc7..45dc962ce 100644 --- a/src/main.c +++ b/src/main.c @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "interface.h" +#include "client.h" #include "command.h" #include "playlist.h" #include "directory.h" diff --git a/src/myfprintf.c b/src/myfprintf.c index 7e4f4678d..abb2fdde3 100644 --- a/src/myfprintf.c +++ b/src/myfprintf.c @@ -17,7 +17,7 @@ */ #include "myfprintf.h" -#include "interface.h" +#include "client.h" #include "path.h" #include "utils.h" #include "os_compat.h" -- cgit v1.2.3 From e97c4e27d34c15324bf71d5dc8443f61a1e26a46 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:02:58 +0200 Subject: client: renamed Interface to struct client Second patch: rename the internal struct name. We will eventually export this type as an opaque forward-declared struct later, so we can pass a struct pointer instead of a file descriptor, which would save us an expensive linear lookup. --- src/client.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index a6ca85497..37d150775 100644 --- a/src/client.c +++ b/src/client.c @@ -59,7 +59,7 @@ static struct strnode *list_cache; static struct strnode *list_cache_head; static struct strnode *list_cache_tail; -typedef struct _Interface { +struct client { char buffer[INTERFACE_MAX_BUFFER_LENGTH]; size_t bufferLength; size_t bufferPos; @@ -81,16 +81,16 @@ typedef struct _Interface { size_t send_buf_used; /* bytes used this instance */ size_t send_buf_size; /* bytes usable this instance */ size_t send_buf_alloc; /* bytes actually allocated */ -} Interface; +}; -static Interface *interfaces; +static struct client *interfaces; -static void flushInterfaceBuffer(Interface * interface); +static void flushInterfaceBuffer(struct client *interface); -static void printInterfaceOutBuffer(Interface * interface); +static void printInterfaceOutBuffer(struct client *interface); #ifdef SO_SNDBUF -static size_t get_default_snd_buf_size(Interface * interface) +static size_t get_default_snd_buf_size(struct client *interface) { int new_size; socklen_t sockOptLen = sizeof(int); @@ -106,13 +106,13 @@ static size_t get_default_snd_buf_size(Interface * interface) return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; } #else /* !SO_SNDBUF */ -static size_t get_default_snd_buf_size(Interface * interface) +static size_t get_default_snd_buf_size(struct client *interface) { return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; } #endif /* !SO_SNDBUF */ -static void set_send_buf_size(Interface * interface) +static void set_send_buf_size(struct client *interface) { size_t new_size = get_default_snd_buf_size(interface); if (interface->send_buf_size != new_size) { @@ -127,7 +127,7 @@ static void set_send_buf_size(Interface * interface) } } -static void openInterface(Interface * interface, int fd) +static void openInterface(struct client *interface, int fd) { assert(interface->fd < 0); @@ -168,7 +168,7 @@ static void free_cmd_list(struct strnode *list) } } -static void cmd_list_clone(Interface * interface) +static void cmd_list_clone(struct client *interface) { struct strnode *new = dup_strlist(interface->cmd_list); free_cmd_list(interface->cmd_list); @@ -181,7 +181,7 @@ static void cmd_list_clone(Interface * interface) interface->cmd_list_tail = new; } -static void new_cmd_list_ptr(Interface * interface, char *s, const int size) +static void new_cmd_list_ptr(struct client *interface, char *s, const int size) { int i; struct strnode *new; @@ -209,7 +209,7 @@ out: interface->cmd_list = interface->cmd_list_tail = new; } -static void closeInterface(Interface * interface) +static void closeInterface(struct client *interface) { struct sllnode *buf; if (interface->fd < 0) @@ -284,7 +284,7 @@ void openAInterface(int fd, const struct sockaddr *addr) } } -static int processLineOfInput(Interface * interface) +static int processLineOfInput(struct client *interface) { int ret = 1; char *line = interface->buffer + interface->bufferPos; @@ -355,7 +355,7 @@ static int processLineOfInput(Interface * interface) return ret; } -static int processBytesRead(Interface * interface, int bytesRead) +static int processBytesRead(struct client *interface, int bytesRead) { int ret = 0; char *buf_tail = &(interface->buffer[interface->bufferLength - 1]); @@ -403,7 +403,7 @@ static int processBytesRead(Interface * interface, int bytesRead) return ret; } -static int interfaceReadInput(Interface * interface) +static int interfaceReadInput(struct client *interface) { int bytesRead; @@ -583,7 +583,7 @@ void initInterfaces(void) interface_max_output_buffer_size = tmp * 1024; } - interfaces = xmalloc(sizeof(Interface) * interface_max_connections); + interfaces = xmalloc(sizeof(interfaces[0]) * interface_max_connections); list_cache = xcalloc(interface_list_cache_size, sizeof(struct strnode)); list_cache_head = &(list_cache[0]); @@ -638,7 +638,7 @@ void closeOldInterfaces(void) } } -static void flushInterfaceBuffer(Interface * interface) +static void flushInterfaceBuffer(struct client *interface) { struct sllnode *buf; ssize_t ret = 0; @@ -690,7 +690,7 @@ int interfacePrintWithFD(int fd, const char *buffer, size_t buflen) { static unsigned int i; size_t copylen; - Interface *interface; + struct client *interface; assert(fd >= 0); @@ -729,7 +729,7 @@ int interfacePrintWithFD(int fd, const char *buffer, size_t buflen) return 0; } -static void printInterfaceOutBuffer(Interface * interface) +static void printInterfaceOutBuffer(struct client *interface) { ssize_t ret; struct sllnode *buf; -- cgit v1.2.3 From ea2592efafb903bd8afb362daab8f3ae9b3a86c3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:02:59 +0200 Subject: client: renamed internal functions and variables Rename all static functions, variables and macros which have "interface" in their name to something nicer prefixed with "client_". --- src/client.c | 593 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 296 insertions(+), 297 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 37d150775..63595da03 100644 --- a/src/client.c +++ b/src/client.c @@ -33,34 +33,34 @@ #define GREETING "OK MPD " PROTOCOL_VERSION "\n" -#define INTERFACE_MAX_BUFFER_LENGTH (40960) -#define INTERFACE_LIST_MODE_BEGIN "command_list_begin" -#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin" -#define INTERFACE_LIST_MODE_END "command_list_end" -#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE (4096) -#define INTERFACE_TIMEOUT_DEFAULT (60) -#define INTERFACE_MAX_CONNECTIONS_DEFAULT (10) -#define INTERFACE_MAX_COMMAND_LIST_DEFAULT (2048*1024) -#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024) - -/* set this to zero to indicate we have no possible interfaces */ -static unsigned int interface_max_connections; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */ -static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT; -static size_t interface_max_command_list_size = - INTERFACE_MAX_COMMAND_LIST_DEFAULT; -static size_t interface_max_output_buffer_size = - INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT; +#define CLIENT_MAX_BUFFER_LENGTH (40960) +#define CLIENT_LIST_MODE_BEGIN "command_list_begin" +#define CLIENT_LIST_OK_MODE_BEGIN "command_list_ok_begin" +#define CLIENT_LIST_MODE_END "command_list_end" +#define CLIENT_DEFAULT_OUT_BUFFER_SIZE (4096) +#define CLIENT_TIMEOUT_DEFAULT (60) +#define CLIENT_MAX_CONNECTIONS_DEFAULT (10) +#define CLIENT_MAX_COMMAND_LIST_DEFAULT (2048*1024) +#define CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024) + +/* set this to zero to indicate we have no possible clients */ +static unsigned int client_max_connections; /*CLIENT_MAX_CONNECTIONS_DEFAULT; */ +static int client_timeout = CLIENT_TIMEOUT_DEFAULT; +static size_t client_max_command_list_size = + CLIENT_MAX_COMMAND_LIST_DEFAULT; +static size_t client_max_output_buffer_size = + CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT; /* maybe make conf option for this, or... 32 might be good enough */ -static long int interface_list_cache_size = 32; +static long int client_list_cache_size = 32; -/* shared globally between all interfaces: */ +/* shared globally between all clients: */ static struct strnode *list_cache; static struct strnode *list_cache_head; static struct strnode *list_cache_tail; struct client { - char buffer[INTERFACE_MAX_BUFFER_LENGTH]; + char buffer[CLIENT_MAX_BUFFER_LENGTH]; size_t bufferLength; size_t bufferPos; int fd; /* file descriptor */ @@ -73,9 +73,9 @@ struct client { int cmd_list_dup; /* has the cmd_list been copied to private space? */ struct sllnode *deferred_send; /* for output if client is slow */ size_t deferred_bytes; /* mem deferred_send consumes */ - int expired; /* set whether this interface should be closed on next - check of old interfaces */ - unsigned int num; /* interface number */ + int expired; /* set whether this client should be closed on next + check of old clients */ + unsigned int num; /* client number */ char *send_buf; size_t send_buf_used; /* bytes used this instance */ @@ -83,71 +83,71 @@ struct client { size_t send_buf_alloc; /* bytes actually allocated */ }; -static struct client *interfaces; +static struct client *clients; -static void flushInterfaceBuffer(struct client *interface); +static void client_write_deferred(struct client *client); -static void printInterfaceOutBuffer(struct client *interface); +static void client_write_output(struct client *client); #ifdef SO_SNDBUF -static size_t get_default_snd_buf_size(struct client *interface) +static size_t get_default_snd_buf_size(struct client *client) { int new_size; socklen_t sockOptLen = sizeof(int); - if (getsockopt(interface->fd, SOL_SOCKET, SO_SNDBUF, + if (getsockopt(client->fd, SOL_SOCKET, SO_SNDBUF, (char *)&new_size, &sockOptLen) < 0) { DEBUG("problem getting sockets send buffer size\n"); - return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; + return CLIENT_DEFAULT_OUT_BUFFER_SIZE; } if (new_size > 0) return (size_t)new_size; DEBUG("sockets send buffer size is not positive\n"); - return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; + return CLIENT_DEFAULT_OUT_BUFFER_SIZE; } #else /* !SO_SNDBUF */ -static size_t get_default_snd_buf_size(struct client *interface) +static size_t get_default_snd_buf_size(struct client *client) { - return INTERFACE_DEFAULT_OUT_BUFFER_SIZE; + return CLIENT_DEFAULT_OUT_BUFFER_SIZE; } #endif /* !SO_SNDBUF */ -static void set_send_buf_size(struct client *interface) +static void set_send_buf_size(struct client *client) { - size_t new_size = get_default_snd_buf_size(interface); - if (interface->send_buf_size != new_size) { - interface->send_buf_size = new_size; + size_t new_size = get_default_snd_buf_size(client); + if (client->send_buf_size != new_size) { + client->send_buf_size = new_size; /* don't resize to get smaller, only bigger */ - if (interface->send_buf_alloc < new_size) { - if (interface->send_buf) - free(interface->send_buf); - interface->send_buf = xmalloc(new_size); - interface->send_buf_alloc = new_size; + if (client->send_buf_alloc < new_size) { + if (client->send_buf) + free(client->send_buf); + client->send_buf = xmalloc(new_size); + client->send_buf_alloc = new_size; } } } -static void openInterface(struct client *interface, int fd) +static void client_init(struct client *client, int fd) { - assert(interface->fd < 0); - - interface->cmd_list_size = 0; - interface->cmd_list_dup = 0; - interface->cmd_list_OK = -1; - interface->bufferLength = 0; - interface->bufferPos = 0; - interface->fd = fd; + assert(client->fd < 0); + + client->cmd_list_size = 0; + client->cmd_list_dup = 0; + client->cmd_list_OK = -1; + client->bufferLength = 0; + client->bufferPos = 0; + client->fd = fd; set_nonblocking(fd); - interface->lastTime = time(NULL); - interface->cmd_list = NULL; - interface->cmd_list_tail = NULL; - interface->deferred_send = NULL; - interface->expired = 0; - interface->deferred_bytes = 0; - interface->send_buf_used = 0; + client->lastTime = time(NULL); + client->cmd_list = NULL; + client->cmd_list_tail = NULL; + client->deferred_send = NULL; + client->expired = 0; + client->deferred_bytes = 0; + client->send_buf_used = 0; - interface->permission = getDefaultPermissions(); - set_send_buf_size(interface); + client->permission = getDefaultPermissions(); + set_send_buf_size(client); xwrite(fd, GREETING, strlen(GREETING)); } @@ -168,26 +168,26 @@ static void free_cmd_list(struct strnode *list) } } -static void cmd_list_clone(struct client *interface) +static void cmd_list_clone(struct client *client) { - struct strnode *new = dup_strlist(interface->cmd_list); - free_cmd_list(interface->cmd_list); - interface->cmd_list = new; - interface->cmd_list_dup = 1; + struct strnode *new = dup_strlist(client->cmd_list); + free_cmd_list(client->cmd_list); + client->cmd_list = new; + client->cmd_list_dup = 1; /* new tail */ while (new && new->next) new = new->next; - interface->cmd_list_tail = new; + client->cmd_list_tail = new; } -static void new_cmd_list_ptr(struct client *interface, char *s, const int size) +static void new_cmd_list_ptr(struct client *client, char *s, const int size) { int i; struct strnode *new; - if (!interface->cmd_list_dup) { - for (i = interface_list_cache_size - 1; i >= 0; --i) { + if (!client->cmd_list_dup) { + for (i = client_list_cache_size - 1; i >= 0; --i) { if (list_cache[i].data) continue; new = &(list_cache[i]); @@ -199,49 +199,49 @@ static void new_cmd_list_ptr(struct client *interface, char *s, const int size) } /* allocate from the heap */ - new = interface->cmd_list_dup ? new_strnode_dup(s, size) + new = client->cmd_list_dup ? new_strnode_dup(s, size) : new_strnode(s); out: - if (interface->cmd_list) { - interface->cmd_list_tail->next = new; - interface->cmd_list_tail = new; + if (client->cmd_list) { + client->cmd_list_tail->next = new; + client->cmd_list_tail = new; } else - interface->cmd_list = interface->cmd_list_tail = new; + client->cmd_list = client->cmd_list_tail = new; } -static void closeInterface(struct client *interface) +static void client_close(struct client *client) { struct sllnode *buf; - if (interface->fd < 0) + if (client->fd < 0) return; - xclose(interface->fd); - interface->fd = -1; + xclose(client->fd); + client->fd = -1; - if (interface->cmd_list) { - free_cmd_list(interface->cmd_list); - interface->cmd_list = NULL; + if (client->cmd_list) { + free_cmd_list(client->cmd_list); + client->cmd_list = NULL; } - if ((buf = interface->deferred_send)) { + if ((buf = client->deferred_send)) { do { struct sllnode *prev = buf; buf = buf->next; free(prev); } while (buf); - interface->deferred_send = NULL; + client->deferred_send = NULL; } - SECURE("interface %i: closed\n", interface->num); + SECURE("client %i: closed\n", client->num); } void openAInterface(int fd, const struct sockaddr *addr) { unsigned int i; - for (i = 0; i < interface_max_connections - && interfaces[i].fd >= 0; i++) /* nothing */ ; + for (i = 0; i < client_max_connections + && clients[i].fd >= 0; i++) /* nothing */ ; - if (i == interface_max_connections) { + if (i == client_max_connections) { ERROR("Max Connections Reached!\n"); xclose(fd); } else { @@ -279,120 +279,120 @@ void openAInterface(int fd, const struct sockaddr *addr) default: hostname = "unknown"; } - SECURE("interface %i: opened from %s\n", i, hostname); - openInterface(&(interfaces[i]), fd); + SECURE("client %i: opened from %s\n", i, hostname); + client_init(&(clients[i]), fd); } } -static int processLineOfInput(struct client *interface) +static int client_process_line(struct client *client) { int ret = 1; - char *line = interface->buffer + interface->bufferPos; - - if (interface->cmd_list_OK >= 0) { - if (strcmp(line, INTERFACE_LIST_MODE_END) == 0) { - DEBUG("interface %i: process command " - "list\n", interface->num); - ret = processListOfCommands(interface->fd, - &(interface->permission), - &(interface->expired), - interface->cmd_list_OK, - interface->cmd_list); - DEBUG("interface %i: process command " - "list returned %i\n", interface->num, ret); + char *line = client->buffer + client->bufferPos; + + if (client->cmd_list_OK >= 0) { + if (strcmp(line, CLIENT_LIST_MODE_END) == 0) { + DEBUG("client %i: process command " + "list\n", client->num); + ret = processListOfCommands(client->fd, + &(client->permission), + &(client->expired), + client->cmd_list_OK, + client->cmd_list); + DEBUG("client %i: process command " + "list returned %i\n", client->num, ret); if (ret == 0) - commandSuccess(interface->fd); + commandSuccess(client->fd); else if (ret == COMMAND_RETURN_CLOSE - || interface->expired) - closeInterface(interface); + || client->expired) + client_close(client); - printInterfaceOutBuffer(interface); - free_cmd_list(interface->cmd_list); - interface->cmd_list = NULL; - interface->cmd_list_OK = -1; + client_write_output(client); + free_cmd_list(client->cmd_list); + client->cmd_list = NULL; + client->cmd_list_OK = -1; } else { size_t len = strlen(line) + 1; - interface->cmd_list_size += len; - if (interface->cmd_list_size > - interface_max_command_list_size) { - ERROR("interface %i: command " + client->cmd_list_size += len; + if (client->cmd_list_size > + client_max_command_list_size) { + ERROR("client %i: command " "list size (%lu) is " "larger than the max " "(%lu)\n", - interface->num, - (unsigned long)interface->cmd_list_size, + client->num, + (unsigned long)client->cmd_list_size, (unsigned long) - interface_max_command_list_size); - closeInterface(interface); + client_max_command_list_size); + client_close(client); ret = COMMAND_RETURN_CLOSE; } else - new_cmd_list_ptr(interface, line, len); + new_cmd_list_ptr(client, line, len); } } else { - if (strcmp(line, INTERFACE_LIST_MODE_BEGIN) == 0) { - interface->cmd_list_OK = 0; + if (strcmp(line, CLIENT_LIST_MODE_BEGIN) == 0) { + client->cmd_list_OK = 0; ret = 1; - } else if (strcmp(line, INTERFACE_LIST_OK_MODE_BEGIN) == 0) { - interface->cmd_list_OK = 1; + } else if (strcmp(line, CLIENT_LIST_OK_MODE_BEGIN) == 0) { + client->cmd_list_OK = 1; ret = 1; } else { - DEBUG("interface %i: process command \"%s\"\n", - interface->num, line); - ret = processCommand(interface->fd, - &(interface->permission), line); - DEBUG("interface %i: command returned %i\n", - interface->num, ret); + DEBUG("client %i: process command \"%s\"\n", + client->num, line); + ret = processCommand(client->fd, + &(client->permission), line); + DEBUG("client %i: command returned %i\n", + client->num, ret); if (ret == 0) - commandSuccess(interface->fd); + commandSuccess(client->fd); else if (ret == COMMAND_RETURN_CLOSE - || interface->expired) { - closeInterface(interface); + || client->expired) { + client_close(client); } - printInterfaceOutBuffer(interface); + client_write_output(client); } } return ret; } -static int processBytesRead(struct client *interface, int bytesRead) +static int client_input_received(struct client *client, int bytesRead) { int ret = 0; - char *buf_tail = &(interface->buffer[interface->bufferLength - 1]); + char *buf_tail = &(client->buffer[client->bufferLength - 1]); while (bytesRead > 0) { - interface->bufferLength++; + client->bufferLength++; bytesRead--; buf_tail++; if (*buf_tail == '\n') { *buf_tail = '\0'; - if (interface->bufferLength > interface->bufferPos) { + if (client->bufferLength > client->bufferPos) { if (*(buf_tail - 1) == '\r') *(buf_tail - 1) = '\0'; } - ret = processLineOfInput(interface); - if (interface->expired) + ret = client_process_line(client); + if (client->expired) return ret; - interface->bufferPos = interface->bufferLength; + client->bufferPos = client->bufferLength; } - if (interface->bufferLength == INTERFACE_MAX_BUFFER_LENGTH) { - if (interface->bufferPos == 0) { - ERROR("interface %i: buffer overflow\n", - interface->num); - closeInterface(interface); + if (client->bufferLength == CLIENT_MAX_BUFFER_LENGTH) { + if (client->bufferPos == 0) { + ERROR("client %i: buffer overflow\n", + client->num); + client_close(client); return 1; } - if (interface->cmd_list_OK >= 0 && - interface->cmd_list && - !interface->cmd_list_dup) - cmd_list_clone(interface); - assert(interface->bufferLength >= interface->bufferPos + if (client->cmd_list_OK >= 0 && + client->cmd_list && + !client->cmd_list_dup) + cmd_list_clone(client); + assert(client->bufferLength >= client->bufferPos && "bufferLength >= bufferPos"); - interface->bufferLength -= interface->bufferPos; - memmove(interface->buffer, - interface->buffer + interface->bufferPos, - interface->bufferLength); - interface->bufferPos = 0; + client->bufferLength -= client->bufferPos; + memmove(client->buffer, + client->buffer + client->bufferPos, + client->bufferLength); + client->bufferPos = 0; } if (ret == COMMAND_RETURN_KILL || ret == COMMAND_RETURN_CLOSE) { return ret; @@ -403,54 +403,53 @@ static int processBytesRead(struct client *interface, int bytesRead) return ret; } -static int interfaceReadInput(struct client *interface) +static int client_read(struct client *client) { int bytesRead; - bytesRead = read(interface->fd, - interface->buffer + interface->bufferLength, - INTERFACE_MAX_BUFFER_LENGTH - interface->bufferLength); + bytesRead = read(client->fd, + client->buffer + client->bufferLength, + CLIENT_MAX_BUFFER_LENGTH - client->bufferLength); if (bytesRead > 0) - return processBytesRead(interface, bytesRead); + return client_input_received(client, bytesRead); else if (bytesRead == 0 || (bytesRead < 0 && errno != EINTR)) { - closeInterface(interface); + client_close(client); } else return 0; return 1; } -static void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds, - int *fdmax) +static void client_manager_register_read_fd(fd_set * fds, int *fdmax) { unsigned int i; FD_ZERO(fds); addListenSocketsToFdSet(fds, fdmax); - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0 && !interfaces[i].expired - && !interfaces[i].deferred_send) { - FD_SET(interfaces[i].fd, fds); - if (*fdmax < interfaces[i].fd) - *fdmax = interfaces[i].fd; + 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; } } } -static void addInterfacesForBufferFlushToFdSet(fd_set * fds, int *fdmax) +static void client_manager_register_write_fd(fd_set * fds, int *fdmax) { unsigned int i; FD_ZERO(fds); - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0 && !interfaces[i].expired - && interfaces[i].deferred_send) { - FD_SET(interfaces[i].fd, fds); - if (*fdmax < interfaces[i].fd) - *fdmax = interfaces[i].fd; + 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; } } } @@ -464,13 +463,13 @@ static void closeNextErroredInterface(void) tv.tv_sec = 0; tv.tv_usec = 0; - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0) { + for (i = 0; i < client_max_connections; i++) { + if (clients[i].fd >= 0) { FD_ZERO(&fds); - FD_SET(interfaces[i].fd, &fds); - if (select(interfaces[i].fd + 1, + FD_SET(clients[i].fd, &fds); + if (select(clients[i].fd + 1, &fds, NULL, NULL, &tv) < 0) { - closeInterface(&interfaces[i]); + client_close(&clients[i]); return; } } @@ -490,8 +489,8 @@ int doIOForInterfaces(void) fdmax = 0; FD_ZERO( &efds ); - addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax); - addInterfacesForBufferFlushToFdSet(&wfds, &fdmax); + client_manager_register_read_fd(&rfds, &fdmax); + client_manager_register_write_fd(&wfds, &fdmax); registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); @@ -511,19 +510,19 @@ int doIOForInterfaces(void) getConnections(&rfds); - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0 - && FD_ISSET(interfaces[i].fd, &rfds)) { + for (i = 0; i < client_max_connections; i++) { + if (clients[i].fd >= 0 + && FD_ISSET(clients[i].fd, &rfds)) { if (COMMAND_RETURN_KILL == - interfaceReadInput(&(interfaces[i]))) { + client_read(&(clients[i]))) { return COMMAND_RETURN_KILL; } - interfaces[i].lastTime = time(NULL); + clients[i].lastTime = time(NULL); } - if (interfaces[i].fd >= 0 - && FD_ISSET(interfaces[i].fd, &wfds)) { - flushInterfaceBuffer(&interfaces[i]); - interfaces[i].lastTime = time(NULL); + if (clients[i].fd >= 0 + && FD_ISSET(clients[i].fd, &wfds)) { + client_write_deferred(&clients[i]); + clients[i].lastTime = time(NULL); } } @@ -542,8 +541,8 @@ void initInterfaces(void) param = getConfigParam(CONF_CONN_TIMEOUT); if (param) { - interface_timeout = strtol(param->value, &test, 10); - if (*test != '\0' || interface_timeout <= 0) { + client_timeout = strtol(param->value, &test, 10); + if (*test != '\0' || client_timeout <= 0) { FATAL("connection timeout \"%s\" is not a positive " "integer, line %i\n", CONF_CONN_TIMEOUT, param->line); @@ -553,13 +552,13 @@ void initInterfaces(void) param = getConfigParam(CONF_MAX_CONN); if (param) { - interface_max_connections = strtol(param->value, &test, 10); - if (*test != '\0' || interface_max_connections <= 0) { + client_max_connections = strtol(param->value, &test, 10); + if (*test != '\0' || client_max_connections <= 0) { FATAL("max connections \"%s\" is not a positive integer" ", line %i\n", param->value, param->line); } } else - interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT; + client_max_connections = CLIENT_MAX_CONNECTIONS_DEFAULT; param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE); @@ -569,7 +568,7 @@ void initInterfaces(void) FATAL("max command list size \"%s\" is not a positive " "integer, line %i\n", param->value, param->line); } - interface_max_command_list_size = tmp * 1024; + client_max_command_list_size = tmp * 1024; } param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE); @@ -580,109 +579,109 @@ void initInterfaces(void) FATAL("max output buffer size \"%s\" is not a positive " "integer, line %i\n", param->value, param->line); } - interface_max_output_buffer_size = tmp * 1024; + client_max_output_buffer_size = tmp * 1024; } - interfaces = xmalloc(sizeof(interfaces[0]) * interface_max_connections); + clients = xmalloc(sizeof(clients[0]) * client_max_connections); - list_cache = xcalloc(interface_list_cache_size, sizeof(struct strnode)); + list_cache = xcalloc(client_list_cache_size, sizeof(struct strnode)); list_cache_head = &(list_cache[0]); - list_cache_tail = &(list_cache[interface_list_cache_size - 1]); - - for (i = 0; i < interface_max_connections; i++) { - interfaces[i].fd = -1; - interfaces[i].send_buf = NULL; - interfaces[i].send_buf_size = 0; - interfaces[i].send_buf_alloc = 0; - interfaces[i].num = i; + 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 closeAllInterfaces(void) +static void client_close_all(void) { unsigned int i; - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0) - closeInterface(&(interfaces[i])); - if (interfaces[i].send_buf) - free(interfaces[i].send_buf); + 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); } void freeAllInterfaces(void) { - closeAllInterfaces(); + client_close_all(); - free(interfaces); + free(clients); - interface_max_connections = 0; + client_max_connections = 0; } void closeOldInterfaces(void) { unsigned int i; - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd >= 0) { - if (interfaces[i].expired) { - DEBUG("interface %i: expired\n", i); - closeInterface(&(interfaces[i])); - } else if (time(NULL) - interfaces[i].lastTime > - interface_timeout) { - DEBUG("interface %i: timeout\n", i); - closeInterface(&(interfaces[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])); } } } } -static void flushInterfaceBuffer(struct client *interface) +static void client_write_deferred(struct client *client) { struct sllnode *buf; ssize_t ret = 0; - buf = interface->deferred_send; + buf = client->deferred_send; while (buf) { - ret = write(interface->fd, buf->data, buf->size); + ret = write(client->fd, buf->data, buf->size); if (ret < 0) break; else if ((size_t)ret < buf->size) { - assert(interface->deferred_bytes >= (size_t)ret); - interface->deferred_bytes -= ret; + assert(client->deferred_bytes >= (size_t)ret); + client->deferred_bytes -= ret; buf->data = (char *)buf->data + ret; buf->size -= ret; } else { struct sllnode *tmp = buf; size_t decr = (buf->size + sizeof(struct sllnode)); - assert(interface->deferred_bytes >= decr); - interface->deferred_bytes -= decr; + assert(client->deferred_bytes >= decr); + client->deferred_bytes -= decr; buf = buf->next; free(tmp); - interface->deferred_send = buf; + client->deferred_send = buf; } - interface->lastTime = time(NULL); + client->lastTime = time(NULL); } - if (!interface->deferred_send) { - DEBUG("interface %i: buffer empty %lu\n", interface->num, - (unsigned long)interface->deferred_bytes); - assert(interface->deferred_bytes == 0); + if (!client->deferred_send) { + DEBUG("client %i: buffer empty %lu\n", client->num, + (unsigned long)client->deferred_bytes); + assert(client->deferred_bytes == 0); } else if (ret < 0 && errno != EAGAIN && errno != EINTR) { - /* cause interface to close */ - DEBUG("interface %i: problems flushing buffer\n", - interface->num); - buf = interface->deferred_send; + /* cause client to close */ + DEBUG("client %i: problems flushing buffer\n", + client->num); + buf = client->deferred_send; do { struct sllnode *prev = buf; buf = buf->next; free(prev); } while (buf); - interface->deferred_send = NULL; - interface->deferred_bytes = 0; - interface->expired = 1; + client->deferred_send = NULL; + client->deferred_bytes = 0; + client->expired = 1; } } @@ -690,105 +689,105 @@ int interfacePrintWithFD(int fd, const char *buffer, size_t buflen) { static unsigned int i; size_t copylen; - struct client *interface; + struct client *client; assert(fd >= 0); - if (i >= interface_max_connections || - interfaces[i].fd < 0 || interfaces[i].fd != fd) { - for (i = 0; i < interface_max_connections; i++) { - if (interfaces[i].fd == fd) + if (i >= client_max_connections || + clients[i].fd < 0 || clients[i].fd != fd) { + for (i = 0; i < client_max_connections; i++) { + if (clients[i].fd == fd) break; } - if (i == interface_max_connections) + if (i == client_max_connections) return -1; } - /* if fd isn't found or interfaces is going to be closed, do nothing */ - if (interfaces[i].expired) + /* if fd isn't found or client is going to be closed, do nothing */ + if (clients[i].expired) return 0; - interface = interfaces + i; + client = clients + i; - while (buflen > 0 && !interface->expired) { + while (buflen > 0 && !client->expired) { size_t left; - assert(interface->send_buf_size >= interface->send_buf_used); - left = interface->send_buf_size - interface->send_buf_used; + assert(client->send_buf_size >= client->send_buf_used); + left = client->send_buf_size - client->send_buf_used; copylen = buflen > left ? left : buflen; - memcpy(interface->send_buf + interface->send_buf_used, buffer, + memcpy(client->send_buf + client->send_buf_used, buffer, copylen); buflen -= copylen; - interface->send_buf_used += copylen; + client->send_buf_used += copylen; buffer += copylen; - if (interface->send_buf_used >= interface->send_buf_size) - printInterfaceOutBuffer(interface); + if (client->send_buf_used >= client->send_buf_size) + client_write_output(client); } return 0; } -static void printInterfaceOutBuffer(struct client *interface) +static void client_write_output(struct client *client) { ssize_t ret; struct sllnode *buf; - if (interface->fd < 0 || interface->expired || - !interface->send_buf_used) + if (client->fd < 0 || client->expired || + !client->send_buf_used) return; - if ((buf = interface->deferred_send)) { - interface->deferred_bytes += sizeof(struct sllnode) - + interface->send_buf_used; - if (interface->deferred_bytes > - interface_max_output_buffer_size) { - ERROR("interface %i: output buffer size (%lu) is " + if ((buf = client->deferred_send)) { + client->deferred_bytes += sizeof(struct sllnode) + + client->send_buf_used; + if (client->deferred_bytes > + client_max_output_buffer_size) { + ERROR("client %i: output buffer size (%lu) is " "larger than the max (%lu)\n", - interface->num, - (unsigned long)interface->deferred_bytes, - (unsigned long)interface_max_output_buffer_size); - /* cause interface to close */ - interface->expired = 1; + client->num, + (unsigned long)client->deferred_bytes, + (unsigned long)client_max_output_buffer_size); + /* cause client to close */ + client->expired = 1; do { struct sllnode *prev = buf; buf = buf->next; free(prev); } while (buf); - interface->deferred_send = NULL; - interface->deferred_bytes = 0; + client->deferred_send = NULL; + client->deferred_bytes = 0; } else { while (buf->next) buf = buf->next; - buf->next = new_sllnode(interface->send_buf, - interface->send_buf_used); + buf->next = new_sllnode(client->send_buf, + client->send_buf_used); } } else { - if ((ret = write(interface->fd, interface->send_buf, - interface->send_buf_used)) < 0) { + if ((ret = write(client->fd, client->send_buf, + client->send_buf_used)) < 0) { if (errno == EAGAIN || errno == EINTR) { - interface->deferred_send = - new_sllnode(interface->send_buf, - interface->send_buf_used); + client->deferred_send = + new_sllnode(client->send_buf, + client->send_buf_used); } else { - DEBUG("interface %i: problems writing\n", - interface->num); - interface->expired = 1; + DEBUG("client %i: problems writing\n", + client->num); + client->expired = 1; return; } - } else if ((size_t)ret < interface->send_buf_used) { - interface->deferred_send = - new_sllnode(interface->send_buf + ret, - interface->send_buf_used - ret); + } else if ((size_t)ret < client->send_buf_used) { + client->deferred_send = + new_sllnode(client->send_buf + ret, + client->send_buf_used - ret); } - if (interface->deferred_send) { - DEBUG("interface %i: buffer created\n", interface->num); - interface->deferred_bytes = - interface->deferred_send->size + if (client->deferred_send) { + DEBUG("client %i: buffer created\n", client->num); + client->deferred_bytes = + client->deferred_send->size + sizeof(struct sllnode); } } - interface->send_buf_used = 0; + client->send_buf_used = 0; } -- cgit v1.2.3 From 9cf1bf0671950024a21918335ab82ce9ef24cbf7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:02 +0200 Subject: client: renamed all public functions Functions which operate on the whole client list are prefixed with "client_manager_", and functions which handle just one client just get "client_". --- src/client.c | 12 ++++++------ src/client.h | 12 ++++++------ src/directory.c | 2 +- src/listen.c | 2 +- src/main.c | 8 ++++---- src/myfprintf.c | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 63595da03..87088e76f 100644 --- a/src/client.c +++ b/src/client.c @@ -234,7 +234,7 @@ static void client_close(struct client *client) SECURE("client %i: closed\n", client->num); } -void openAInterface(int fd, const struct sockaddr *addr) +void client_new(int fd, const struct sockaddr *addr) { unsigned int i; @@ -476,7 +476,7 @@ static void closeNextErroredInterface(void) } } -int doIOForInterfaces(void) +int client_manager_io(void) { fd_set rfds; fd_set wfds; @@ -532,7 +532,7 @@ int doIOForInterfaces(void) return 1; } -void initInterfaces(void) +void client_manager_init(void) { unsigned int i; char *test; @@ -610,7 +610,7 @@ static void client_close_all(void) free(list_cache); } -void freeAllInterfaces(void) +void client_manager_deinit(void) { client_close_all(); @@ -619,7 +619,7 @@ void freeAllInterfaces(void) client_max_connections = 0; } -void closeOldInterfaces(void) +void client_manager_expire(void) { unsigned int i; @@ -685,7 +685,7 @@ static void client_write_deferred(struct client *client) } } -int interfacePrintWithFD(int fd, const char *buffer, size_t buflen) +int client_print(int fd, const char *buffer, size_t buflen) { static unsigned int i; size_t copylen; diff --git a/src/client.h b/src/client.h index c83381319..64639b2af 100644 --- a/src/client.h +++ b/src/client.h @@ -21,12 +21,12 @@ #include "os_compat.h" -void initInterfaces(void); -void openAInterface(int fd, const struct sockaddr *addr); -void freeAllInterfaces(void); -void closeOldInterfaces(void); -int interfacePrintWithFD(int fd, const char *buffer, size_t len); +void client_manager_init(void); +void client_new(int fd, const struct sockaddr *addr); +void client_manager_deinit(void); +void client_manager_expire(void); +int client_print(int fd, const char *buffer, size_t len); -int doIOForInterfaces(void); +int client_manager_io(void); #endif diff --git a/src/directory.c b/src/directory.c index 6f3409356..46d309c76 100644 --- a/src/directory.c +++ b/src/directory.c @@ -177,7 +177,7 @@ int updateInit(int fd, List * pathList) finishSigHandlers(); closeAllListenSockets(); - freeAllInterfaces(); + client_manager_deinit(); finishPlaylist(); finishVolume(); diff --git a/src/listen.c b/src/listen.c index 4adebb66a..c40035279 100644 --- a/src/listen.c +++ b/src/listen.c @@ -297,7 +297,7 @@ void getConnections(fd_set * fds) if (FD_ISSET(listenSockets[i], fds)) { if ((fd = accept(listenSockets[i], &sockAddr, &socklen)) >= 0) { - openAInterface(fd, &sockAddr); + client_new(fd, &sockAddr); } else if (fd < 0 && (errno != EAGAIN && errno != EINTR)) { ERROR("Problems accept()'ing\n"); diff --git a/src/main.c b/src/main.c index 45dc962ce..363359831 100644 --- a/src/main.c +++ b/src/main.c @@ -415,7 +415,7 @@ int main(int argc, char *argv[]) initAudioConfig(); initAudioDriver(); initVolume(); - initInterfaces(); + client_manager_init(); initReplayGainState(); initNormalization(); initInputStream(); @@ -435,17 +435,17 @@ int main(int argc, char *argv[]) decoder_init(); read_state_file(); - while (COMMAND_RETURN_KILL != doIOForInterfaces() && + while (COMMAND_RETURN_KILL != client_manager_io() && COMMAND_RETURN_KILL != handlePendingSignals()) { syncPlayerAndPlaylist(); - closeOldInterfaces(); + client_manager_expire(); readDirectoryDBIfUpdateIsFinished(); } write_state_file(); ob_trigger_action(OB_ACTION_PAUSE_SET); finishZeroconf(); - freeAllInterfaces(); + client_manager_deinit(); closeAllListenSockets(); finishPlaylist(); diff --git a/src/myfprintf.c b/src/myfprintf.c index abb2fdde3..200c80334 100644 --- a/src/myfprintf.c +++ b/src/myfprintf.c @@ -49,7 +49,7 @@ void vfdprintf(const int fd, const char *fmt, va_list args) len = strlen(buf); if (fd == STDERR_FILENO || fd == STDOUT_FILENO || - interfacePrintWithFD(fd, buf, len) < 0) + client_print(fd, buf, len) < 0) blockingWrite(fd, buf, len); } -- cgit v1.2.3 From 1e6af706599c733a707e9fd32f0ef733d1908362 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:03 +0200 Subject: client: return early in client_new() This saves one level of indent. --- src/client.c | 61 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 87088e76f..54c62bc83 100644 --- a/src/client.c +++ b/src/client.c @@ -237,6 +237,7 @@ static void client_close(struct client *client) void client_new(int fd, const struct sockaddr *addr) { unsigned int i; + const char *hostname; for (i = 0; i < client_max_connections && clients[i].fd >= 0; i++) /* nothing */ ; @@ -244,44 +245,44 @@ void client_new(int fd, const struct sockaddr *addr) if (i == client_max_connections) { ERROR("Max Connections Reached!\n"); xclose(fd); - } else { - const char *hostname; - switch (addr->sa_family) { + return; + } + + switch (addr->sa_family) { #ifdef HAVE_TCP - case AF_INET: - hostname = (const char *)inet_ntoa(((const struct sockaddr_in *) - addr)->sin_addr); - if (!hostname) - hostname = "error getting ipv4 address"; - break; + case AF_INET: + hostname = (const char *)inet_ntoa(((const struct sockaddr_in *) + addr)->sin_addr); + if (!hostname) + hostname = "error getting ipv4 address"; + break; #ifdef HAVE_IPV6 - case AF_INET6: - { - static char host[INET6_ADDRSTRLEN + 1]; - memset(host, 0, INET6_ADDRSTRLEN + 1); - if (inet_ntop(AF_INET6, (const void *) - &(((const struct sockaddr_in6 *)addr)-> - sin6_addr), host, - INET6_ADDRSTRLEN)) { - hostname = (const char *)host; - } else { - hostname = "error getting ipv6 address"; - } + case AF_INET6: + { + static char host[INET6_ADDRSTRLEN + 1]; + memset(host, 0, INET6_ADDRSTRLEN + 1); + if (inet_ntop(AF_INET6, (const void *) + &(((const struct sockaddr_in6 *)addr)-> + sin6_addr), host, + INET6_ADDRSTRLEN)) { + hostname = (const char *)host; + } else { + hostname = "error getting ipv6 address"; } - break; + } + break; #endif #endif /* HAVE_TCP */ #ifdef HAVE_UN - case AF_UNIX: - hostname = "local connection"; - break; + case AF_UNIX: + hostname = "local connection"; + break; #endif /* HAVE_UN */ - default: - hostname = "unknown"; - } - SECURE("client %i: opened from %s\n", i, hostname); - client_init(&(clients[i]), fd); + default: + hostname = "unknown"; } + SECURE("client %i: opened from %s\n", i, hostname); + client_init(&(clients[i]), fd); } static int client_process_line(struct client *client) -- cgit v1.2.3 From 7c5a476927734aec99ba87d744ac46ff7e890dd5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:06 +0200 Subject: client: added function client_by_fd() The code becomes less complex and more readable when we move this linear search into a separate mini function. --- src/client.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 54c62bc83..c4693193f 100644 --- a/src/client.c +++ b/src/client.c @@ -686,30 +686,38 @@ static void client_write_deferred(struct client *client) } } -int client_print(int fd, const char *buffer, size_t buflen) +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]; + + for (i = 0; i < client_max_connections; i++) + if (clients[i].fd == fd) + return &clients[i]; + + return NULL; +} + +int client_print(int fd, const char *buffer, size_t buflen) +{ size_t copylen; struct client *client; assert(fd >= 0); - if (i >= client_max_connections || - clients[i].fd < 0 || clients[i].fd != fd) { - for (i = 0; i < client_max_connections; i++) { - if (clients[i].fd == fd) - break; - } - if (i == client_max_connections) - return -1; - } + client = client_by_fd(fd); + if (client == NULL) + return -1; /* if fd isn't found or client is going to be closed, do nothing */ - if (clients[i].expired) + if (client->expired) return 0; - client = clients + i; - while (buflen > 0 && !client->expired) { size_t left; -- cgit v1.2.3 From a396943470949bf67065c6a3e3a98540ef4e966b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:48 +0200 Subject: 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. --- src/client.c | 166 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 76 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index c4693193f..2dbc9d0fd 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; @@ -511,19 +523,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); } } @@ -535,7 +545,6 @@ int client_manager_io(void) void client_manager_init(void) { - unsigned int i; char *test; ConfigParam *param; @@ -583,31 +592,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); } @@ -615,25 +612,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); } } } @@ -688,17 +681,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; } @@ -742,8 +729,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)) { -- cgit v1.2.3 From 4184435c697ba953e0a224da5d8f7f4e880c1644 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:49 +0200 Subject: client: don't free client resources except in client_close() All of the client's resources are freed in client_close(). It is enough to set the "expired" flag, no need to duplicate lots of destruction code again and again. --- src/client.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 2dbc9d0fd..3065a6940 100644 --- a/src/client.c +++ b/src/client.c @@ -667,14 +667,6 @@ static void client_write_deferred(struct client *client) /* cause client to close */ DEBUG("client %i: problems flushing buffer\n", client->num); - buf = client->deferred_send; - do { - struct sllnode *prev = buf; - buf = buf->next; - free(prev); - } while (buf); - client->deferred_send = NULL; - client->deferred_bytes = 0; client->expired = 1; } } @@ -744,13 +736,6 @@ static void client_write_output(struct client *client) (unsigned long)client_max_output_buffer_size); /* cause client to close */ client->expired = 1; - do { - struct sllnode *prev = buf; - buf = buf->next; - free(prev); - } while (buf); - client->deferred_send = NULL; - client->deferred_bytes = 0; } else { while (buf->next) buf = buf->next; -- cgit v1.2.3 From 7ff63fec2ca1c2c45d28a1907ab1e08e0356996e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:51 +0200 Subject: client: moved code to client_defer_output() Split the large function client_write_output() into two parts; this is the first code moving patch. --- src/client.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 3065a6940..586d4d212 100644 --- a/src/client.c +++ b/src/client.c @@ -716,33 +716,40 @@ int client_print(int fd, const char *buffer, size_t buflen) return 0; } +static void client_defer_output(struct client *client, + const void *data, size_t length) +{ + struct sllnode *buf = client->deferred_send; + + assert(client->deferred_send != NULL); + + client->deferred_bytes += sizeof(struct sllnode) + length; + if (client->deferred_bytes > client_max_output_buffer_size) { + ERROR("client %i: output buffer size (%lu) is " + "larger than the max (%lu)\n", + client->num, + (unsigned long)client->deferred_bytes, + (unsigned long)client_max_output_buffer_size); + /* cause client to close */ + client->expired = 1; + } else { + while (buf->next) + buf = buf->next; + buf->next = new_sllnode(data, length); + } +} + static void client_write_output(struct client *client) { ssize_t ret; - struct sllnode *buf; if (client->expired || !client->send_buf_used) return; - if ((buf = client->deferred_send)) { - client->deferred_bytes += sizeof(struct sllnode) - + client->send_buf_used; - if (client->deferred_bytes > - client_max_output_buffer_size) { - ERROR("client %i: output buffer size (%lu) is " - "larger than the max (%lu)\n", - client->num, - (unsigned long)client->deferred_bytes, - (unsigned long)client_max_output_buffer_size); - /* cause client to close */ - client->expired = 1; - } else { - while (buf->next) - buf = buf->next; - buf->next = new_sllnode(client->send_buf, - client->send_buf_used); - } - } else { + if (client->deferred_send != NULL) + client_defer_output(client, client->send_buf, + client->send_buf_used); + else { if ((ret = write(client->fd, client->send_buf, client->send_buf_used)) < 0) { if (errno == EAGAIN || errno == EINTR) { -- cgit v1.2.3 From 3682efe7a705043f9005c456cfc806aeefa788ff Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:54 +0200 Subject: client: return early on error in client_defer_output() Exit the function when an error occurs, and move the rest of the following code one indent level left. --- src/client.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 586d4d212..6457fb373 100644 --- a/src/client.c +++ b/src/client.c @@ -719,7 +719,7 @@ int client_print(int fd, const char *buffer, size_t buflen) static void client_defer_output(struct client *client, const void *data, size_t length) { - struct sllnode *buf = client->deferred_send; + struct sllnode *buf; assert(client->deferred_send != NULL); @@ -732,11 +732,13 @@ static void client_defer_output(struct client *client, (unsigned long)client_max_output_buffer_size); /* cause client to close */ client->expired = 1; - } else { - while (buf->next) - buf = buf->next; - buf->next = new_sllnode(data, length); + return; } + + buf = client->deferred_send; + while (buf->next) + buf = buf->next; + buf->next = new_sllnode(data, length); } static void client_write_output(struct client *client) -- cgit v1.2.3 From d6c92ea1348730de5ed8d31b40c92eb5b8e71944 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:56 +0200 Subject: client: client_defer_output() can create the first defer buffer client_defer_output() was designed to add new buffers to an existing deferred_send buffer. Tweak it and allow it to create a new buffer list. --- src/client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 6457fb373..531177ab2 100644 --- a/src/client.c +++ b/src/client.c @@ -719,7 +719,7 @@ int client_print(int fd, const char *buffer, size_t buflen) static void client_defer_output(struct client *client, const void *data, size_t length) { - struct sllnode *buf; + struct sllnode **buf_r; assert(client->deferred_send != NULL); @@ -735,10 +735,10 @@ static void client_defer_output(struct client *client, return; } - buf = client->deferred_send; - while (buf->next) - buf = buf->next; - buf->next = new_sllnode(data, length); + buf_r = &client->deferred_send; + while (*buf_r != NULL) + buf_r = &(*buf_r)->next; + *buf_r = new_sllnode(data, length); } static void client_write_output(struct client *client) -- cgit v1.2.3 From e3293d40147f440cc520f77084a3216064a9b4dd Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:03:58 +0200 Subject: client: moved code to client_write() Move the second part of client_write_output() into a separate function. --- src/client.c | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 531177ab2..d681f8b0b 100644 --- a/src/client.c +++ b/src/client.c @@ -741,41 +741,43 @@ static void client_defer_output(struct client *client, *buf_r = new_sllnode(data, length); } -static void client_write_output(struct client *client) +static void client_write(struct client *client, + const char *data, size_t length) { ssize_t ret; + assert(client->deferred_send == NULL); + + if ((ret = write(client->fd, data, length)) < 0) { + if (errno == EAGAIN || errno == EINTR) { + client->deferred_send = new_sllnode(data, length); + } else { + DEBUG("client %i: problems writing\n", client->num); + client->expired = 1; + return; + } + } else if ((size_t)ret < client->send_buf_used) { + client->deferred_send = new_sllnode(data + ret, length - ret); + } + + if (client->deferred_send) { + DEBUG("client %i: buffer created\n", client->num); + client->deferred_bytes = + client->deferred_send->size + + sizeof(struct sllnode); + } +} + +static void client_write_output(struct client *client) +{ if (client->expired || !client->send_buf_used) return; if (client->deferred_send != NULL) client_defer_output(client, client->send_buf, client->send_buf_used); - else { - if ((ret = write(client->fd, client->send_buf, - client->send_buf_used)) < 0) { - if (errno == EAGAIN || errno == EINTR) { - client->deferred_send = - new_sllnode(client->send_buf, - client->send_buf_used); - } else { - DEBUG("client %i: problems writing\n", - client->num); - client->expired = 1; - return; - } - } else if ((size_t)ret < client->send_buf_used) { - client->deferred_send = - new_sllnode(client->send_buf + ret, - client->send_buf_used - ret); - } - if (client->deferred_send) { - DEBUG("client %i: buffer created\n", client->num); - client->deferred_bytes = - client->deferred_send->size - + sizeof(struct sllnode); - } - } + else + client_write(client, client->send_buf, client->send_buf_used); client->send_buf_used = 0; } -- cgit v1.2.3 From 592d7484ce76fde36c78dc85a6099149c42b734c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:20:04 +0200 Subject: client: use client_defer_output() in client_write() Eliminate duplicated code, call client_defer_output() which we splitted from client_write_output() earlier. --- src/client.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index d681f8b0b..4bb11ba5a 100644 --- a/src/client.c +++ b/src/client.c @@ -750,22 +750,18 @@ static void client_write(struct client *client, if ((ret = write(client->fd, data, length)) < 0) { if (errno == EAGAIN || errno == EINTR) { - client->deferred_send = new_sllnode(data, length); + client_defer_output(client, data, length); } else { DEBUG("client %i: problems writing\n", client->num); client->expired = 1; return; } } else if ((size_t)ret < client->send_buf_used) { - client->deferred_send = new_sllnode(data + ret, length - ret); + client_defer_output(client, data + ret, length - ret); } - if (client->deferred_send) { + if (client->deferred_send) DEBUG("client %i: buffer created\n", client->num); - client->deferred_bytes = - client->deferred_send->size - + sizeof(struct sllnode); - } } static void client_write_output(struct client *client) -- cgit v1.2.3 From 1cb70dcaf7d733c4bbf55d6071d7eabd28651814 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:20:10 +0200 Subject: client: select() errors are fatal Previously, when select() failed, we assumed that there was an invalid file descriptor in one of the client structs. Thus we tried select() one by one. This is bogus, because we should never have invalid file descriptors. Remove it, and make select() errors fatal. --- src/client.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 4bb11ba5a..6ee9b988d 100644 --- a/src/client.c +++ b/src/client.c @@ -469,26 +469,6 @@ static void client_manager_register_write_fd(fd_set * fds, int *fdmax) } } -static void closeNextErroredInterface(void) -{ - struct client *client, *n; - fd_set fds; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 0; - - 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; - } - } -} - int client_manager_io(void) { fd_set rfds; @@ -508,19 +488,15 @@ int client_manager_io(void) registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); selret = select(fdmax + 1, &rfds, &wfds, &efds, NULL); - if (selret < 0 && errno == EINTR) - break; - - registered_IO_consume_fds(&selret, &rfds, &wfds, &efds); - - if (selret == 0) - break; - if (selret < 0) { - closeNextErroredInterface(); - continue; + if (errno == EINTR) + break; + + FATAL("select() failed: %s\n", strerror(errno)); } + registered_IO_consume_fds(&selret, &rfds, &wfds, &efds); + getConnections(&rfds); list_for_each_entry_safe(client, n, &clients, siblings) { -- cgit v1.2.3 From 827d346899cf0d0d95f8320660944c8f38488b57 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:20:10 +0200 Subject: client: no while loop in client_manager_io() The last patch removed the "continue" directive, and now the while loop is without function. Remove it. Also make client_manager_io() return 0. --- src/client.c | 54 ++++++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 6ee9b988d..f03dd407b 100644 --- a/src/client.c +++ b/src/client.c @@ -476,47 +476,41 @@ int client_manager_io(void) fd_set efds; struct client *client, *n; int selret; - int fdmax; + int fdmax = 0; - while (1) { - fdmax = 0; + FD_ZERO( &efds ); + client_manager_register_read_fd(&rfds, &fdmax); + client_manager_register_write_fd(&wfds, &fdmax); - FD_ZERO( &efds ); - client_manager_register_read_fd(&rfds, &fdmax); - client_manager_register_write_fd(&wfds, &fdmax); + registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); - registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); + selret = select(fdmax + 1, &rfds, &wfds, &efds, NULL); + if (selret < 0) { + if (errno == EINTR) + return 0; - selret = select(fdmax + 1, &rfds, &wfds, &efds, NULL); - if (selret < 0) { - if (errno == EINTR) - break; - - FATAL("select() failed: %s\n", strerror(errno)); - } + FATAL("select() failed: %s\n", strerror(errno)); + } - registered_IO_consume_fds(&selret, &rfds, &wfds, &efds); + registered_IO_consume_fds(&selret, &rfds, &wfds, &efds); - getConnections(&rfds); + getConnections(&rfds); - list_for_each_entry_safe(client, n, &clients, siblings) { - if (FD_ISSET(client->fd, &rfds)) { - if (COMMAND_RETURN_KILL == - client_read(client)) { - return COMMAND_RETURN_KILL; - } - client->lastTime = time(NULL); - } - if (FD_ISSET(client->fd, &wfds)) { - client_write_deferred(client); - client->lastTime = time(NULL); + list_for_each_entry_safe(client, n, &clients, siblings) { + if (FD_ISSET(client->fd, &rfds)) { + if (COMMAND_RETURN_KILL == + client_read(client)) { + return COMMAND_RETURN_KILL; } + client->lastTime = time(NULL); + } + if (FD_ISSET(client->fd, &wfds)) { + client_write_deferred(client); + client->lastTime = time(NULL); } - - break; } - return 1; + return 0; } void client_manager_init(void) -- cgit v1.2.3 From 9567f849e514940da6c2c6da52dde932b7b2fb48 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:20:10 +0200 Subject: client: moved "expired" accesses into inline function Hiding this flag allows us later to remove it easily. --- src/client.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index f03dd407b..f1e3685c0 100644 --- a/src/client.c +++ b/src/client.c @@ -131,6 +131,16 @@ static void set_send_buf_size(struct client *client) } } +static inline int client_is_expired(const struct client *client) +{ + return client->expired; +} + +static inline void client_set_expired(struct client *client) +{ + client->expired = 1; +} + static void client_init(struct client *client, int fd) { static unsigned int next_client_num; @@ -307,19 +317,25 @@ static int client_process_line(struct client *client) if (client->cmd_list_OK >= 0) { if (strcmp(line, CLIENT_LIST_MODE_END) == 0) { + int expired; + DEBUG("client %i: process command " "list\n", client->num); ret = processListOfCommands(client->fd, &(client->permission), - &(client->expired), + &(expired), client->cmd_list_OK, client->cmd_list); DEBUG("client %i: process command " "list returned %i\n", client->num, ret); + + if (expired) + client_set_expired(client); + if (ret == 0) commandSuccess(client->fd); else if (ret == COMMAND_RETURN_CLOSE - || client->expired) + || client_is_expired(client)) client_close(client); client_write_output(client); @@ -361,7 +377,7 @@ static int client_process_line(struct client *client) if (ret == 0) commandSuccess(client->fd); else if (ret == COMMAND_RETURN_CLOSE - || client->expired) { + || client_is_expired(client)) { client_close(client); } client_write_output(client); @@ -387,7 +403,7 @@ static int client_input_received(struct client *client, int bytesRead) *(buf_tail - 1) = '\0'; } ret = client_process_line(client); - if (client->expired) + if (client_is_expired(client)) return ret; client->bufferPos = client->bufferLength; } @@ -445,7 +461,7 @@ static void client_manager_register_read_fd(fd_set * fds, int *fdmax) addListenSocketsToFdSet(fds, fdmax); list_for_each_entry(client, &clients, siblings) { - if (!client->expired && !client->deferred_send) { + if (!client_is_expired(client) && !client->deferred_send) { FD_SET(client->fd, fds); if (*fdmax < client->fd) *fdmax = client->fd; @@ -460,7 +476,7 @@ static void client_manager_register_write_fd(fd_set * fds, int *fdmax) FD_ZERO(fds); list_for_each_entry(client, &clients, siblings) { - if (client->fd >= 0 && !client->expired + if (client->fd >= 0 && !client_is_expired(client) && client->deferred_send) { FD_SET(client->fd, fds); if (*fdmax < client->fd) @@ -590,7 +606,7 @@ void client_manager_expire(void) struct client *client, *n; list_for_each_entry_safe(client, n, &clients, siblings) { - if (client->expired) { + if (client_is_expired(client)) { DEBUG("client %i: expired\n", client->num); client_close(client); } else if (time(NULL) - client->lastTime > @@ -637,7 +653,7 @@ static void client_write_deferred(struct client *client) /* cause client to close */ DEBUG("client %i: problems flushing buffer\n", client->num); - client->expired = 1; + client_set_expired(client); } } @@ -664,10 +680,10 @@ int client_print(int fd, const char *buffer, size_t buflen) return -1; /* if fd isn't found or client is going to be closed, do nothing */ - if (client->expired) + if (client_is_expired(client)) return 0; - while (buflen > 0 && !client->expired) { + while (buflen > 0 && !client_is_expired(client)) { size_t left; assert(client->send_buf_size >= client->send_buf_used); @@ -701,7 +717,7 @@ static void client_defer_output(struct client *client, (unsigned long)client->deferred_bytes, (unsigned long)client_max_output_buffer_size); /* cause client to close */ - client->expired = 1; + client_set_expired(client); return; } @@ -723,7 +739,7 @@ static void client_write(struct client *client, client_defer_output(client, data, length); } else { DEBUG("client %i: problems writing\n", client->num); - client->expired = 1; + client_set_expired(client); return; } } else if ((size_t)ret < client->send_buf_used) { @@ -736,7 +752,7 @@ static void client_write(struct client *client, static void client_write_output(struct client *client) { - if (client->expired || !client->send_buf_used) + if (client_is_expired(client) || !client->send_buf_used) return; if (client->deferred_send != NULL) -- cgit v1.2.3 From 9e35e50f856038e231e06a5f3d85ff1545053438 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:20:10 +0200 Subject: client: replace "expired" flag with fd==-1 Why waste 4 bytes for a flag which we can hide in another variable. --- src/client.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index f1e3685c0..ba15a90de 100644 --- a/src/client.c +++ b/src/client.c @@ -66,7 +66,7 @@ struct client { char buffer[CLIENT_MAX_BUFFER_LENGTH]; size_t bufferLength; size_t bufferPos; - int fd; /* file descriptor */ + int fd; /* file descriptor; -1 if expired */ int permission; time_t lastTime; struct strnode *cmd_list; /* for when in list mode */ @@ -76,8 +76,6 @@ struct client { int cmd_list_dup; /* has the cmd_list been copied to private space? */ struct sllnode *deferred_send; /* for output if client is slow */ size_t deferred_bytes; /* mem deferred_send consumes */ - int expired; /* set whether this client should be closed on next - check of old clients */ unsigned int num; /* client number */ char *send_buf; @@ -133,12 +131,15 @@ static void set_send_buf_size(struct client *client) static inline int client_is_expired(const struct client *client) { - return client->expired; + return client->fd < 0; } static inline void client_set_expired(struct client *client) { - client->expired = 1; + if (client->fd >= 0) { + xclose(client->fd); + client->fd = -1; + } } static void client_init(struct client *client, int fd) @@ -156,7 +157,6 @@ static void client_init(struct client *client, int fd) client->cmd_list = NULL; client->cmd_list_tail = NULL; client->deferred_send = NULL; - client->expired = 0; client->deferred_bytes = 0; client->num = next_client_num++; client->send_buf_used = 0; -- cgit v1.2.3 From 692cfc5c36ddff07888d1c2e7ecefda8be8ead47 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:20:10 +0200 Subject: client: moved code to sockaddr_to_tmp_string() Unclutter the client_new() constructor by moving unrelated complex code into a separate function. --- src/client.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index ba15a90de..f34d64b88 100644 --- a/src/client.c +++ b/src/client.c @@ -258,16 +258,10 @@ static void client_close(struct client *client) free(client); } -void client_new(int fd, const struct sockaddr *addr) +static const char * +sockaddr_to_tmp_string(const struct sockaddr *addr) { const char *hostname; - struct client *client; - - if (num_clients >= client_max_connections) { - ERROR("Max Connections Reached!\n"); - xclose(fd); - return; - } switch (addr->sa_family) { #ifdef HAVE_TCP @@ -303,11 +297,25 @@ void client_new(int fd, const struct sockaddr *addr) hostname = "unknown"; } + return hostname; +} + +void client_new(int fd, const struct sockaddr *addr) +{ + struct client *client; + + if (num_clients >= client_max_connections) { + ERROR("Max Connections Reached!\n"); + xclose(fd); + return; + } + 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); + SECURE("client %i: opened from %s\n", client->num, + sockaddr_to_tmp_string(addr)); } static int client_process_line(struct client *client) -- cgit v1.2.3 From 557679eba7e6daae37e90c645b1e69174fb1456c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 Aug 2008 20:23:22 +0200 Subject: client: more assertions --- src/client.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/client.c b/src/client.c index f34d64b88..51f3e8e3b 100644 --- a/src/client.c +++ b/src/client.c @@ -146,6 +146,8 @@ static void client_init(struct client *client, int fd) { static unsigned int next_client_num; + assert(fd >= 0); + client->cmd_list_size = 0; client->cmd_list_dup = 0; client->cmd_list_OK = -1; @@ -632,6 +634,8 @@ static void client_write_deferred(struct client *client) buf = client->deferred_send; while (buf) { + assert(buf->size > 0); + ret = write(client->fd, buf->data, buf->size); if (ret < 0) break; @@ -715,6 +719,7 @@ static void client_defer_output(struct client *client, { struct sllnode **buf_r; + assert(length > 0); assert(client->deferred_send != NULL); client->deferred_bytes += sizeof(struct sllnode) + length; @@ -740,6 +745,7 @@ static void client_write(struct client *client, { ssize_t ret; + assert(length > 0); assert(client->deferred_send == NULL); if ((ret = write(client->fd, data, length)) < 0) { -- cgit v1.2.3 From 421fced5f9484a288fdc4f3ab33dfd4bfbfb7e84 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 29 Aug 2008 06:17:54 +0200 Subject: client: removed superfluous assertion client_defer_output() was modified so that it can create the deferred_send list. With this patch, the assertion on "deferred_send!=NULL" has become invalid. Remove it. --- src/client.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 51f3e8e3b..3a96e4caf 100644 --- a/src/client.c +++ b/src/client.c @@ -720,7 +720,6 @@ static void client_defer_output(struct client *client, struct sllnode **buf_r; assert(length > 0); - assert(client->deferred_send != NULL); client->deferred_bytes += sizeof(struct sllnode) + length; if (client->deferred_bytes > client_max_output_buffer_size) { -- cgit v1.2.3 From 4ad71d6f79dfd8700441a5b3334e10ae5ab9f157 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 29 Aug 2008 09:36:38 +0200 Subject: client: added global "expired" flag Patch bdeb8e14 ("client: moved "expired" accesses into inline function") was created under the wrong assumption that processListOfCommands() could modify the expired flag, which is not the case. Although "expired" is a non-const pointer, processListOfCommands() just reads it, using it as the break condition in a "while" loop. I will address this issue with a better overall solution, but for now provide a pointer to a global "expired" flag. --- src/client.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 3a96e4caf..bce0acd5e 100644 --- a/src/client.c +++ b/src/client.c @@ -134,12 +134,16 @@ static inline int client_is_expired(const struct client *client) return client->fd < 0; } +static int global_expired; + static inline void client_set_expired(struct client *client) { if (client->fd >= 0) { xclose(client->fd); client->fd = -1; } + + global_expired = 1; } static void client_init(struct client *client, int fd) @@ -327,21 +331,18 @@ static int client_process_line(struct client *client) if (client->cmd_list_OK >= 0) { if (strcmp(line, CLIENT_LIST_MODE_END) == 0) { - int expired; - DEBUG("client %i: process command " "list\n", client->num); + + global_expired = 0; ret = processListOfCommands(client->fd, &(client->permission), - &(expired), + &global_expired, client->cmd_list_OK, client->cmd_list); DEBUG("client %i: process command " "list returned %i\n", client->num, ret); - if (expired) - client_set_expired(client); - if (ret == 0) commandSuccess(client->fd); else if (ret == COMMAND_RETURN_CLOSE -- cgit v1.2.3 From 69af10a006bf9e67f4689642e06bae24f67e873d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 29 Aug 2008 09:36:40 +0200 Subject: client: check "expired" after command execution The old code tried to write a response to the client, without even checking if it was already closed. Now that we have added more assertions, these may fail... perform the "expired" check earlier. --- src/client.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index bce0acd5e..6a43b9586 100644 --- a/src/client.c +++ b/src/client.c @@ -343,11 +343,14 @@ static int client_process_line(struct client *client) DEBUG("client %i: process command " "list returned %i\n", client->num, ret); + if (ret == COMMAND_RETURN_CLOSE || + client_is_expired(client)) { + client_close(client); + return COMMAND_RETURN_CLOSE; + } + if (ret == 0) commandSuccess(client->fd); - else if (ret == COMMAND_RETURN_CLOSE - || client_is_expired(client)) - client_close(client); client_write_output(client); free_cmd_list(client->cmd_list); @@ -385,12 +388,16 @@ static int client_process_line(struct client *client) &(client->permission), line); DEBUG("client %i: command returned %i\n", client->num, ret); - if (ret == 0) - commandSuccess(client->fd); - else if (ret == COMMAND_RETURN_CLOSE - || client_is_expired(client)) { + + if (ret == COMMAND_RETURN_CLOSE || + client_is_expired(client)) { client_close(client); + return COMMAND_RETURN_CLOSE; } + + if (ret == 0) + commandSuccess(client->fd); + client_write_output(client); } } -- cgit v1.2.3 From 0e645468c6249800f573efaa4bca94753245d7e0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 29 Aug 2008 09:36:40 +0200 Subject: client: reorder function declarations Change the order of function declarations in client.h, to make it well arranged and readable. --- src/client.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client.h b/src/client.h index 64639b2af..a4cb4a902 100644 --- a/src/client.h +++ b/src/client.h @@ -22,11 +22,12 @@ #include "os_compat.h" void client_manager_init(void); -void client_new(int fd, const struct sockaddr *addr); void client_manager_deinit(void); +int client_manager_io(void); void client_manager_expire(void); -int client_print(int fd, const char *buffer, size_t len); -int client_manager_io(void); +void client_new(int fd, const struct sockaddr *addr); + +int client_print(int fd, const char *buffer, size_t len); #endif -- cgit v1.2.3