* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
- * $Id: commio.c 1779 2006-07-30 16:36:39Z jilles $
+ * $Id: commio.c 3354 2007-04-03 09:21:31Z nenolod $
*/
#include "libcharybdis.h"
"Comm Error"
};
-fde_t *fd_table = NULL;
+#define FD_HASH_SIZE 128
+static dlink_list fd_table[FD_HASH_SIZE];
static void fdlist_update_biggest(int fd, int opening);
static PF comm_connect_timeout;
static void comm_connect_dns_callback(void *vptr, struct DNSReply *reply);
static PF comm_connect_tryconnect;
+static int comm_max_connections = 0;
+
+static int
+comm_read_raw(fde_t *F, void *buf, size_t count)
+{
+ s_assert(F != NULL);
+ s_assert(buf != NULL);
+ s_assert(count > 0);
+
+ return read(F->fd, buf, count);
+}
+
+static int
+comm_write_raw(fde_t *F, const void *buf, size_t count)
+{
+ s_assert(F != NULL);
+ s_assert(buf != NULL);
+ s_assert(count > 0);
+
+ return write(F->fd, buf, count);
+}
+
+inline fde_t *
+comm_locate_fd(int fd)
+{
+ int bucket = fd % FD_HASH_SIZE;
+ dlink_list *list = &fd_table[bucket];
+ dlink_node *n;
+
+ DLINK_FOREACH(n, list->head)
+ {
+ fde_t *F = (fde_t *) n->data;
+
+ if (F->fd == fd)
+ return F;
+ }
+
+ return NULL;
+}
+
+inline fde_t *
+comm_add_fd(int fd)
+{
+ fde_t *F = comm_locate_fd(fd);
+ dlink_list *list;
+
+ if (F != NULL)
+ return F;
+
+ F = MyMalloc(sizeof(fde_t));
+ F->fd = fd;
+
+ F->read_impl = comm_read_raw;
+ F->write_impl = comm_write_raw;
+
+ list = &fd_table[fd % FD_HASH_SIZE];
+ dlinkAdd(F, &F->node, list);
+
+ return F;
+}
+
+inline void
+comm_remove_fd(int fd)
+{
+ int bucket = fd % FD_HASH_SIZE;
+ fde_t *F;
+ dlink_list *list = &fd_table[bucket];
+
+ F = comm_locate_fd(fd);
+ if (F == NULL)
+ return;
+
+ dlinkDelete(&F->node, list);
+ MyFree(F);
+}
/* 32bit solaris is kinda slow and stdio only supports fds < 256
* so we got to do this crap below.
* (BTW Fuck you Sun, I hate your guts and I hope you go bankrupt soon)
+ * XXX: this is no longer needed in Solaris 10. --nenolod
*/
#if defined (__SVR4) && defined (__sun)
static void comm_fd_hack(int *fd)
int fd;
#endif
- /* XXX someone tell me why we care about 4 fd's ? */
- /* XXX btw, fd 3 is used for profiler ! */
-
- for (i = 4; i < MAXCONNECTIONS; ++i)
+ /*
+ * we start at 4 to avoid giving fds where malloc messages
+ * could be written --nenolod
+ */
+ for (i = 4; i < comm_max_connections; ++i)
{
- if(fd_table[i].flags.open)
+ fde_t *F = comm_locate_fd(i);
+
+ if(F != NULL && F->flags.open)
comm_close(i);
else
close(i);
{
int nonb = 0;
int res;
+ fde_t *F = comm_locate_fd(fd);
nonb |= O_NONBLOCK;
res = fcntl(fd, F_GETFL, 0);
if(-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
return 0;
- fd_table[fd].flags.nonblocking = 1;
+ if (F != NULL)
+ F->flags.nonblocking = 1;
+
return 1;
}
{
fde_t *F;
s_assert(fd >= 0);
- F = &fd_table[fd];
+ F = comm_locate_fd(fd);
s_assert(F->flags.open);
F->timeout = CurrentTime + (timeout / 1000);
{
fde_t *F;
s_assert(fd >= 0);
- F = &fd_table[fd];
+ F = comm_locate_fd(fd);
s_assert(F->flags.open);
F->flush_timeout = CurrentTime + (timeout / 1000);
void
comm_checktimeouts(void *notused)
{
- int fd;
PF *hdl;
void *data;
fde_t *F;
- for (fd = 0; fd <= highest_fd; fd++)
+ dlink_list *bucket;
+ int i;
+ dlink_node *n, *n2;
+
+ for (i = 0; i <= FD_HASH_SIZE; i++)
{
- F = &fd_table[fd];
- if(!F->flags.open)
- continue;
- if(F->flags.closing)
- continue;
+ bucket = &fd_table[i];
- /* check flush functions */
- if(F->flush_handler &&
- F->flush_timeout > 0 && F->flush_timeout < CurrentTime)
- {
- hdl = F->flush_handler;
- data = F->flush_data;
- comm_setflush(F->fd, 0, NULL, NULL);
- hdl(F->fd, data);
- }
+ if (dlink_list_length(bucket) <= 0)
+ continue;
- /* check timeouts */
- if(F->timeout_handler &&
- F->timeout > 0 && F->timeout < CurrentTime)
+ DLINK_FOREACH_SAFE(n, n2, bucket->head)
{
- /* Call timeout handler */
- hdl = F->timeout_handler;
- data = F->timeout_data;
- comm_settimeout(F->fd, 0, NULL, NULL);
- hdl(F->fd, data);
+ F = (fde_t *) n->data;
+
+ if(F == NULL)
+ continue;
+ if(!F->flags.open)
+ continue;
+ if(F->flags.closing)
+ continue;
+
+ /* check flush functions */
+ if(F->flush_handler &&
+ F->flush_timeout > 0 && F->flush_timeout < CurrentTime)
+ {
+ hdl = F->flush_handler;
+ data = F->flush_data;
+ comm_setflush(F->fd, 0, NULL, NULL);
+ hdl(F->fd, data);
+ }
+
+ /* check timeouts */
+ if(F->timeout_handler &&
+ F->timeout > 0 && F->timeout < CurrentTime)
+ {
+ /* Call timeout handler */
+ hdl = F->timeout_handler;
+ data = F->timeout_data;
+ comm_settimeout(F->fd, 0, NULL, NULL);
+ hdl(F->fd, data);
+ }
}
}
}
void *ipptr = NULL;
fde_t *F;
s_assert(fd >= 0);
- F = &fd_table[fd];
+ F = comm_locate_fd(fd);
F->flags.called_connect = 1;
s_assert(callback);
F->connect.callback = callback;
comm_connect_callback(int fd, int status)
{
CNCB *hdl;
- fde_t *F = &fd_table[fd];
+ fde_t *F = comm_locate_fd(fd);
+
/* This check is gross..but probably necessary */
- if(F->connect.callback == NULL)
+ if(F == NULL || F->connect.callback == NULL)
return;
+
/* Clear the connect flag + handler */
hdl = F->connect.callback;
F->connect.callback = NULL;
comm_connect_tryconnect(int fd, void *notused)
{
int retval;
- fde_t *F = &fd_table[fd];
+ fde_t *F = comm_locate_fd(fd);
if(F->connect.callback == NULL)
return;
/* Try the connect() */
- retval = connect(fd, (struct sockaddr *) &fd_table[fd].connect.hostaddr,
- GET_SS_LEN(fd_table[fd].connect.hostaddr));
+ retval = connect(fd, (struct sockaddr *) &F->connect.hostaddr,
+ GET_SS_LEN(F->connect.hostaddr));
/* Error? */
if(retval < 0)
{
{
int fd;
/* First, make sure we aren't going to run out of file descriptors */
- if(number_fd >= MASTER_MAX)
+ if(number_fd >= comm_max_connections)
{
errno = ENFILE;
return -1;
comm_accept(int fd, struct sockaddr *pn, socklen_t *addrlen)
{
int newfd;
- if(number_fd >= MASTER_MAX)
+ if(number_fd >= comm_max_connections)
{
errno = ENFILE;
return -1;
{
if(fd < highest_fd)
return;
- s_assert(fd < MAXCONNECTIONS);
+ s_assert(fd < comm_max_connections);
if(fd > highest_fd)
{
* re-opening it
*/
s_assert(!opening);
- while (highest_fd >= 0 && !fd_table[highest_fd].flags.open)
+ while (highest_fd >= 0 && comm_locate_fd(fd) != NULL)
highest_fd--;
}
fdlist_init(void)
{
static int initialized = 0;
+ struct rlimit limit;
if(!initialized)
{
- /* Since we're doing this once .. */
- fd_table = MyMalloc((MAXCONNECTIONS + 1) * sizeof(fde_t));
+ memset(&fd_table, '\0', sizeof(dlink_list) * FD_HASH_SIZE);
+
+ /* set up comm_max_connections. */
+ if(!getrlimit(RLIMIT_NOFILE, &limit))
+ comm_max_connections = limit.rlim_cur;
+
initialized = 1;
}
}
void
comm_open(int fd, unsigned int type, const char *desc)
{
- fde_t *F = &fd_table[fd];
+ fde_t *F = comm_add_fd(fd);
s_assert(fd >= 0);
if(F->flags.open)
void
comm_close(int fd)
{
- fde_t *F = &fd_table[fd];
+ fde_t *F = comm_locate_fd(fd);
s_assert(F->flags.open);
/* All disk fd's MUST go through file_close() ! */
s_assert(F->type != FD_FILE);
}
comm_setselect(F->fd, FDLIST_NONE, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0);
comm_setflush(F->fd, 0, NULL, NULL);
+ F->timeout = 0;
if (F->dns_query != NULL)
{
F->flags.open = 0;
fdlist_update_biggest(fd, 0);
number_fd--;
- memset(F, '\0', sizeof(fde_t));
- F->timeout = 0;
+ comm_remove_fd(fd);
+
/* Unlike squid, we're actually closing the FD here! -- adrian */
close(fd);
}
-
/*
* comm_dump() - dump the list of active filedescriptors
*/
{
int i;
- for (i = 0; i <= highest_fd; i++)
+ for (i = 0; i <= FD_HASH_SIZE; i++)
{
- if(!fd_table[i].flags.open)
+ dlink_node *n;
+
+ if (dlink_list_length(&fd_table[i]) <= 0)
continue;
- sendto_one_numeric(source_p, RPL_STATSDEBUG,
- "F :fd %-3d desc '%s'",
- i, fd_table[i].desc);
+ DLINK_FOREACH(n, fd_table[i].head)
+ {
+ fde_t *F = (fde_t *) n->data;
+
+ if(F == NULL || !F->flags.open)
+ continue;
+
+ sendto_one_numeric(source_p, RPL_STATSDEBUG,
+ "F :fd %-3d bucket %-3d desc '%s'",
+ F->fd, i, F->desc);
+ }
}
}
comm_note(int fd, const char *format, ...)
{
va_list args;
+ fde_t *F = comm_add_fd(fd); /* XXX: epoll, kqueue. */
if(format)
{
va_start(args, format);
- ircvsnprintf(fd_table[fd].desc, FD_DESC_SZ, format, args);
+ ircvsnprintf(F->desc, FD_DESC_SZ, format, args);
va_end(args);
}
else
- fd_table[fd].desc[0] = '\0';
+ F->desc[0] = '\0';
}
+extern int
+comm_get_maxconnections(void)
+{
+ fdlist_init();
+ return comm_max_connections;
+}