libratbox is the new libcharybdis... thanks to androsyn and jilles on making something sane where previous attempts failed. ;)

This commit is contained in:
William Pitcock 2008-04-01 19:35:46 -05:00
parent 954012d39b
commit 5ae4cce9e1
21 changed files with 0 additions and 6147 deletions

View file

@ -1,87 +0,0 @@
#
# Makefile.in for ircd/src/io
#
# $Id: Makefile.in 1269 2006-04-30 16:51:11Z nenolod $
#
CC = @CC@
INSTALL = @INSTALL@
INSTALL_BIN = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SUID = @INSTALL_PROGRAM@ -o root -m 4755
RM = @RM@
LEX = @LEX@
LEXLIB = @LEXLIB@
CFLAGS = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
LDFLAGS = @LDFLAGS@
MKDEP = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
MV = @MV@
RM = @RM@
YACC = @YACC@
AR = @AR@
RANLIB = @RANLIB@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libexecdir = @libexecdir@
sysconfdir = @sysconfdir@
localstatedir = @localstatedir@
# Change this later! -- adrian
moduledir = @prefix@/modules
automoduledir = @prefix@/modules/autoload
INCLUDES = -I../include -I../adns -I.
CPPFLAGS = ${INCLUDES} @CPPFLAGS@
default: all
BASE_SRCS = \
balloc.c \
commio.c \
event.c \
libcharybdis.c \
linebuf.c \
memory.c \
snprintf.c \
tools.c
SRCS = ${BASE_SRCS} @SELECT_TYPE@.c
OBJS = ${SRCS:.c=.o}
all: libcharybdis.a
build: all
libcharybdis.a: ${OBJS}
rm -f $@
${AR} cqv $@ ${OBJS}
${RANLIB} $@
# this is really the default rule for c files
.c.o:
${CC} ${CPPFLAGS} ${CFLAGS} -c $<
.PHONY: depend clean distclean
install:
depend:
@${MKDEP} ${CPPFLAGS} ${BASE_SRCS} ${EXTRA_SRCS} > .depend.tmp
@sed -e '/^# DO NOT DELETE THIS LINE/,$$d' <Makefile >Makefile.depend
@echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend
@echo '# make depend needs it.' >>Makefile.depend
@cat .depend.tmp >>Makefile.depend
@mv Makefile.depend Makefile
@rm -f .depend.tmp
clean:
${RM} -f *.o *.exe *~ libcharybdis.a
lint:
distclean: clean
${RM} -f Makefile version.c.last
# DO NOT DELETE THIS LINE!!!
# make depend needs it.

View file

@ -1,652 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* balloc.c: A block allocator.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* File: blalloc.c
* Owner: Wohali (Joan Touzet)
*
* Modified 2001/11/29 for mmap() support by Aaron Sethman <androsyn@ratbox.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
*
* $Id: balloc.c 388 2005-12-07 16:34:40Z nenolod $
*/
/*
* About the block allocator
*
* Basically we have three ways of getting memory off of the operating
* system. Below are this list of methods and the order of preference.
*
* 1. mmap() anonymous pages with the MMAP_ANON flag.
* 2. mmap() via the /dev/zero trick.
* 3. malloc()
*
* The advantages of 1 and 2 are this. We can munmap() the pages which will
* return the pages back to the operating system, thus reducing the size
* of the process as the memory is unused. malloc() on many systems just keeps
* a heap of memory to itself, which never gets given back to the OS, except on
* exit. This of course is bad, if say we have an event that causes us to allocate
* say, 200MB of memory, while our normal memory consumption would be 15MB. In the
* malloc() case, the amount of memory allocated to our process never goes down, as
* malloc() has it locked up in its heap. With the mmap() method, we can munmap()
* the block and return it back to the OS, thus causing our memory consumption to go
* down after we no longer need it.
*
* Of course it is up to the caller to make sure BlockHeapGarbageCollect() gets
* called periodically to do this cleanup, otherwise you'll keep the memory in the
* process.
*
*
*/
#include "stdinc.h"
#include "libcharybdis.h"
#define WE_ARE_MEMORY_C
#include "setup.h"
#include "balloc.h"
#ifndef NOBALLOC
#include "ircd_defs.h" /* DEBUG_BLOCK_ALLOCATOR */
#include "ircd.h"
#include "memory.h"
#include "irc_string.h"
#include "tools.h"
#include "s_log.h"
#include "client.h"
#include "event.h"
#ifdef HAVE_MMAP /* We've got mmap() that is good */
#include <sys/mman.h>
/* HP-UX sucks */
#ifdef MAP_ANONYMOUS
#ifndef MAP_ANON
#define MAP_ANON MAP_ANONYMOUS
#endif
#endif
#endif
static int newblock(BlockHeap * bh);
static int BlockHeapGarbageCollect(BlockHeap *);
static void block_heap_gc(void *unused);
static dlink_list heap_lists;
#if defined(HAVE_MMAP) && !defined(MAP_ANON)
static int zero_fd = -1;
#endif
#define blockheap_fail(x) _blockheap_fail(x, __FILE__, __LINE__)
static void
_blockheap_fail(const char *reason, const char *file, int line)
{
libcharybdis_log("Blockheap failure: %s (%s:%d)", reason, file, line);
abort();
}
/*
* static inline void free_block(void *ptr, size_t size)
*
* Inputs: The block and its size
* Output: None
* Side Effects: Returns memory for the block back to the OS
*/
static inline void
free_block(void *ptr, size_t size)
{
#ifdef HAVE_MMAP
munmap(ptr, size);
#else
free(ptr);
#endif
}
#ifdef DEBUG_BALLOC
/* Check the list length the very slow way */
static unsigned long
slow_list_length(dlink_list *list)
{
dlink_node *ptr;
unsigned long count = 0;
for (ptr = list->head; ptr; ptr = ptr->next)
{
count++;
if(count > list->length * 2)
{
blockheap_fail("count > list->length * 2 - I give up");
}
}
return count;
}
static void
bh_sanity_check_block(BlockHeap *bh, Block *block)
{
unsigned long s_used, s_free;
s_used = slow_list_length(&block->used_list);
s_free = slow_list_length(&block->free_list);
if(s_used != dlink_list_length(&block->used_list))
blockheap_fail("used link count doesn't match head count");
if(s_free != dlink_list_length(&block->free_list))
blockheap_fail("free link count doesn't match head count");
if(dlink_list_length(&block->used_list) + dlink_list_length(&block->free_list) != bh->elemsPerBlock)
blockheap_fail("used_list + free_list != elemsPerBlock");
}
#if 0
/* See how confused we are */
static void
bh_sanity_check(BlockHeap *bh)
{
Block *walker;
unsigned long real_alloc = 0;
unsigned long s_used, s_free;
unsigned long blockcount = 0;
unsigned long allocated;
if(bh == NULL)
blockheap_fail("Trying to sanity check a NULL block");
allocated = bh->blocksAllocated * bh->elemsPerBlock;
for(walker = bh->base; walker != NULL; walker = walker->next)
{
blockcount++;
s_used = slow_list_length(&walker->used_list);
s_free = slow_list_length(&walker->free_list);
if(s_used != dlink_list_length(&walker->used_list))
blockheap_fail("used link count doesn't match head count");
if(s_free != dlink_list_length(&walker->free_list))
blockheap_fail("free link count doesn't match head count");
if(dlink_list_length(&walker->used_list) + dlink_list_length(&walker->free_list) != bh->elemsPerBlock)
blockheap_fail("used_list + free_list != elemsPerBlock");
real_alloc += dlink_list_length(&walker->used_list);
real_alloc += dlink_list_length(&walker->free_list);
}
if(allocated != real_alloc)
blockheap_fail("block allocations don't match heap");
if(bh->blocksAllocated != blockcount)
blockheap_fail("blocksAllocated don't match blockcount");
}
static void
bh_sanity_check_all(void *unused)
{
dlink_node *ptr;
DLINK_FOREACH(ptr, heap_lists.head)
{
bh_sanity_check(ptr->data);
}
}
#endif
#endif
/*
* void initBlockHeap(void)
*
* Inputs: None
* Outputs: None
* Side Effects: Initializes the block heap
*/
void
initBlockHeap(void)
{
#if defined(HAVE_MMAP) && !defined(MAP_ANON)
zero_fd = open("/dev/zero", O_RDWR);
if(zero_fd < 0)
blockheap_fail("Failed opening /dev/zero");
comm_socket(zero_fd, FD_FILE, "Anonymous mmap()");
#endif
eventAddIsh("block_heap_gc", block_heap_gc, NULL, 30);
}
/*
* static inline void *get_block(size_t size)
*
* Input: Size of block to allocate
* Output: Pointer to new block
* Side Effects: None
*/
static inline void *
get_block(size_t size)
{
void *ptr;
#ifdef HAVE_MMAP
#ifdef MAP_ANON
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
#else
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
#endif
if(ptr == MAP_FAILED)
{
ptr = NULL;
}
#else
ptr = malloc(size);
#endif
return (ptr);
}
static void
block_heap_gc(void *unused)
{
dlink_node *ptr;
DLINK_FOREACH(ptr, heap_lists.head)
{
BlockHeapGarbageCollect(ptr->data);
}
}
/* ************************************************************************ */
/* FUNCTION DOCUMENTATION: */
/* newblock */
/* Description: */
/* Allocates a new block for addition to a blockheap */
/* Parameters: */
/* bh (IN): Pointer to parent blockheap. */
/* Returns: */
/* 0 if successful, 1 if not */
/* ************************************************************************ */
static int
newblock(BlockHeap * bh)
{
MemBlock *newblk;
Block *b;
unsigned long i;
void *offset;
/* Setup the initial data structure. */
b = (Block *) calloc(1, sizeof(Block));
if(b == NULL)
{
return (1);
}
b->free_list.head = b->free_list.tail = NULL;
b->used_list.head = b->used_list.tail = NULL;
b->next = bh->base;
b->alloc_size = (bh->elemsPerBlock + 1) * (bh->elemSize + sizeof(MemBlock));
b->elems = get_block(b->alloc_size);
if(b->elems == NULL)
{
return (1);
}
offset = b->elems;
/* Setup our blocks now */
for (i = 0; i < bh->elemsPerBlock; i++)
{
void *data;
newblk = (void *) offset;
newblk->block = b;
#ifdef DEBUG_BALLOC
newblk->magic = BALLOC_MAGIC;
#endif
data = (void *) ((size_t) offset + sizeof(MemBlock));
newblk->block = b;
dlinkAdd(data, &newblk->self, &b->free_list);
offset = (unsigned char *) ((unsigned char *) offset +
bh->elemSize + sizeof(MemBlock));
}
++bh->blocksAllocated;
bh->freeElems += bh->elemsPerBlock;
bh->base = b;
return (0);
}
/* ************************************************************************ */
/* FUNCTION DOCUMENTATION: */
/* BlockHeapCreate */
/* Description: */
/* Creates a new blockheap from which smaller blocks can be allocated. */
/* Intended to be used instead of multiple calls to malloc() when */
/* performance is an issue. */
/* Parameters: */
/* elemsize (IN): Size of the basic element to be stored */
/* elemsperblock (IN): Number of elements to be stored in a single block */
/* of memory. When the blockheap runs out of free memory, it will */
/* allocate elemsize * elemsperblock more. */
/* Returns: */
/* Pointer to new BlockHeap, or NULL if unsuccessful */
/* ************************************************************************ */
BlockHeap *
BlockHeapCreate(size_t elemsize, int elemsperblock)
{
BlockHeap *bh;
s_assert(elemsize > 0 && elemsperblock > 0);
/* Catch idiotic requests up front */
if((elemsize <= 0) || (elemsperblock <= 0))
{
blockheap_fail("Attempting to BlockHeapCreate idiotic sizes");
}
/* Allocate our new BlockHeap */
bh = (BlockHeap *) calloc(1, sizeof(BlockHeap));
if(bh == NULL)
{
blockheap_fail("Attempt to calloc() failed");
outofmemory(); /* die.. out of memory */
}
if((elemsize % sizeof(void *)) != 0)
{
/* Pad to even pointer boundary */
elemsize += sizeof(void *);
elemsize &= ~(sizeof(void *) - 1);
}
bh->elemSize = elemsize;
bh->elemsPerBlock = elemsperblock;
bh->blocksAllocated = 0;
bh->freeElems = 0;
bh->base = NULL;
/* Be sure our malloc was successful */
if(newblock(bh))
{
if(bh != NULL)
free(bh);
libcharybdis_restart("Aiee! -- newblock() failed!!!");
}
if(bh == NULL)
{
blockheap_fail("bh == NULL when it shouldn't be");
}
dlinkAdd(bh, &bh->hlist, &heap_lists);
return (bh);
}
/* ************************************************************************ */
/* FUNCTION DOCUMENTATION: */
/* BlockHeapAlloc */
/* Description: */
/* Returns a pointer to a struct within our BlockHeap that's free for */
/* the taking. */
/* Parameters: */
/* bh (IN): Pointer to the Blockheap. */
/* Returns: */
/* Pointer to a structure (void *), or NULL if unsuccessful. */
/* ************************************************************************ */
void *
BlockHeapAlloc(BlockHeap * bh)
{
Block *walker;
dlink_node *new_node;
s_assert(bh != NULL);
if(bh == NULL)
{
blockheap_fail("Cannot allocate if bh == NULL");
}
if(bh->freeElems == 0)
{
/* Allocate new block and assign */
/* newblock returns 1 if unsuccessful, 0 if not */
if(newblock(bh))
{
/* That didn't work..try to garbage collect */
BlockHeapGarbageCollect(bh);
if(bh->freeElems == 0)
{
libcharybdis_restart("newblock() failed and garbage collection didn't help");
}
}
}
for (walker = bh->base; walker != NULL; walker = walker->next)
{
if(dlink_list_length(&walker->free_list) > 0)
{
#ifdef DEBUG_BALLOC
bh_sanity_check_block(bh, walker);
#endif
bh->freeElems--;
new_node = walker->free_list.head;
dlinkMoveNode(new_node, &walker->free_list, &walker->used_list);
s_assert(new_node->data != NULL);
if(new_node->data == NULL)
blockheap_fail("new_node->data is NULL and that shouldn't happen!!!");
memset(new_node->data, 0, bh->elemSize);
#ifdef DEBUG_BALLOC
do
{
struct MemBlock *memblock = (void *) ((size_t) new_node->data - sizeof(MemBlock));
if(memblock->magic == BALLOC_FREE_MAGIC)
memblock->magic = BALLOC_MAGIC;
} while(0);
bh_sanity_check_block(bh, walker);
#endif
return (new_node->data);
}
}
blockheap_fail("BlockHeapAlloc failed, giving up");
return NULL;
}
/* ************************************************************************ */
/* FUNCTION DOCUMENTATION: */
/* BlockHeapFree */
/* Description: */
/* Returns an element to the free pool, does not free() */
/* Parameters: */
/* bh (IN): Pointer to BlockHeap containing element */
/* ptr (in): Pointer to element to be "freed" */
/* Returns: */
/* 0 if successful, 1 if element not contained within BlockHeap. */
/* ************************************************************************ */
int
BlockHeapFree(BlockHeap * bh, void *ptr)
{
Block *block;
struct MemBlock *memblock;
s_assert(bh != NULL);
s_assert(ptr != NULL);
if(bh == NULL)
{
libcharybdis_restart("balloc.c:BlockHeapFree() bh == NULL");
return (1);
}
if(ptr == NULL)
{
libcharybdis_restart("balloc.BlockHeapFree() ptr == NULL");
return (1);
}
memblock = (void *) ((size_t) ptr - sizeof(MemBlock));
#ifdef DEBUG_BALLOC
if(memblock->magic == BALLOC_FREE_MAGIC)
{
blockheap_fail("double free of a block");
outofmemory();
} else
if(memblock->magic != BALLOC_MAGIC)
{
blockheap_fail("memblock->magic != BALLOC_MAGIC");
outofmemory();
}
#endif
s_assert(memblock->block != NULL);
if(memblock->block == NULL)
{
blockheap_fail("memblock->block == NULL, not a valid block?");
outofmemory();
}
block = memblock->block;
#ifdef DEBUG_BALLOC
bh_sanity_check_block(bh, block);
#endif
bh->freeElems++;
mem_frob(ptr, bh->elemSize);
dlinkMoveNode(&memblock->self, &block->used_list, &block->free_list);
#ifdef DEBUG_BALLOC
bh_sanity_check_block(bh, block);
#endif
return (0);
}
/* ************************************************************************ */
/* FUNCTION DOCUMENTATION: */
/* BlockHeapGarbageCollect */
/* Description: */
/* Performs garbage collection on the block heap. Any blocks that are */
/* completely unallocated are removed from the heap. Garbage collection */
/* will never remove the root node of the heap. */
/* Parameters: */
/* bh (IN): Pointer to the BlockHeap to be cleaned up */
/* Returns: */
/* 0 if successful, 1 if bh == NULL */
/* ************************************************************************ */
static int
BlockHeapGarbageCollect(BlockHeap * bh)
{
Block *walker, *last;
if(bh == NULL)
{
return (1);
}
if(bh->freeElems < bh->elemsPerBlock || bh->blocksAllocated == 1)
{
/* There couldn't possibly be an entire free block. Return. */
return (0);
}
last = NULL;
walker = bh->base;
while (walker != NULL)
{
if((dlink_list_length(&walker->free_list) == bh->elemsPerBlock) != 0)
{
free_block(walker->elems, walker->alloc_size);
if(last != NULL)
{
last->next = walker->next;
if(walker != NULL)
free(walker);
walker = last->next;
}
else
{
bh->base = walker->next;
if(walker != NULL)
free(walker);
walker = bh->base;
}
bh->blocksAllocated--;
bh->freeElems -= bh->elemsPerBlock;
}
else
{
last = walker;
walker = walker->next;
}
}
return (0);
}
/* ************************************************************************ */
/* FUNCTION DOCUMENTATION: */
/* BlockHeapDestroy */
/* Description: */
/* Completely free()s a BlockHeap. Use for cleanup. */
/* Parameters: */
/* bh (IN): Pointer to the BlockHeap to be destroyed. */
/* Returns: */
/* 0 if successful, 1 if bh == NULL */
/* ************************************************************************ */
int
BlockHeapDestroy(BlockHeap * bh)
{
Block *walker, *next;
if(bh == NULL)
{
return (1);
}
for (walker = bh->base; walker != NULL; walker = next)
{
next = walker->next;
free_block(walker->elems, walker->alloc_size);
if(walker != NULL)
free(walker);
}
dlinkDelete(&bh->hlist, &heap_lists);
free(bh);
return (0);
}
void
BlockHeapUsage(BlockHeap * bh, size_t * bused, size_t * bfree, size_t * bmemusage)
{
size_t used;
size_t freem;
size_t memusage;
if(bh == NULL)
{
return;
}
freem = bh->freeElems;
used = (bh->blocksAllocated * bh->elemsPerBlock) - bh->freeElems;
memusage = used * (bh->elemSize + sizeof(MemBlock));
if(bused != NULL)
*bused = used;
if(bfree != NULL)
*bfree = freem;
if(bmemusage != NULL)
*bmemusage = memusage;
}
#endif /* NOBALLOC */

View file

@ -1,112 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* balloc.h: The ircd block allocator header.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox development team
*
* 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
*
* $Id: balloc.h 1781 2006-07-30 18:07:38Z jilles $
*/
#ifndef INCLUDED_blalloc_h
#define INCLUDED_blalloc_h
#include "setup.h"
#include "tools.h"
#include "memory.h"
#include "ircd_defs.h"
#define CACHEFILE_HEAP_SIZE 32
#define CACHELINE_HEAP_SIZE 64
#ifdef NOBALLOC
typedef struct BlockHeap BlockHeap;
#define initBlockHeap()
#define BlockHeapGarbageCollect(x)
#define BlockHeapCreate(es, epb) ((BlockHeap*)(es))
#define BlockHeapDestroy(x)
#define BlockHeapAlloc(x) MyMalloc((int)x)
#define BlockHeapFree(x,y) MyFree(y)
#define BlockHeapUsage(bh, bused, bfree, bmemusage) do { if (bused) (*(size_t *)bused) = 0; if (bfree) *((size_t *)bfree) = 0; if (bmemusage) *((size_t *)bmemusage) = 0; } while(0)
typedef struct MemBlock
{
void *dummy;
} MemBlock;
#else
#undef DEBUG_BALLOC
#ifdef DEBUG_BALLOC
#define BALLOC_MAGIC 0x3d3a3c3d
#define BALLOC_FREE_MAGIC 0xafafafaf
#endif
/* status information for an allocated block in heap */
struct Block
{
size_t alloc_size;
struct Block *next; /* Next in our chain of blocks */
void *elems; /* Points to allocated memory */
dlink_list free_list;
dlink_list used_list;
};
typedef struct Block Block;
struct MemBlock
{
#ifdef DEBUG_BALLOC
unsigned long magic;
#endif
dlink_node self;
Block *block; /* Which block we belong to */
};
typedef struct MemBlock MemBlock;
/* information for the root node of the heap */
struct BlockHeap
{
dlink_node hlist;
size_t elemSize; /* Size of each element to be stored */
unsigned long elemsPerBlock; /* Number of elements per block */
unsigned long blocksAllocated; /* Number of blocks allocated */
unsigned long freeElems; /* Number of free elements */
Block *base; /* Pointer to first block */
};
typedef struct BlockHeap BlockHeap;
extern int BlockHeapFree(BlockHeap * bh, void *ptr);
extern void *BlockHeapAlloc(BlockHeap * bh);
extern BlockHeap *BlockHeapCreate(size_t elemsize, int elemsperblock);
extern int BlockHeapDestroy(BlockHeap * bh);
extern void initBlockHeap(void);
extern void BlockHeapUsage(BlockHeap * bh, size_t * bused, size_t * bfree, size_t * bmemusage);
#endif /* NOBALLOC */
#endif /* INCLUDED_blalloc_h */

View file

@ -1,911 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* commio.c: Network/file related functions
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: commio.c 3354 2007-04-03 09:21:31Z nenolod $
*/
#include "libcharybdis.h"
#ifndef IN_LOOPBACKNET
#define IN_LOOPBACKNET 0x7f
#endif
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned int) 0xffffffff)
#endif
const char *const NONB_ERROR_MSG = "set_non_blocking failed for %s:%s";
const char *const SETBUF_ERROR_MSG = "set_sock_buffers failed for server %s:%s";
static const char *comm_err_str[] = { "Comm OK", "Error during bind()",
"Error during DNS lookup", "connect timeout",
"Error during connect()",
"Comm Error"
};
#define FD_HASH_SIZE 128
static dlink_list fd_table[FD_HASH_SIZE];
static void fdlist_update_biggest(int fd, int opening);
/* Highest FD and number of open FDs .. */
int highest_fd = -1; /* Its -1 because we haven't started yet -- adrian */
int number_fd = 0;
static void comm_connect_callback(int fd, int status);
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 newfd;
if(*fd > 256 || *fd < 0)
return;
if((newfd = fcntl(*fd, F_DUPFD, 256)) != -1)
{
close(*fd);
*fd = newfd;
}
return;
}
#else
#define comm_fd_hack(fd)
#endif
/* close_all_connections() can be used *before* the system come up! */
void
comm_close_all(void)
{
int i;
#ifndef NDEBUG
int fd;
#endif
/*
* we start at 4 to avoid giving fds where malloc messages
* could be written --nenolod
*/
for (i = 4; i < comm_max_connections; ++i)
{
fde_t *F = comm_locate_fd(i);
if(F != NULL && F->flags.open)
comm_close(i);
else
close(i);
}
/* XXX should his hack be done in all cases? */
#ifndef NDEBUG
/* fugly hack to reserve fd == 2 */
(void) close(2);
fd = open("stderr.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
if(fd >= 0)
{
dup2(fd, 2);
close(fd);
}
#endif
}
/*
* get_sockerr - get the error value from the socket or the current errno
*
* Get the *real* error from the socket (well try to anyway..).
* This may only work when SO_DEBUG is enabled but its worth the
* gamble anyway.
*/
int
comm_get_sockerr(int fd)
{
int errtmp = errno;
#ifdef SO_ERROR
int err = 0;
socklen_t len = sizeof(err);
if(-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &err, (socklen_t *) & len))
{
if(err)
errtmp = err;
}
errno = errtmp;
#endif
return errtmp;
}
/*
* set_sock_buffers - set send and receive buffers for socket
*
* inputs - fd file descriptor
* - size to set
* output - returns true (1) if successful, false (0) otherwise
* side effects -
*/
int
comm_set_buffers(int fd, int size)
{
if(setsockopt
(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size))
|| setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size)))
return 0;
return 1;
}
/*
* set_non_blocking - Set the client connection into non-blocking mode.
*
* inputs - fd to set into non blocking mode
* output - 1 if successful 0 if not
* side effects - use POSIX compliant non blocking and
* be done with it.
*/
int
comm_set_nb(int fd)
{
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;
if (F != NULL)
F->flags.nonblocking = 1;
return 1;
}
/*
* stolen from squid - its a neat (but overused! :) routine which we
* can use to see whether we can ignore this errno or not. It is
* generally useful for non-blocking network IO related errnos.
* -- adrian
*/
int
ignoreErrno(int ierrno)
{
switch (ierrno)
{
case EINPROGRESS:
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
case EALREADY:
case EINTR:
#ifdef ERESTART
case ERESTART:
#endif
return 1;
default:
return 0;
}
}
/*
* comm_settimeout() - set the socket timeout
*
* Set the timeout for the fd
*/
void
comm_settimeout(int fd, time_t timeout, PF * callback, void *cbdata)
{
fde_t *F;
s_assert(fd >= 0);
F = comm_locate_fd(fd);
s_assert(F->flags.open);
F->timeout = CurrentTime + (timeout / 1000);
F->timeout_handler = callback;
F->timeout_data = cbdata;
}
/*
* comm_setflush() - set a flush function
*
* A flush function is simply a function called if found during
* comm_timeouts(). Its basically a second timeout, except in this case
* I'm too lazy to implement multiple timeout functions! :-)
* its kinda nice to have it seperate, since this is designed for
* flush functions, and when comm_close() is implemented correctly
* with close functions, we _actually_ don't call comm_close() here ..
*/
void
comm_setflush(int fd, time_t timeout, PF * callback, void *cbdata)
{
fde_t *F;
s_assert(fd >= 0);
F = comm_locate_fd(fd);
s_assert(F->flags.open);
F->flush_timeout = CurrentTime + (timeout / 1000);
F->flush_handler = callback;
F->flush_data = cbdata;
}
/*
* comm_checktimeouts() - check the socket timeouts
*
* All this routine does is call the given callback/cbdata, without closing
* down the file descriptor. When close handlers have been implemented,
* this will happen.
*/
void
comm_checktimeouts(void *notused)
{
PF *hdl;
void *data;
fde_t *F;
dlink_list *bucket;
int i;
dlink_node *n, *n2;
for (i = 0; i <= FD_HASH_SIZE; i++)
{
bucket = &fd_table[i];
if (dlink_list_length(bucket) <= 0)
continue;
DLINK_FOREACH_SAFE(n, n2, bucket->head)
{
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 comm_connect_tcp(int fd, const char *host, u_short port,
* struct sockaddr *clocal, int socklen,
* CNCB *callback, void *data, int aftype, int timeout)
* Input: An fd to connect with, a host and port to connect to,
* a local sockaddr to connect from + length(or NULL to use the
* default), a callback, the data to pass into the callback, the
* address family.
* Output: None.
* Side-effects: A non-blocking connection to the host is started, and
* if necessary, set up for selection. The callback given
* may be called now, or it may be called later.
*/
void
comm_connect_tcp(int fd, const char *host, u_short port,
struct sockaddr *clocal, int socklen, CNCB * callback,
void *data, int aftype, int timeout)
{
void *ipptr = NULL;
fde_t *F;
s_assert(fd >= 0);
F = comm_locate_fd(fd);
F->flags.called_connect = 1;
s_assert(callback);
F->connect.callback = callback;
F->connect.data = data;
memset(&F->connect.hostaddr, 0, sizeof(F->connect.hostaddr));
#ifdef IPV6
if(aftype == AF_INET6)
{
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&F->connect.hostaddr;
SET_SS_LEN(F->connect.hostaddr, sizeof(struct sockaddr_in6));
in6->sin6_port = htons(port);
in6->sin6_family = AF_INET6;
ipptr = &in6->sin6_addr;
} else
#endif
{
struct sockaddr_in *in = (struct sockaddr_in *)&F->connect.hostaddr;
SET_SS_LEN(F->connect.hostaddr, sizeof(struct sockaddr_in));
in->sin_port = htons(port);
in->sin_family = AF_INET;
ipptr = &in->sin_addr;
}
/* Note that we're using a passed sockaddr here. This is because
* generally you'll be bind()ing to a sockaddr grabbed from
* getsockname(), so this makes things easier.
* XXX If NULL is passed as local, we should later on bind() to the
* virtual host IP, for completeness.
* -- adrian
*/
if((clocal != NULL) && (bind(F->fd, clocal, socklen) < 0))
{
/* Failure, call the callback with COMM_ERR_BIND */
comm_connect_callback(F->fd, COMM_ERR_BIND);
/* ... and quit */
return;
}
/* Next, if we have been given an IP, get the addr and skip the
* DNS check (and head direct to comm_connect_tryconnect().
*/
if(inetpton(aftype, host, ipptr) <= 0)
{
/* Send the DNS request, for the next level */
F->dns_query = MyMalloc(sizeof(struct DNSQuery));
F->dns_query->ptr = F;
F->dns_query->callback = comm_connect_dns_callback;
#ifdef IPV6
if (aftype == AF_INET6)
gethost_byname_type(host, F->dns_query, T_AAAA);
else
#endif
gethost_byname_type(host, F->dns_query, T_A);
}
else
{
/* We have a valid IP, so we just call tryconnect */
/* Make sure we actually set the timeout here .. */
comm_settimeout(F->fd, timeout * 1000, comm_connect_timeout, NULL);
comm_connect_tryconnect(F->fd, NULL);
}
}
/*
* comm_connect_callback() - call the callback, and continue with life
*/
static void
comm_connect_callback(int fd, int status)
{
CNCB *hdl;
fde_t *F = comm_locate_fd(fd);
/* This check is gross..but probably necessary */
if(F == NULL || F->connect.callback == NULL)
return;
/* Clear the connect flag + handler */
hdl = F->connect.callback;
F->connect.callback = NULL;
F->flags.called_connect = 0;
/* Clear the timeout handler */
comm_settimeout(F->fd, 0, NULL, NULL);
/* Call the handler */
hdl(F->fd, status, F->connect.data);
}
/*
* comm_connect_timeout() - this gets called when the socket connection
* times out. This *only* can be called once connect() is initially
* called ..
*/
static void
comm_connect_timeout(int fd, void *notused)
{
/* error! */
comm_connect_callback(fd, COMM_ERR_TIMEOUT);
}
/*
* comm_connect_dns_callback() - called at the completion of the DNS request
*
* The DNS request has completed, so if we've got an error, return it,
* otherwise we initiate the connect()
*/
static void
comm_connect_dns_callback(void *vptr, struct DNSReply *reply)
{
fde_t *F = vptr;
/* Free dns_query now to avoid double reslist free -- jilles */
MyFree(F->dns_query);
F->dns_query = NULL;
if(!reply)
{
comm_connect_callback(F->fd, COMM_ERR_DNS);
return;
}
/* No error, set a 10 second timeout */
comm_settimeout(F->fd, 30 * 1000, comm_connect_timeout, NULL);
/* Copy over the DNS reply info so we can use it in the connect() */
#ifdef IPV6
if(reply->addr.ss_family == AF_INET6)
{
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&F->connect.hostaddr;
memcpy(&in6->sin6_addr, &((struct sockaddr_in6 *)&reply->addr)->sin6_addr, sizeof(struct in6_addr));
}
else
#endif
{
struct sockaddr_in *in = (struct sockaddr_in *)&F->connect.hostaddr;
in->sin_addr.s_addr = ((struct sockaddr_in *)&reply->addr)->sin_addr.s_addr;
}
/* Now, call the tryconnect() routine to try a connect() */
comm_connect_tryconnect(F->fd, NULL);
}
/* static void comm_connect_tryconnect(int fd, void *notused)
* Input: The fd, the handler data(unused).
* Output: None.
* Side-effects: Try and connect with pending connect data for the FD. If
* we succeed or get a fatal error, call the callback.
* Otherwise, it is still blocking or something, so register
* to select for a write event on this FD.
*/
static void
comm_connect_tryconnect(int fd, void *notused)
{
int retval;
fde_t *F = comm_locate_fd(fd);
if(F->connect.callback == NULL)
return;
/* Try the connect() */
retval = connect(fd, (struct sockaddr *) &F->connect.hostaddr,
GET_SS_LEN(F->connect.hostaddr));
/* Error? */
if(retval < 0)
{
/*
* If we get EISCONN, then we've already connect()ed the socket,
* which is a good thing.
* -- adrian
*/
if(errno == EISCONN)
comm_connect_callback(F->fd, COMM_OK);
else if(ignoreErrno(errno))
/* Ignore error? Reschedule */
comm_setselect(F->fd, FDLIST_SERVER, COMM_SELECT_WRITE|COMM_SELECT_RETRY,
comm_connect_tryconnect, NULL, 0);
else
/* Error? Fail with COMM_ERR_CONNECT */
comm_connect_callback(F->fd, COMM_ERR_CONNECT);
return;
}
/* If we get here, we've suceeded, so call with COMM_OK */
comm_connect_callback(F->fd, COMM_OK);
}
/*
* comm_error_str() - return an error string for the given error condition
*/
const char *
comm_errstr(int error)
{
if(error < 0 || error >= COMM_ERR_MAX)
return "Invalid error number!";
return comm_err_str[error];
}
/*
* comm_socket() - open a socket
*
* This is a highly highly cut down version of squid's comm_open() which
* for the most part emulates socket(), *EXCEPT* it fails if we're about
* to run out of file descriptors.
*/
int
comm_socket(int family, int sock_type, int proto, const char *note)
{
int fd;
/* First, make sure we aren't going to run out of file descriptors */
if(number_fd >= comm_max_connections)
{
errno = ENFILE;
return -1;
}
/*
* Next, we try to open the socket. We *should* drop the reserved FD
* limit if/when we get an error, but we can deal with that later.
* XXX !!! -- adrian
*/
fd = socket(family, sock_type, proto);
comm_fd_hack(&fd);
if(fd < 0)
return -1; /* errno will be passed through, yay.. */
#if defined(IPV6) && defined(IPV6_V6ONLY)
/*
* Make sure we can take both IPv4 and IPv6 connections
* on an AF_INET6 socket
*/
if(family == AF_INET6)
{
int off = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) == -1)
{
libcharybdis_log("comm_socket: Could not set IPV6_V6ONLY option to 1 on FD %d: %s",
fd, strerror(errno));
close(fd);
return -1;
}
}
#endif
/* Set the socket non-blocking, and other wonderful bits */
if(!comm_set_nb(fd))
{
libcharybdis_log("comm_open: Couldn't set FD %d non blocking: %s", fd, strerror(errno));
close(fd);
return -1;
}
/* Next, update things in our fd tracking */
comm_open(fd, FD_SOCKET, note);
return fd;
}
/*
* comm_accept() - accept an incoming connection
*
* This is a simple wrapper for accept() which enforces FD limits like
* comm_open() does.
*/
int
comm_accept(int fd, struct sockaddr *pn, socklen_t *addrlen)
{
int newfd;
if(number_fd >= comm_max_connections)
{
errno = ENFILE;
return -1;
}
/*
* Next, do the accept(). if we get an error, we should drop the
* reserved fd limit, but we can deal with that when comm_open()
* also does it. XXX -- adrian
*/
newfd = accept(fd, (struct sockaddr *) pn, addrlen);
comm_fd_hack(&newfd);
if(newfd < 0)
return -1;
/* Set the socket non-blocking, and other wonderful bits */
if(!comm_set_nb(newfd))
{
libcharybdis_log("comm_accept: Couldn't set FD %d non blocking!", newfd);
close(newfd);
return -1;
}
/* Next, tag the FD as an incoming connection */
comm_open(newfd, FD_SOCKET, "Incoming connection");
/* .. and return */
return newfd;
}
/*
* If a sockaddr_storage is AF_INET6 but is a mapped IPv4
* socket manged the sockaddr.
*/
#ifndef mangle_mapped_sockaddr
void
mangle_mapped_sockaddr(struct sockaddr *in)
{
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;
if(in->sa_family == AF_INET)
return;
if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
{
struct sockaddr_in in4;
memset(&in4, 0, sizeof(struct sockaddr_in));
in4.sin_family = AF_INET;
in4.sin_port = in6->sin6_port;
in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
memcpy(in, &in4, sizeof(struct sockaddr_in));
}
return;
}
#endif
static void
fdlist_update_biggest(int fd, int opening)
{
if(fd < highest_fd)
return;
s_assert(fd < comm_max_connections);
if(fd > highest_fd)
{
/*
* s_assert that we are not closing a FD bigger than
* our known biggest FD
*/
s_assert(opening);
highest_fd = fd;
return;
}
/* if we are here, then fd == Biggest_FD */
/*
* s_assert that we are closing the biggest FD; we can't be
* re-opening it
*/
s_assert(!opening);
while (highest_fd >= 0 && comm_locate_fd(fd) != NULL)
highest_fd--;
}
void
fdlist_init(void)
{
static int initialized = 0;
struct rlimit limit;
if(!initialized)
{
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;
}
}
/* Called to open a given filedescriptor */
void
comm_open(int fd, unsigned int type, const char *desc)
{
fde_t *F = comm_add_fd(fd);
s_assert(fd >= 0);
if(F->flags.open)
{
comm_close(fd);
}
s_assert(!F->flags.open);
F->fd = fd;
F->type = type;
F->flags.open = 1;
#ifdef NOTYET
F->defer.until = 0;
F->defer.n = 0;
F->defer.handler = NULL;
#endif
fdlist_update_biggest(fd, 1);
F->comm_index = -1;
F->list = FDLIST_NONE;
if(desc)
strlcpy(F->desc, desc, sizeof(F->desc));
number_fd++;
}
/* Called to close a given filedescriptor */
void
comm_close(int 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);
if(F->type == FD_FILE)
{
s_assert(F->read_handler == NULL);
s_assert(F->write_handler == NULL);
}
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)
{
delete_resolver_queries(F->dns_query);
MyFree(F->dns_query);
F->dns_query = NULL;
}
F->flags.open = 0;
fdlist_update_biggest(fd, 0);
number_fd--;
comm_remove_fd(fd);
/* Unlike squid, we're actually closing the FD here! -- adrian */
close(fd);
}
/*
* comm_dump() - dump the list of active filedescriptors
*/
void
comm_dump(struct Client *source_p)
{
int i;
for (i = 0; i <= FD_HASH_SIZE; i++)
{
dlink_node *n;
if (dlink_list_length(&fd_table[i]) <= 0)
continue;
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() - set the fd note
*
* Note: must be careful not to overflow fd_table[fd].desc when
* calling.
*/
void
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(F->desc, FD_DESC_SZ, format, args);
va_end(args);
}
else
F->desc[0] = '\0';
}
extern int
comm_get_maxconnections(void)
{
fdlist_init();
return comm_max_connections;
}

View file

@ -1,208 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* commio.h: A header for the network subsystem.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox development team
*
* 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
*
* $Id: commio.h 3354 2007-04-03 09:21:31Z nenolod $
*/
#ifndef INCLUDED_commio_h
#define INCLUDED_commio_h
#include "setup.h"
#include "config.h"
#include "ircd_defs.h"
#include "tools.h"
typedef struct _fde fde_t;
/* Callback for completed IO events */
typedef void PF(int fd, void *);
/* virtual function types for I/O --nenolod */
typedef int IOFuncRead(fde_t *, void *buf, size_t count);
typedef int IOFuncWrite(fde_t *, const void *buf, size_t count);
/* Callback for completed connections */
/* int fd, int status, void * */
typedef void CNCB(int fd, int, void *);
#define FD_DESC_SZ 128 /* hostlen + comment */
/* FD type values */
enum
{
FD_NONE,
FD_LOG,
FD_FILE,
FD_FILECLOSE,
FD_SOCKET,
FD_PIPE,
FD_UNKNOWN
};
enum
{
COMM_OK,
COMM_ERR_BIND,
COMM_ERR_DNS,
COMM_ERR_TIMEOUT,
COMM_ERR_CONNECT,
COMM_ERROR,
COMM_ERR_MAX
};
typedef enum fdlist_t
{
FDLIST_NONE,
FDLIST_SERVICE,
FDLIST_SERVER,
FDLIST_IDLECLIENT,
FDLIST_BUSYCLIENT,
FDLIST_MAX
}
fdlist_t;
extern int highest_fd;
extern int number_fd;
struct Client;
struct _fde
{
/* New-school stuff, again pretty much ripped from squid */
/*
* Yes, this gives us only one pending read and one pending write per
* filedescriptor. Think though: when do you think we'll need more?
*/
int fd; /* So we can use the fde_t as a callback ptr */
int type;
fdlist_t list; /* Which list this FD should sit on */
int comm_index; /* where in the poll list we live */
char desc[FD_DESC_SZ];
PF *read_handler;
void *read_data;
PF *write_handler;
void *write_data;
PF *timeout_handler;
void *timeout_data;
time_t timeout;
PF *flush_handler;
void *flush_data;
time_t flush_timeout;
IOFuncRead *read_impl;
IOFuncWrite *write_impl;
struct DNSQuery *dns_query;
struct
{
unsigned int open:1;
unsigned int close_request:1;
unsigned int write_daemon:1;
unsigned int closing:1;
unsigned int socket_eof:1;
unsigned int nolinger:1;
unsigned int nonblocking:1;
unsigned int ipc:1;
unsigned int called_connect:1;
}
flags;
struct
{
struct irc_sockaddr_storage hostaddr;
CNCB *callback;
void *data;
/* We'd also add the retry count here when we get to that -- adrian */
}
connect;
int pflags;
dlink_node node;
};
void fdlist_init(void);
extern void comm_open(int, unsigned int, const char *);
extern void comm_close(int);
extern void comm_dump(struct Client *source_p);
#ifndef __GNUC__
extern void comm_note(int fd, const char *format, ...);
#else
extern void comm_note(int fd, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
#endif
#define FB_EOF 0x01
#define FB_FAIL 0x02
/* Size of a read buffer */
#define READBUF_SIZE 16384 /* used by src/packet.c and src/s_serv.c */
/* Type of IO */
#define COMM_SELECT_READ 0x1
#define COMM_SELECT_WRITE 0x2
#define COMM_SELECT_RETRY 0x4
extern int readcalls;
extern const char *const NONB_ERROR_MSG;
extern const char *const SETBUF_ERROR_MSG;
extern void comm_close_all(void);
extern int comm_set_nb(int);
extern int comm_set_buffers(int, int);
extern int comm_get_sockerr(int);
extern int ignoreErrno(int ierrno);
extern void comm_settimeout(int fd, time_t, PF *, void *);
extern void comm_setflush(int fd, time_t, PF *, void *);
extern void comm_checktimeouts(void *);
extern void comm_connect_tcp(int fd, const char *, u_short,
struct sockaddr *, int, CNCB *, void *, int, int);
extern const char *comm_errstr(int status);
extern int comm_socket(int family, int sock_type, int proto, const char *note);
extern int comm_accept(int fd, struct sockaddr *pn, socklen_t *addrlen);
/* These must be defined in the network IO loop code of your choice */
extern void comm_setselect(int fd, fdlist_t list, unsigned int type,
PF * handler, void *client_data, time_t timeout);
extern void init_netio(void);
extern int read_message(time_t, unsigned char);
extern int comm_select(unsigned long);
extern int disable_sock_options(int);
#ifdef IPV6
extern void mangle_mapped_sockaddr(struct sockaddr *in);
#else
#define mangle_mapped_sockaddr(x)
#endif
extern int comm_get_maxconnections(void);
extern fde_t *comm_locate_fd(int fd);
extern fde_t *comm_add_fd(int fd);
#endif /* INCLUDED_commio_h */

View file

@ -1,263 +0,0 @@
/*
* charybdis: A slightly useful ircd.
* epoll.c: Linux epoll compatible network routines.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002-2005 ircd-ratbox development team
* Copyright (C) 2002 Aaron Sethman <androsyn@ratbox.org>
* Copyright (C) 2008 William Pitcock <nenolod@sacredspiral.co.uk>
*
* 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
*
* $Id: epoll.c 3444 2007-05-09 00:32:08Z nenolod $
*/
#include "config.h"
#include "stdinc.h"
#include <sys/epoll.h>
#include "libcharybdis.h"
static int ep; /* epoll file descriptor */
static struct epoll_event *pfd;
static int pfd_size;
#ifndef HAVE_EPOLL_CTL /* bah..glibc doesn't support epoll yet.. */
#include <sys/epoll.h>
#include <sys/syscall.h>
_syscall1(int, epoll_create, int, maxfds);
_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, events);
_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents,
int, maxevents, int, timeout);
#endif /* HAVE_EPOLL_CTL */
/*
* init_netio
*
* This is a needed exported function which will be called to initialise
* the network loop code.
*/
void
init_netio(void)
{
pfd_size = getdtablesize();
ep = epoll_create(pfd_size);
pfd = MyMalloc(sizeof(struct epoll_event) * pfd_size);
if(ep < 0)
{
fprintf(stderr, "init_netio: Couldn't open epoll fd!\n");
exit(115); /* Whee! */
}
comm_note(ep, "epoll file descriptor");
}
/*
* comm_setselect
*
* This is a needed exported function which will be called to register
* and deregister interest in a pending IO state for a given FD.
*/
void
comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
void *client_data, time_t timeout)
{
struct epoll_event ep_event;
fde_t *F = comm_locate_fd(fd);
int old_flags = F->pflags;
int op = -1;
s_assert(fd >= 0);
s_assert(F->flags.open);
/* Update the list, even though we're not using it .. */
F->list = list;
if(type & COMM_SELECT_READ)
{
if(handler != NULL)
F->pflags |= EPOLLIN;
else
F->pflags &= ~EPOLLIN;
F->read_handler = handler;
F->read_data = client_data;
}
if(type & COMM_SELECT_WRITE)
{
if(handler != NULL)
F->pflags |= EPOLLOUT;
else
F->pflags &= ~EPOLLOUT;
F->write_handler = handler;
F->write_data = client_data;
}
if(timeout)
F->timeout = CurrentTime + (timeout / 1000);
if(old_flags == 0 && F->pflags == 0)
return;
else if(F->pflags <= 0)
op = EPOLL_CTL_DEL;
else if(old_flags == 0 && F->pflags > 0)
op = EPOLL_CTL_ADD;
else if(F->pflags != old_flags)
op = EPOLL_CTL_MOD;
if(op == -1)
return;
ep_event.events = F->pflags;
ep_event.data.ptr = F;
if(epoll_ctl(ep, op, fd, &ep_event) != 0)
{
libcharybdis_log("comm_setselect(): epoll_ctl failed: %s", strerror(errno));
abort();
}
}
/*
* comm_select
*
* Called to do the new-style IO, courtesy of squid (like most of this
* new IO code). This routine handles the stuff we've hidden in
* comm_setselect and fd_table[] and calls callbacks for IO ready
* events.
*/
int
comm_select(unsigned long delay)
{
int num, i, flags, old_flags, op;
struct epoll_event ep_event;
void *data;
num = epoll_wait(ep, pfd, pfd_size, delay);
set_time();
if(num < 0 && !ignoreErrno(errno))
{
return COMM_ERROR;
}
if(num == 0)
return COMM_OK;
for (i = 0; i < num; i++)
{
PF *hdl;
fde_t *F = pfd[i].data.ptr;
old_flags = F->pflags;
if(pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
{
hdl = F->read_handler;
data = F->read_data;
F->read_handler = NULL;
F->read_data = NULL;
if(hdl) {
hdl(F->fd, data);
}
else
libcharybdis_log("epoll.c: NULL read handler called");
}
if(F->flags.open == 0 && F->pflags == 0)
continue;
else if (F->flags.open == 0)
{
F->pflags = ep_event.events = flags;
ep_event.data.ptr = F;
if(epoll_ctl(ep, EPOLL_CTL_DEL, F->fd, &ep_event) != 0) {
/* XXX: we assume this is because close(2) has been called here. */
if (errno == EBADF)
continue;
libcharybdis_log("comm_select(): epoll_ctl failed while trying to delete an FD marked as closed: %s", strerror(errno));
abort();
}
continue;
}
if(pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))
{
hdl = F->write_handler;
data = F->write_data;
F->write_handler = NULL;
F->write_data = NULL;
if(hdl) {
hdl(F->fd, data);
}
else
libcharybdis_log("epoll.c: NULL write handler called");
}
if(F->flags.open == 0 && F->pflags == 0)
continue;
else if (F->flags.open == 0)
{
F->pflags = ep_event.events = flags;
ep_event.data.ptr = F;
if(epoll_ctl(ep, EPOLL_CTL_DEL, F->fd, &ep_event) != 0) {
/* XXX: we assume this is because close(2) has been called here. */
if (errno == EBADF)
continue;
libcharybdis_log("comm_select(): epoll_ctl failed while trying to delete an FD marked as closed: %s", strerror(errno));
abort();
}
continue;
}
flags = 0;
if(F->read_handler != NULL)
flags |= EPOLLIN;
else
flags &= ~EPOLLIN;
if(F->write_handler != NULL)
flags |= EPOLLOUT;
else
flags &= ~EPOLLOUT;
if(old_flags != flags)
{
if(flags == 0)
op = EPOLL_CTL_DEL;
else
op = EPOLL_CTL_MOD;
F->pflags = ep_event.events = flags;
ep_event.data.ptr = F;
if(epoll_ctl(ep, op, F->fd, &ep_event) != 0)
libcharybdis_log("comm_select(): epoll_ctl failed: %s", strerror(errno));
}
}
return COMM_OK;
}

View file

@ -1,352 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* event.c: Event functions.
*
* Copyright (C) 1998-2000 Regents of the University of California
* Copyright (C) 2001-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* Code borrowed from the squid web cache by Adrian Chadd.
* Original header:
*
* DEBUG: section 41 Event Processing
* AUTHOR: Henrik Nordstrom
*
* SQUID Internet Object Cache http://squid.nlanr.net/Squid/
* ----------------------------------------------------------
*
* Squid is the result of efforts by numerous individuals from the
* Internet community. Development is led by Duane Wessels of the
* National Laboratory for Applied Network Research and funded by the
* National Science Foundation. Squid is Copyrighted (C) 1998 by
* the Regents of the University of California. Please see the
* COPYRIGHT file for full details. Squid incorporates software
* developed and/or copyrighted by other sources. Please see the
* CREDITS file for full details.
*
* 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
*
* $Id: event.c 498 2006-01-15 16:40:33Z jilles $
*/
/*
* How its used:
*
* Should be pretty self-explanatory. Events are added to the static
* array event_table with a frequency time telling eventRun how often
* to execute it.
*/
#include "stdinc.h"
#include "config.h"
#include "ircd.h"
#include "event.h"
#include "client.h"
#include "send.h"
#include "memory.h"
#include "s_log.h"
#include "numeric.h"
static const char *last_event_ran = NULL;
struct ev_entry event_table[MAX_EVENTS];
static time_t event_time_min = -1;
/*
* void eventAdd(const char *name, EVH *func, void *arg, time_t when)
*
* Input: Name of event, function to call, arguments to pass, and frequency
* of the event.
* Output: None
* Side Effects: Adds the event to the event list.
*/
void
eventAdd(const char *name, EVH * func, void *arg, time_t when)
{
int i;
/* find first inactive index */
for (i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].active == 0)
{
event_table[i].func = func;
event_table[i].name = name;
event_table[i].arg = arg;
event_table[i].when = CurrentTime + when;
event_table[i].frequency = when;
event_table[i].active = 1;
if((event_table[i].when < event_time_min) || (event_time_min == -1))
event_time_min = event_table[i].when;
return;
}
}
/* erk! couldnt add to event table */
sendto_realops_snomask(SNO_DEBUG, L_ALL, "Unable to add event [%s] to event table", name);
}
void
eventAddOnce(const char *name, EVH *func, void *arg, time_t when)
{
int i;
/* find first inactive index */
for (i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].active == 0)
{
event_table[i].func = func;
event_table[i].name = name;
event_table[i].arg = arg;
event_table[i].when = CurrentTime + when;
event_table[i].frequency = 0;
event_table[i].active = 1;
if ((event_table[i].when < event_time_min) || (event_time_min == -1))
event_time_min = event_table[i].when;
return;
}
}
/* erk! couldnt add to event table */
sendto_realops_snomask(SNO_DEBUG, L_ALL,
"Unable to add event [%s] to event table", name);
}
/*
* void eventDelete(EVH *func, void *arg)
*
* Input: Function handler, argument that was passed.
* Output: None
* Side Effects: Removes the event from the event list
*/
void
eventDelete(EVH * func, void *arg)
{
int i;
i = eventFind(func, arg);
if(i == -1)
return;
event_table[i].name = NULL;
event_table[i].func = NULL;
event_table[i].arg = NULL;
event_table[i].active = 0;
}
/*
* void eventAddIsh(const char *name, EVH *func, void *arg, time_t delta_isa)
*
* Input: Name of event, function to call, arguments to pass, and frequency
* of the event.
* Output: None
* Side Effects: Adds the event to the event list within +- 1/3 of the
* specified frequency.
*/
void
eventAddIsh(const char *name, EVH * func, void *arg, time_t delta_ish)
{
if(delta_ish >= 3.0)
{
const time_t two_third = (2 * delta_ish) / 3;
delta_ish = two_third + ((rand() % 1000) * two_third) / 1000;
/*
* XXX I hate the above magic, I don't even know if its right.
* Grr. -- adrian
*/
}
eventAdd(name, func, arg, delta_ish);
}
/*
* void eventRun(void)
*
* Input: None
* Output: None
* Side Effects: Runs pending events in the event list
*/
void
eventRun(void)
{
int i;
for (i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].active && (event_table[i].when <= CurrentTime))
{
last_event_ran = event_table[i].name;
event_table[i].func(event_table[i].arg);
event_time_min = -1;
/* event is scheduled more than once */
if(event_table[i].frequency)
event_table[i].when = CurrentTime + event_table[i].frequency;
else
{
event_table[i].name = NULL;
event_table[i].func = NULL;
event_table[i].arg = NULL;
event_table[i].active = 0;
}
}
}
}
/*
* time_t eventNextTime(void)
*
* Input: None
* Output: Specifies the next time eventRun() should be run
* Side Effects: None
*/
time_t
eventNextTime(void)
{
int i;
if(event_time_min == -1)
{
for (i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].active &&
((event_table[i].when < event_time_min) || (event_time_min == -1)))
event_time_min = event_table[i].when;
}
}
return event_time_min;
}
/*
* void eventInit(void)
*
* Input: None
* Output: None
* Side Effects: Initializes the event system.
*/
void
eventInit(void)
{
last_event_ran = NULL;
memset((void *) event_table, 0, sizeof(event_table));
}
/*
* int eventFind(EVH *func, void *arg)
*
* Input: Event function and the argument passed to it
* Output: Index to the slow in the event_table
* Side Effects: None
*/
int
eventFind(EVH * func, void *arg)
{
int i;
for (i = 0; i < MAX_EVENTS; i++)
{
if((event_table[i].func == func) &&
(event_table[i].arg == arg) && event_table[i].active)
return i;
}
return -1;
}
/*
* void show_events(struct Client *source_p)
*
* Input: Client requesting the event
* Output: List of events
* Side Effects: None
*/
void
show_events(struct Client *source_p)
{
int i;
if(last_event_ran)
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"E :Last event to run: %s",
last_event_ran);
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"E :Operation Next Execution");
for (i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].active)
{
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"E :%-28s %-4d seconds",
event_table[i].name,
(int)(event_table[i].when - CurrentTime));
}
}
}
/*
* void set_back_events(time_t by)
* Input: Time to set back events by.
* Output: None.
* Side-effects: Sets back all events by "by" seconds.
*/
void
set_back_events(time_t by)
{
int i;
for (i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].when > by)
event_table[i].when -= by;
else
event_table[i].when = 0;
}
}
void
eventUpdate(const char *name, time_t freq)
{
int i;
for(i = 0; i < MAX_EVENTS; i++)
{
if(event_table[i].active &&
!irccmp(event_table[i].name, name))
{
event_table[i].frequency = freq;
/* update when its scheduled to run if its higher
* than the new frequency
*/
if((CurrentTime + freq) < event_table[i].when)
event_table[i].when = CurrentTime + freq;
return;
}
}
}

View file

@ -1,64 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* event.h: The ircd event header.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox development team
*
* 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
*
* $Id: event.h 380 2005-12-07 15:08:37Z nenolod $
*/
#ifndef INCLUDED_event_h
#define INCLUDED_event_h
/*
* How many event entries we need to allocate at a time in the block
* allocator. 16 should be plenty at a time.
*/
#define MAX_EVENTS 50
typedef void EVH(void *);
/* The list of event processes */
struct ev_entry
{
EVH *func;
void *arg;
const char *name;
time_t frequency;
time_t when;
int active;
};
extern void eventAdd(const char *name, EVH * func, void *arg, time_t when);
extern void eventAddOnce(const char *name, EVH * func, void *arg, time_t when);
extern void eventAddIsh(const char *name, EVH * func, void *arg, time_t delta_ish);
extern void eventRun(void);
extern time_t eventNextTime(void);
extern void eventInit(void);
extern void eventDelete(EVH * func, void *);
extern int eventFind(EVH * func, void *);
extern void set_back_events(time_t);
void eventUpdate(const char *name, time_t freq);
extern void show_events(struct Client *source_p);
#endif /* INCLUDED_event_h */

View file

@ -1,287 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* kqueue.c: FreeBSD kqueue compatible network routines.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: kqueue.c 3358 2007-04-03 09:34:38Z nenolod $
*/
#include "stdinc.h"
#include <sys/event.h>
#include "libcharybdis.h"
#define KE_LENGTH 128
/* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
#ifndef EV_SET
#define EV_SET(kevp, a, b, c, d, e, f) do { \
(kevp)->ident = (a); \
(kevp)->filter = (b); \
(kevp)->flags = (c); \
(kevp)->fflags = (d); \
(kevp)->data = (e); \
(kevp)->udata = (f); \
} while(0)
#endif
static void kq_update_events(fde_t *, short, PF *);
static int kq;
static struct timespec zero_timespec;
static struct kevent *kqlst; /* kevent buffer */
static int kqmax; /* max structs to buffer */
static int kqoff; /* offset into the buffer */
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Private functions */
void
kq_update_events(fde_t * F, short filter, PF * handler)
{
PF *cur_handler;
int kep_flags;
switch (filter)
{
case EVFILT_READ:
cur_handler = F->read_handler;
break;
case EVFILT_WRITE:
cur_handler = F->write_handler;
break;
default:
/* XXX bad! -- adrian */
return;
break;
}
if((cur_handler == NULL && handler != NULL) || (cur_handler != NULL && handler == NULL))
{
struct kevent *kep;
kep = kqlst + kqoff;
if(handler != NULL)
{
if(filter == EVFILT_WRITE)
kep_flags = (EV_ADD | EV_ENABLE | EV_ONESHOT);
else
kep_flags = (EV_ADD | EV_ENABLE);
}
else
{
/* lets definately not poll stuff that isn't real --
* some kqueue implementations hate doing this... and
* it's intended to delete AND disable at the same time.
*
* don't believe me? read kevent(4). --nenolod
*/
kep_flags = (EV_DELETE | EV_DISABLE);
}
EV_SET(kep, (uintptr_t) F->fd, filter, kep_flags, 0, 0, (void *) F);
if(++kqoff == kqmax)
{
int ret;
ret = kevent(kq, kqlst, kqoff, NULL, 0, &zero_timespec);
/* jdc -- someone needs to do error checking... */
if(ret == -1)
{
libcharybdis_log("kq_update_events(): kevent(): %s", strerror(errno));
return;
}
kqoff = 0;
}
}
}
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Public functions */
/*
* init_netio
*
* This is a needed exported function which will be called to initialise
* the network loop code.
*/
void
init_netio(void)
{
kq = kqueue();
if(kq < 0)
{
libcharybdis_log("init_netio: Couldn't open kqueue fd!\n");
exit(115); /* Whee! */
}
kqmax = getdtablesize();
kqlst = MyMalloc(sizeof(struct kevent) * kqmax);
zero_timespec.tv_sec = 0;
zero_timespec.tv_nsec = 0;
}
/*
* comm_setselect
*
* This is a needed exported function which will be called to register
* and deregister interest in a pending IO state for a given FD.
*/
void
comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
void *client_data, time_t timeout)
{
fde_t *F = comm_locate_fd(fd);
s_assert(fd >= 0);
s_assert(F->flags.open);
/* Update the list, even though we're not using it .. */
F->list = list;
if(type & COMM_SELECT_READ)
{
kq_update_events(F, EVFILT_READ, handler);
F->read_handler = handler;
F->read_data = client_data;
}
if(type & COMM_SELECT_WRITE)
{
kq_update_events(F, EVFILT_WRITE, handler);
F->write_handler = handler;
F->write_data = client_data;
}
if(timeout)
F->timeout = CurrentTime + (timeout / 1000);
}
/*
* Check all connections for new connections and input data that is to be
* processed. Also check for connections with data queued and whether we can
* write it out.
*/
/*
* comm_select
*
* Called to do the new-style IO, courtesy of squid (like most of this
* new IO code). This routine handles the stuff we've hidden in
* comm_setselect and fd_table[] and calls callbacks for IO ready
* events.
*/
int
comm_select(unsigned long delay)
{
int num, i;
static struct kevent ke[KE_LENGTH];
struct timespec poll_time;
/*
* remember we are doing NANOseconds here, not micro/milli. God knows
* why jlemon used a timespec, but hey, he wrote the interface, not I
* -- Adrian
*/
poll_time.tv_sec = delay / 1000;
poll_time.tv_nsec = (delay % 1000) * 1000000;
for (;;)
{
num = kevent(kq, kqlst, kqoff, ke, KE_LENGTH, &poll_time);
kqoff = 0;
if(num >= 0)
break;
if(ignoreErrno(errno))
break;
set_time();
return COMM_ERROR;
/* NOTREACHED */
}
set_time();
if(num == 0)
return COMM_OK; /* No error.. */
for (i = 0; i < num; i++)
{
int fd = (int) ke[i].ident;
PF *hdl = NULL;
fde_t *F = comm_locate_fd(fd);
if(ke[i].flags & EV_ERROR)
{
errno = (int) ke[i].data;
/* XXX error == bad! -- adrian */
continue; /* XXX! */
}
if (F == NULL)
{
/* XXX this is because of our "queueing" of
* kqueue changes so we may get ones for fds
* we have already closed? -- jilles */
continue;
}
switch (ke[i].filter)
{
case EVFILT_READ:
if((hdl = F->read_handler) != NULL)
{
F->read_handler = NULL;
hdl(fd, F->read_data);
}
break;
case EVFILT_WRITE:
if((hdl = F->write_handler) != NULL)
{
F->write_handler = NULL;
hdl(fd, F->write_data);
}
break;
default:
/* Bad! -- adrian */
break;
}
}
return COMM_OK;
}

View file

@ -1,91 +0,0 @@
/*
* charybdis: A slightly useful ircd.
* libcharybdis.c: library entrypoint
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
* Copyright (C) 2005 William Pitcock and Jilles Tjoelker
*
* 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
*
* $Id: libcharybdis.c 386 2005-12-07 16:21:24Z nenolod $
*/
#include "stdinc.h"
#include "libcharybdis.h"
static void (*log_callback)(const char *str) = NULL;
static void (*restart_callback)(const char *str) = NULL;
static void (*die_callback)(const char *str) = NULL;
static char errbuf[BUFSIZE * 2];
void libcharybdis_log(const char *str, ...)
{
va_list args;
if (log_callback == NULL)
return;
va_start(args, str);
ircvsnprintf(errbuf, BUFSIZE * 2, str, args);
va_end(args);
log_callback(errbuf);
}
void libcharybdis_restart(const char *str, ...)
{
va_list args;
if (restart_callback == NULL)
return;
va_start(args, str);
ircvsnprintf(errbuf, BUFSIZE * 2, str, args);
va_end(args);
restart_callback(errbuf);
}
void libcharybdis_die(const char *str, ...)
{
va_list args;
if (die_callback == NULL)
return;
va_start(args, str);
ircvsnprintf(errbuf, BUFSIZE * 2, str, args);
va_end(args);
die_callback(errbuf);
}
void libcharybdis_init(void (*log_cb)(const char *str),
void (*restart_cb)(const char *str), void (*die_cb)(const char *str))
{
log_callback = log_cb;
restart_callback = restart_cb;
die_callback = die_cb;
fdlist_init();
init_netio();
eventInit();
initBlockHeap();
init_dlink_nodes();
linebuf_init();
}

View file

@ -1,48 +0,0 @@
/*
* charybdis: A slightly useful ircd.
* libcharybdis.h: library entrypoint
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
* Copyright (C) 2005 William Pitcock and Jilles Tjoelker
*
* 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
*
* $Id: libcharybdis.h 388 2005-12-07 16:34:40Z nenolod $
*/
#ifndef _LIBCHARYBDIS_H
#define _LIBCHARYBDIS_H
#include "stdinc.h"
#include "res.h"
#include "numeric.h"
#include "tools.h"
#include "memory.h"
#include "balloc.h"
#include "linebuf.h"
#include "sprintf_irc.h"
#include "commio.h"
#include "event.h"
extern void libcharybdis_log(const char *str, ...);
extern void libcharybdis_restart(const char *str, ...);
extern void libcharybdis_die(const char *str, ...);
extern void libcharybdis_init(void (*)(const char *),
void (*)(const char *), void (*)(const char *));
#endif

View file

@ -1,686 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* linebuf.c: Maintains linebuffers.
*
* Copyright (C) 2001-2002 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: linebuf.c 1110 2006-03-29 22:55:25Z nenolod $
*/
#include "stdinc.h"
#include "tools.h"
#include "client.h"
#include "linebuf.h"
#include "memory.h"
#include "event.h"
#include "balloc.h"
#include "hook.h"
#include "commio.h"
#include "sprintf_irc.h"
#ifdef STRING_WITH_STRINGS
# include <string.h>
# include <strings.h>
#else
# ifdef HAVE_STRING_H
# include <string.h>
# else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
# endif
#endif
extern BlockHeap *linebuf_heap;
static int bufline_count = 0;
/*
* linebuf_init
*
* Initialise the linebuf mechanism
*/
void
linebuf_init(void)
{
linebuf_heap = BlockHeapCreate(sizeof(buf_line_t), LINEBUF_HEAP_SIZE);
}
static buf_line_t *
linebuf_allocate(void)
{
buf_line_t *t;
t = BlockHeapAlloc(linebuf_heap);
t->refcount = 0;
return (t);
}
static void
linebuf_free(buf_line_t * p)
{
BlockHeapFree(linebuf_heap, p);
}
/*
* linebuf_new_line
*
* Create a new line, and link it to the given linebuf.
* It will be initially empty.
*/
static buf_line_t *
linebuf_new_line(buf_head_t * bufhead)
{
buf_line_t *bufline;
dlink_node *node;
bufline = linebuf_allocate();
if(bufline == NULL)
return NULL;
++bufline_count;
node = make_dlink_node();
bufline->len = 0;
bufline->terminated = 0;
bufline->flushing = 0;
bufline->raw = 0;
/* Stick it at the end of the buf list */
dlinkAddTail(bufline, node, &bufhead->list);
bufline->refcount++;
/* And finally, update the allocated size */
bufhead->alloclen++;
bufhead->numlines++;
return bufline;
}
/*
* linebuf_done_line
*
* We've finished with the given line, so deallocate it
*/
static void
linebuf_done_line(buf_head_t * bufhead, buf_line_t * bufline, dlink_node * node)
{
/* Remove it from the linked list */
dlinkDestroy(node, &bufhead->list);
/* Update the allocated size */
bufhead->alloclen--;
bufhead->len -= bufline->len;
s_assert(bufhead->len >= 0);
bufhead->numlines--;
bufline->refcount--;
s_assert(bufline->refcount >= 0);
if(bufline->refcount == 0)
{
/* and finally, deallocate the buf */
--bufline_count;
s_assert(bufline_count >= 0);
linebuf_free(bufline);
}
}
/*
* skip to end of line or the crlfs, return the number of bytes ..
*/
static inline int
linebuf_skip_crlf(char *ch, int len)
{
int orig_len = len;
/* First, skip until the first non-CRLF */
for (; len; len--, ch++)
{
if(*ch == '\r')
break;
else if(*ch == '\n')
break;
}
/* Then, skip until the last CRLF */
for (; len; len--, ch++)
{
if((*ch != '\r') && (*ch != '\n'))
break;
}
s_assert(orig_len > len);
return (orig_len - len);
}
/*
* linebuf_newbuf
*
* Initialise the new buffer
*/
void
linebuf_newbuf(buf_head_t * bufhead)
{
/* not much to do right now :) */
memset(bufhead, 0, sizeof(buf_head_t));
}
/*
* client_flush_input
*
* inputs - pointer to client
* output - none
* side effects - all input line bufs are flushed
*/
void
client_flush_input(struct Client *client_p)
{
/* This way, it can be called for remote client as well */
if(client_p->localClient == NULL)
return;
linebuf_donebuf(&client_p->localClient->buf_recvq);
}
/*
* linebuf_donebuf
*
* Flush all the lines associated with this buffer
*/
void
linebuf_donebuf(buf_head_t * bufhead)
{
while (bufhead->list.head != NULL)
{
linebuf_done_line(bufhead,
(buf_line_t *) bufhead->list.head->data, bufhead->list.head);
}
}
/*
* linebuf_copy_line
*
* Okay..this functions comments made absolutely no sense.
*
* Basically what we do is this. Find the first chunk of text
* and then scan for a CRLF. If we didn't find it, but we didn't
* overflow our buffer..we wait for some more data.
* If we found a CRLF, we replace them with a \0 character.
* If we overflowed, we copy the most our buffer can handle, terminate
* it with a \0 and return.
*
* The return value is the amount of data we consumed. This could
* be different than the size of the linebuffer, as when we discard
* the overflow, we don't want to process it again.
*
* This still sucks in my opinion, but it seems to work.
*
* -Aaron
*/
static int
linebuf_copy_line(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
{
int cpylen = 0; /* how many bytes we've copied */
char *ch = data; /* Pointer to where we are in the read data */
char *bufch = bufline->buf + bufline->len;
int clen = 0; /* how many bytes we've processed,
and don't ever want to see again.. */
/* If its full or terminated, ignore it */
bufline->raw = 0;
s_assert(bufline->len < BUF_DATA_SIZE);
if(bufline->terminated == 1)
return 0;
clen = cpylen = linebuf_skip_crlf(ch, len);
if(clen == -1)
return -1;
/* This is the ~overflow case..This doesn't happen often.. */
if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
{
memcpy(bufch, ch, (BUF_DATA_SIZE - bufline->len - 1));
bufline->buf[BUF_DATA_SIZE - 1] = '\0';
bufch = bufline->buf + BUF_DATA_SIZE - 2;
while (cpylen && (*bufch == '\r' || *bufch == '\n'))
{
*bufch = '\0';
cpylen--;
bufch--;
}
bufline->terminated = 1;
bufline->len = BUF_DATA_SIZE - 1;
bufhead->len += BUF_DATA_SIZE - 1;
return clen;
}
memcpy(bufch, ch, cpylen);
bufch += cpylen;
*bufch = '\0';
bufch--;
if(*bufch != '\r' && *bufch != '\n')
{
/* No linefeed, bail for the next time */
bufhead->len += cpylen;
bufline->len += cpylen;
bufline->terminated = 0;
return clen;
}
/* Yank the CRLF off this, replace with a \0 */
while (cpylen && (*bufch == '\r' || *bufch == '\n'))
{
*bufch = '\0';
cpylen--;
bufch--;
}
bufline->terminated = 1;
bufhead->len += cpylen;
bufline->len += cpylen;
return clen;
}
/*
* linebuf_copy_raw
*
* Copy as much data as possible directly into a linebuf,
* splitting at \r\n, but without altering any data.
*
*/
static int
linebuf_copy_raw(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
{
int cpylen = 0; /* how many bytes we've copied */
char *ch = data; /* Pointer to where we are in the read data */
char *bufch = bufline->buf + bufline->len;
int clen = 0; /* how many bytes we've processed,
and don't ever want to see again.. */
/* If its full or terminated, ignore it */
bufline->raw = 1;
s_assert(bufline->len < BUF_DATA_SIZE);
if(bufline->terminated == 1)
return 0;
clen = cpylen = linebuf_skip_crlf(ch, len);
if(clen == -1)
return -1;
/* This is the overflow case..This doesn't happen often.. */
if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
{
clen = BUF_DATA_SIZE - bufline->len - 1;
memcpy(bufch, ch, clen);
bufline->buf[BUF_DATA_SIZE - 1] = '\0';
bufch = bufline->buf + BUF_DATA_SIZE - 2;
bufline->terminated = 1;
bufline->len = BUF_DATA_SIZE - 1;
bufhead->len += BUF_DATA_SIZE - 1;
return clen;
}
memcpy(bufch, ch, cpylen);
bufch += cpylen;
*bufch = '\0';
bufch--;
if(*bufch != '\r' && *bufch != '\n')
{
/* No linefeed, bail for the next time */
bufhead->len += cpylen;
bufline->len += cpylen;
bufline->terminated = 0;
return clen;
}
bufline->terminated = 1;
bufhead->len += cpylen;
bufline->len += cpylen;
return clen;
}
/*
* linebuf_parse
*
* Take a given buffer and break out as many buffers as we can.
* If we find a CRLF, we terminate that buffer and create a new one.
* If we don't find a CRLF whilst parsing a buffer, we don't mark it
* 'finished', so the next loop through we can continue appending ..
*
* A few notes here, which you'll need to understand before continuing.
*
* - right now I'm only dealing with single sized buffers. Later on,
* I might consider chaining buffers together to get longer "lines"
* but seriously, I don't see the advantage right now.
*
* - This *is* designed to turn into a reference-counter-protected setup
* to dodge copious copies.
*/
int
linebuf_parse(buf_head_t * bufhead, char *data, int len, int raw)
{
buf_line_t *bufline;
int cpylen;
int linecnt = 0;
/* First, if we have a partial buffer, try to squeze data into it */
if(bufhead->list.tail != NULL)
{
/* Check we're doing the partial buffer thing */
bufline = bufhead->list.tail->data;
s_assert(!bufline->flushing);
/* just try, the worst it could do is *reject* us .. */
if(!raw)
cpylen = linebuf_copy_line(bufhead, bufline, data, len);
else
cpylen = linebuf_copy_raw(bufhead, bufline, data, len);
if(cpylen == -1)
return -1;
linecnt++;
/* If we've copied the same as what we've got, quit now */
if(cpylen == len)
return linecnt; /* all the data done so soon? */
/* Skip the data and update len .. */
len -= cpylen;
s_assert(len >= 0);
data += cpylen;
}
/* Next, the loop */
while (len > 0)
{
/* We obviously need a new buffer, so .. */
bufline = linebuf_new_line(bufhead);
/* And parse */
if(!raw)
cpylen = linebuf_copy_line(bufhead, bufline, data, len);
else
cpylen = linebuf_copy_raw(bufhead, bufline, data, len);
if(cpylen == -1)
return -1;
len -= cpylen;
s_assert(len >= 0);
data += cpylen;
linecnt++;
}
return linecnt;
}
/*
* linebuf_get
*
* get the next buffer from our line. For the time being it will copy
* data into the given buffer and free the underlying linebuf.
*/
int
linebuf_get(buf_head_t * bufhead, char *buf, int buflen, int partial, int raw)
{
buf_line_t *bufline;
int cpylen;
char *start, *ch;
/* make sure we have a line */
if(bufhead->list.head == NULL)
return 0; /* Obviously not.. hrm. */
bufline = bufhead->list.head->data;
/* make sure that the buffer was actually *terminated */
if(!(partial || bufline->terminated))
return 0; /* Wait for more data! */
/* make sure we've got the space, including the NULL */
cpylen = bufline->len;
s_assert(cpylen + 1 <= buflen);
/* Copy it */
start = bufline->buf;
/* if we left extraneous '\r\n' characters in the string,
* and we don't want to read the raw data, clean up the string.
*/
if(bufline->raw && !raw)
{
/* skip leading EOL characters */
while (cpylen && (*start == '\r' || *start == '\n'))
{
start++;
cpylen--;
}
/* skip trailing EOL characters */
ch = &start[cpylen - 1];
while (cpylen && (*ch == '\r' || *ch == '\n'))
{
ch--;
cpylen--;
}
}
memcpy(buf, start, cpylen + 1);
/* convert CR/LF to NULL */
if(bufline->raw && !raw)
buf[cpylen] = '\0';
s_assert(cpylen >= 0);
/* Deallocate the line */
linebuf_done_line(bufhead, bufline, bufhead->list.head);
/* return how much we copied */
return cpylen;
}
/*
* linebuf_attach
*
* attach the lines in a buf_head_t to another buf_head_t
* without copying the data (using refcounts).
*/
void
linebuf_attach(buf_head_t * bufhead, buf_head_t * new)
{
dlink_node *ptr;
buf_line_t *line;
DLINK_FOREACH(ptr, new->list.head)
{
line = ptr->data;
dlinkAddTailAlloc(line, &bufhead->list);
/* Update the allocated size */
bufhead->alloclen++;
bufhead->len += line->len;
bufhead->numlines++;
line->refcount++;
}
}
/*
* linebuf_putmsg
*
* Similar to linebuf_put, but designed for use by send.c.
*
* prefixfmt is used as a format for the varargs, and is inserted first.
* Then format/va_args is appended to the buffer.
*/
void
linebuf_putmsg(buf_head_t * bufhead, const char *format, va_list * va_args,
const char *prefixfmt, ...)
{
buf_line_t *bufline;
int len = 0;
va_list prefix_args;
/* make sure the previous line is terminated */
#ifndef NDEBUG
if(bufhead->list.tail)
{
bufline = bufhead->list.tail->data;
s_assert(bufline->terminated);
}
#endif
/* Create a new line */
bufline = linebuf_new_line(bufhead);
if(prefixfmt != NULL)
{
va_start(prefix_args, prefixfmt);
len = ircvsnprintf(bufline->buf, BUF_DATA_SIZE, prefixfmt, prefix_args);
va_end(prefix_args);
}
if(va_args != NULL)
{
len += ircvsnprintf((bufline->buf + len), (BUF_DATA_SIZE - len), format, *va_args);
}
bufline->terminated = 1;
/* Truncate the data if required */
if(len > 510)
{
len = 510;
bufline->buf[len++] = '\r';
bufline->buf[len++] = '\n';
}
else if(len == 0)
{
bufline->buf[len++] = '\r';
bufline->buf[len++] = '\n';
bufline->buf[len] = '\0';
}
else
{
/* Chop trailing CRLF's .. */
while ((bufline->buf[len] == '\r')
|| (bufline->buf[len] == '\n') || (bufline->buf[len] == '\0'))
{
len--;
}
bufline->buf[++len] = '\r';
bufline->buf[++len] = '\n';
bufline->buf[++len] = '\0';
}
bufline->len = len;
bufhead->len += len;
}
/*
* linebuf_flush
*
* Flush data to the buffer. It tries to write as much data as possible
* to the given socket. Any return values are passed straight through.
* If there is no data in the socket, EWOULDBLOCK is set as an errno
* rather than returning 0 (which would map to an EOF..)
*
* Notes: XXX We *should* have a clue here when a non-full buffer is arrived.
* and tag it so that we don't re-schedule another write until
* we have a CRLF.
*/
int
linebuf_flush(fde_t *fd, buf_head_t * bufhead)
{
buf_line_t *bufline;
int retval;
/* Check we actually have a first buffer */
if(bufhead->list.head == NULL)
{
/* nope, so we return none .. */
errno = EWOULDBLOCK;
return -1;
}
bufline = bufhead->list.head->data;
/* And that its actually full .. */
if(!bufline->terminated)
{
errno = EWOULDBLOCK;
return -1;
}
/* Check we're flushing the first buffer */
if(!bufline->flushing)
{
bufline->flushing = 1;
bufhead->writeofs = 0;
}
/* Now, try writing data */
retval = fd->write_impl(fd, bufline->buf + bufhead->writeofs, bufline->len - bufhead->writeofs);
if(retval <= 0)
return retval;
/* we've got data, so update the write offset */
bufhead->writeofs += retval;
/* if we've written everything *and* the CRLF, deallocate and update
bufhead */
if(bufhead->writeofs == bufline->len)
{
bufhead->writeofs = 0;
s_assert(bufhead->len >= 0);
linebuf_done_line(bufhead, bufline, bufhead->list.head);
}
/* Return line length */
return retval;
}
/*
* count linebufs for stats z
*/
void
count_linebuf_memory(size_t * count, size_t * linebuf_memory_used)
{
BlockHeapUsage(linebuf_heap, count, NULL, linebuf_memory_used);
}

View file

@ -1,87 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* linebuf.h: A header for the linebuf code.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox development team
*
* 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
*
* $Id: linebuf.h 376 2005-12-07 15:00:41Z nenolod $
*/
#ifndef __LINEBUF_H__
#define __LINEBUF_H__
#include "tools.h"
#include "commio.h"
/* How big we want a buffer - 510 data bytes, plus space for a '\0' */
#define BUF_DATA_SIZE 511
#define LINEBUF_COMPLETE 0
#define LINEBUF_PARTIAL 1
#define LINEBUF_PARSED 0
#define LINEBUF_RAW 1
struct _buf_line;
struct _buf_head;
typedef struct _buf_line buf_line_t;
typedef struct _buf_head buf_head_t;
struct _buf_line
{
char buf[BUF_DATA_SIZE + 2];
unsigned int terminated; /* Whether we've terminated the buffer */
unsigned int flushing; /* Whether we're flushing .. */
unsigned int raw; /* Whether this linebuf may hold 8-bit data */
int len; /* How much data we've got */
int refcount; /* how many linked lists are we in? */
struct _buf_line *next; /* next in free list */
};
struct _buf_head
{
dlink_list list; /* the actual dlink list */
int len; /* length of all the data */
int alloclen; /* Actual allocated data length */
int writeofs; /* offset in the first line for the write */
int numlines; /* number of lines */
};
/* they should be functions, but .. */
#define linebuf_len(x) ((x)->len)
#define linebuf_alloclen(x) ((x)->alloclen)
#define linebuf_numlines(x) ((x)->numlines)
extern void linebuf_init(void);
/* declared as static */
/* extern buf_line_t *linebuf_new_line(buf_head_t *); */
/* extern void linebuf_done_line(buf_head_t *, buf_line_t *, dlink_node *); */
/* extern int linebuf_skip_crlf(char *, int); */
/* extern void linebuf_terminate_crlf(buf_head_t *, buf_line_t *); */
extern void linebuf_newbuf(buf_head_t *);
extern void client_flush_input(struct Client *);
extern void linebuf_donebuf(buf_head_t *);
extern int linebuf_parse(buf_head_t *, char *, int, int);
extern int linebuf_get(buf_head_t *, char *, int, int, int);
extern void linebuf_putmsg(buf_head_t *, const char *, va_list *, const char *, ...);
extern int linebuf_flush(fde_t *, buf_head_t *);
extern void linebuf_attach(buf_head_t *, buf_head_t *);
extern void count_linebuf_memory(size_t *, size_t *);
#endif

View file

@ -1,75 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* memory.c: Memory utilities.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: memory.c 388 2005-12-07 16:34:40Z nenolod $
*/
#define WE_ARE_MEMORY_C
#include "libcharybdis.h"
/*
* MyMalloc - allocate memory, call outofmemory on failure
*/
void *
MyMalloc(size_t size)
{
void *ret = calloc(1, size);
if(ret == NULL)
outofmemory();
return ret;
}
/*
* MyRealloc - reallocate memory, call outofmemory on failure
*/
void *
MyRealloc(void *x, size_t y)
{
void *ret = realloc(x, y);
if(ret == NULL)
outofmemory();
return ret;
}
/*
* outofmemory()
*
* input - NONE
* output - NONE
* side effects - simply try to report there is a problem. Abort if it was called more than once
*/
void
outofmemory()
{
static int was_here = 0;
if(was_here)
libcharybdis_die("Out of Memory!");
was_here = 1;
libcharybdis_restart("Aiee! Out of memory... >_<!");
}

View file

@ -1,79 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* memory.h: A header for the memory functions.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox development team
*
* 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
*
* $Id: memory.h 382 2005-12-07 15:15:59Z nenolod $
*/
#ifndef _I_MEMORY_H
#define _I_MEMORY_H
#include "ircd_defs.h"
#include "setup.h"
#include "balloc.h"
/* Needed to use uintptr_t for some pointer manipulation. */
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#else /* No inttypes.h */
#ifndef HAVE_UINTPTR_T
typedef unsigned long uintptr_t;
#endif
#endif
extern void outofmemory(void);
extern void *MyMalloc(size_t size);
extern void *MyRealloc(void *x, size_t y);
/* forte (and maybe others) dont like double declarations,
* so we dont declare the inlines unless GNUC
*/
/* darwin doesnt like these.. */
#ifndef __APPLE__
#ifdef __GNUC__
extern inline void *
MyMalloc(size_t size)
{
void *ret = calloc(1, size);
if(ret == NULL)
outofmemory();
return (ret);
}
extern inline void *
MyRealloc(void *x, size_t y)
{
void *ret = realloc(x, y);
if(ret == NULL)
outofmemory();
return (ret);
}
#endif /* __GNUC__ */
#endif /* __APPLE__ */
#define MyFree(x) do { if(x) free(x); } while (0)
#endif /* _I_MEMORY_H */

View file

@ -1,305 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* s_bsd_poll.c: POSIX poll() compatible network routines.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: poll.c 3528 2007-07-07 08:08:23Z nenolod $
*/
#include "config.h"
#include "stdinc.h"
#include <sys/poll.h>
#include "libcharybdis.h"
/* I hate linux -- adrian */
#ifndef POLLRDNORM
#define POLLRDNORM POLLIN
#endif
#ifndef POLLWRNORM
#define POLLWRNORM POLLOUT
#endif
struct _pollfd_list
{
struct pollfd *pollfds;
int maxindex; /* highest FD number */
int allocated;
};
typedef struct _pollfd_list pollfd_list_t;
pollfd_list_t pollfd_list;
static void poll_update_pollfds(int, short, PF *);
static unsigned long last_count = 0;
static unsigned long empty_count = 0;
/*
* init_netio
*
* This is a needed exported function which will be called to initialise
* the network loop code.
*/
void
init_netio(void)
{
int fd;
int maxconn = comm_get_maxconnections();
pollfd_list.pollfds = calloc(sizeof(struct pollfd), maxconn);
for (fd = 0; fd < maxconn; fd++)
pollfd_list.pollfds[fd].fd = -1;
pollfd_list.maxindex = 0;
pollfd_list.allocated = maxconn;
}
static inline void
resize_poll_array(int fd)
{
int i, old_value = pollfd_list.allocated;
if (fd < pollfd_list.allocated)
return;
pollfd_list.allocated += 1024;
pollfd_list.pollfds = MyRealloc(pollfd_list.pollfds, pollfd_list.allocated * sizeof(struct pollfd));
/* because realloced memory can contain junk, we have to zero it out. */
memset(&pollfd_list.pollfds[old_value+1], 0, sizeof(struct pollfd) * 1024);
for (i = old_value + 1; i <= pollfd_list.allocated; i++)
pollfd_list.pollfds[i].fd = -1;
}
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Private functions */
/*
* find a spare slot in the fd list. We can optimise this out later!
* -- adrian
*/
static inline int
poll_findslot(void)
{
int i;
for (i = 0; i < pollfd_list.allocated; i++)
{
if(pollfd_list.pollfds[i].fd == -1)
{
/* MATCH!!#$*&$ */
return i;
}
}
s_assert(1 == 0);
/* NOTREACHED */
return -1;
}
/*
* set and clear entries in the pollfds[] array.
*/
static void
poll_update_pollfds(int fd, short event, PF * handler)
{
fde_t *F = comm_locate_fd(fd);
int comm_index;
resize_poll_array(fd);
if (F == NULL)
F = comm_add_fd(fd);
if(F->comm_index < 0)
F->comm_index = poll_findslot();
comm_index = F->comm_index;
/* Update the events */
if(handler)
{
F->list = FDLIST_IDLECLIENT;
pollfd_list.pollfds[comm_index].events |= event;
pollfd_list.pollfds[comm_index].fd = fd;
/* update maxindex here */
if(comm_index > pollfd_list.maxindex)
pollfd_list.maxindex = comm_index;
}
else
{
if(comm_index >= 0)
{
pollfd_list.pollfds[comm_index].events &= ~event;
if(pollfd_list.pollfds[comm_index].events == 0)
{
pollfd_list.pollfds[comm_index].fd = -1;
pollfd_list.pollfds[comm_index].revents = 0;
F->comm_index = -1;
F->list = FDLIST_NONE;
/* update pollfd_list.maxindex here */
if(comm_index == pollfd_list.maxindex)
while (pollfd_list.maxindex >= 0 &&
pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
pollfd_list.maxindex--;
}
}
}
}
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Public functions */
/*
* comm_setselect
*
* This is a needed exported function which will be called to register
* and deregister interest in a pending IO state for a given FD.
*/
void
comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
void *client_data, time_t timeout)
{
fde_t *F = comm_locate_fd(fd);
s_assert(fd >= 0);
s_assert(F->flags.open);
if(type & COMM_SELECT_READ)
{
F->read_handler = handler;
F->read_data = client_data;
poll_update_pollfds(fd, POLLRDNORM, handler);
}
if(type & COMM_SELECT_WRITE)
{
F->write_handler = handler;
F->write_data = client_data;
poll_update_pollfds(fd, POLLWRNORM, handler);
}
if(timeout)
F->timeout = CurrentTime + (timeout / 1000);
}
static void
irc_sleep(unsigned long useconds)
{
#ifdef HAVE_NANOSLEEP
struct timespec t;
t.tv_sec = useconds / (unsigned long) 1000000;
t.tv_nsec = (useconds % (unsigned long) 1000000) * 1000;
nanosleep(&t, (struct timespec *) NULL);
#else
struct timeval t;
t.tv_sec = 0;
t.tv_usec = useconds;
select(0, NULL, NULL, NULL, &t);
#endif
return;
}
/* int comm_select_fdlist(unsigned long delay)
* Input: The maximum time to delay.
* Output: Returns -1 on error, 0 on success.
* Side-effects: Deregisters future interest in IO and calls the handlers
* if an event occurs for an FD.
* Comments: Check all connections for new connections and input data
* that is to be processed. Also check for connections with data queued
* and whether we can write it out.
* Called to do the new-style IO, courtesy of squid (like most of this
* new IO code). This routine handles the stuff we've hidden in
* comm_setselect and fd_table[] and calls callbacks for IO ready
* events.
*/
int
comm_select(unsigned long delay)
{
int num;
int fd;
int ci;
unsigned long ndelay;
PF *hdl;
if(last_count > 0)
{
empty_count = 0;
ndelay = 0;
}
else {
ndelay = ++empty_count * 15000 ;
if(ndelay > delay * 1000)
ndelay = delay * 1000;
}
for (;;)
{
/* XXX kill that +1 later ! -- adrian */
if(ndelay > 0)
irc_sleep(ndelay);
last_count = num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0);
if(num >= 0)
break;
if(ignoreErrno(errno))
continue;
/* error! */
set_time();
return -1;
/* NOTREACHED */
}
/* update current time again, eww.. */
set_time();
if(num == 0)
return 0;
/* XXX we *could* optimise by falling out after doing num fds ... */
for (ci = 0; ci < pollfd_list.maxindex + 1; ci++)
{
fde_t *F;
int revents;
if(((revents = pollfd_list.pollfds[ci].revents) == 0) ||
(pollfd_list.pollfds[ci].fd) == -1)
continue;
fd = pollfd_list.pollfds[ci].fd;
F = comm_locate_fd(fd);
if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
{
hdl = F->read_handler;
F->read_handler = NULL;
poll_update_pollfds(fd, POLLRDNORM, NULL);
if(hdl)
hdl(fd, F->read_data);
}
if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
{
hdl = F->write_handler;
F->write_handler = NULL;
poll_update_pollfds(fd, POLLWRNORM, NULL);
if(hdl)
hdl(fd, F->write_data);
}
}
return 0;
}

View file

@ -1,180 +0,0 @@
/*
* charybdis: A slightly useful ircd.
* ports.c: Solaris ports compatible network routines.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002-2004 ircd-ratbox development team
* Copyright (C) 2005 Edward Brocklesby.
* Copyright (C) 2005 William Pitcock and Jilles Tjoelker
* Copyright (C) 2007 River Tarnell
*
* 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
*
* $Id: ports.c 3366 2007-04-03 09:57:53Z nenolod $
*/
#include "stdinc.h"
#include <port.h>
#include <time.h>
#include "stdinc.h"
#include "res.h"
#include "numeric.h"
#include "tools.h"
#include "memory.h"
#include "balloc.h"
#include "linebuf.h"
#include "sprintf_irc.h"
#include "commio.h"
#include "ircevent.h"
#include "modules.h"
static int comm_init(void);
static void comm_deinit(void);
static int comm_select_impl(unsigned long delay);
static void comm_setselect_impl(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout);
static void pe_update_events(fde_t *, short, PF *);
static int pe;
static struct timespec zero_timespec;
static port_event_t *pelst; /* port buffer */
static int pemax; /* max structs to buffer */
static void
pe_update_events(fde_t * F, short filter, PF * handler)
{
PF *cur_handler = NULL;
if (filter == POLLRDNORM)
cur_handler = F->read_handler;
else if (filter == POLLWRNORM)
cur_handler = F->write_handler;
if (!cur_handler && handler)
port_associate(pe, PORT_SOURCE_FD, F->fd, filter, F);
else if (cur_handler && !handler)
port_dissociate(pe, PORT_SOURCE_FD, F->fd);
}
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Public functions */
/*
* init_netio
*
* This is a needed exported function which will be called to initialise
* the network loop code.
*/
static int
init_netio(void)
{
if((pe = port_create()) < 0) {
ilog(L_MAIN, "init_netio: Couldn't open port fd!\n");
exit(115); /* Whee! */
}
pemax = getdtablesize();
pelst = MyMalloc(sizeof(port_event_t) * pemax);
zero_timespec.tv_sec = 0;
zero_timespec.tv_nsec = 0;
return 0;
}
/*
* ircd_setselect
*
* This is a needed exported function which will be called to register
* and deregister interest in a pending IO state for a given FD.
*/
void
comm_setselect(int fd, unsigned int type, PF * handler,
void *client_data, time_t timeout)
{
fde_t *F = &fd_table[fd];
s_assert(fd >= 0);
s_assert(F->flags.open);
if (type & COMM_SELECT_READ) {
pe_update_events(F, POLLRDNORM, handler);
F->read_handler = handler;
F->read_data = client_data;
}
if (type & COMM_SELECT_WRITE) {
pe_update_events(F, POLLWRNORM, handler);
F->write_handler = handler;
F->write_data = client_data;
}
}
/*
* ircd_select
*
* Called to do the new-style IO, courtesy of squid (like most of this
* new IO code). This routine handles the stuff we've hidden in
* ircd_setselect and fd_table[] and calls callbacks for IO ready
* events.
*/
int
comm_select(unsigned long delay)
{
int i, fd;
unsigned int nget = 1;
struct timespec poll_time;
poll_time.tv_sec = delay / 1000;
poll_time.tv_nsec = (delay % 1000) * 1000000;
i = port_getn(pe, pelst, pemax, &nget, &poll_time);
set_time();
if (i == -1)
return COMM_ERROR;
for (i = 0; i < nget; i++)
{
PF *hdl = NULL;
fde_t *F;
switch(pelst[i].portev_source)
{
case PORT_SOURCE_FD:
fd = pelst[i].portev_object;
F = &fd_table[fd];
if ((pelst[i].portev_events & POLLRDNORM) && (hdl = F->read_handler)) {
F->read_handler = NULL;
hdl(fd, F->read_data);
}
if (F->flags.open == 0)
continue;
if ((pelst[i].portev_events & POLLWRNORM) && (hdl = F->write_handler)) {
F->write_handler = NULL;
hdl(fd, F->write_data);
}
break;
default:
break;
}
}
return COMM_OK;
}

View file

@ -1,202 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* select.c: select() compatible network routines.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: select.c 3528 2007-07-07 08:08:23Z nenolod $
*/
#include "config.h"
#include "libcharybdis.h"
/*
* Note that this is only a single list - multiple lists is kinda pointless
* under select because the list size is a function of the highest FD :-)
* -- adrian
*/
fd_set select_readfds;
fd_set select_writefds;
/*
* You know, I'd rather have these local to comm_select but for some
* reason my gcc decides that I can't modify them at all..
* -- adrian
*/
fd_set tmpreadfds;
fd_set tmpwritefds;
static void select_update_selectfds(int fd, short event, PF * handler);
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Private functions */
/*
* set and clear entries in the select array ..
*/
static void
select_update_selectfds(int fd, short event, PF * handler)
{
/* Update the read / write set */
if(event & COMM_SELECT_READ)
{
if(handler)
FD_SET(fd, &select_readfds);
else
FD_CLR(fd, &select_readfds);
}
if(event & COMM_SELECT_WRITE)
{
if(handler)
FD_SET(fd, &select_writefds);
else
FD_CLR(fd, &select_writefds);
}
}
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Public functions */
/*
* init_netio
*
* This is a needed exported function which will be called to initialise
* the network loop code.
*/
void
init_netio(void)
{
FD_ZERO(&select_readfds);
FD_ZERO(&select_writefds);
}
/*
* comm_setselect
*
* This is a needed exported function which will be called to register
* and deregister interest in a pending IO state for a given FD.
*/
void
comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
void *client_data, time_t timeout)
{
fde_t *F = comm_locate_fd(fd);
s_assert(fd >= 0);
if (!F)
F = comm_add_fd(fd);
if(type & COMM_SELECT_READ)
{
F->read_handler = handler;
F->read_data = client_data;
select_update_selectfds(fd, COMM_SELECT_READ, handler);
}
if(type & COMM_SELECT_WRITE)
{
F->write_handler = handler;
F->write_data = client_data;
select_update_selectfds(fd, COMM_SELECT_WRITE, handler);
}
if(timeout)
F->timeout = CurrentTime + (timeout / 1000);
}
/*
* Check all connections for new connections and input data that is to be
* processed. Also check for connections with data queued and whether we can
* write it out.
*/
/*
* comm_select
*
* Do IO events
*/
int
comm_select(unsigned long delay)
{
int num;
int fd;
PF *hdl;
fde_t *F;
struct timeval to;
/* Copy over the read/write sets so we don't have to rebuild em */
memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set));
memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set));
for (;;)
{
to.tv_sec = 0;
to.tv_usec = delay * 1000;
num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
if(num >= 0)
break;
if(ignoreErrno(errno))
continue;
set_time();
/* error! */
return -1;
/* NOTREACHED */
}
set_time();
if(num == 0)
return 0;
/* XXX we *could* optimise by falling out after doing num fds ... */
for (fd = 0; fd < highest_fd + 1; fd++)
{
F = comm_locate_fd(fd);
if(FD_ISSET(fd, &tmpreadfds))
{
hdl = F->read_handler;
F->read_handler = NULL;
if(hdl)
hdl(fd, F->read_data);
}
if(F->flags.open == 0)
continue; /* Read handler closed us..go on */
if(FD_ISSET(fd, &tmpwritefds))
{
hdl = F->write_handler;
F->write_handler = NULL;
if(hdl)
hdl(fd, F->write_data);
}
if(F->read_handler == NULL)
select_update_selectfds(fd, COMM_SELECT_READ, NULL);
if(F->write_handler == NULL)
select_update_selectfds(fd, COMM_SELECT_WRITE, NULL);
}
return 0;
}

View file

@ -1,981 +0,0 @@
/*
* libString, Copyright (C) 1999 Patrick Alken
* This library comes with absolutely NO WARRANTY
*
* Should you choose to use and/or modify this source code, please
* do so under the terms of the GNU General Public License under which
* this library is distributed.
*
* $Id: snprintf.c 382 2005-12-07 15:15:59Z nenolod $
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include "setup.h"
#include "sprintf_irc.h"
/*
* This table is arranged in chronological order from 0-999,
* however the numbers are written backwards, so the number 100
* is expressed in this table as "001".
* It's purpose is to ensure fast conversions from integers to
* ASCII strings. When an integer variable is encountered, a
* simple hash algorithm is used to determine where to look
* in this array for the corresponding string.
* This outperforms continually dividing by 10 and using the
* digit obtained as a character, because we can now divide by
* 1000 and use the remainder directly, thus cutting down on
* the number of costly divisions needed. For an integer's worst
* case, 2 divisions are needed because it can only go up to
* 32767, so after 2 divisions by 1000, and some algebra, we will
* be left with 327 which we can get from this table. This is much
* better than the 5 divisions by 10 that we would need if we did
* it the conventional way. Of course, if we made this table go
* from 0-9999, only 1 division would be needed.
* Longs and unsigned ints of course, are another matter :-).
*
* Patrick Alken <wnder@underworld.net>
*/
/*
* Set this to the number of indices (numbers) in our table
*/
#define TABLE_MAX 1000
static const char *IntTable[] = {
"000", "100", "200", "300", "400",
"500", "600", "700", "800", "900",
"010", "110", "210", "310", "410",
"510", "610", "710", "810", "910",
"020", "120", "220", "320", "420",
"520", "620", "720", "820", "920",
"030", "130", "230", "330", "430",
"530", "630", "730", "830", "930",
"040", "140", "240", "340", "440",
"540", "640", "740", "840", "940",
"050", "150", "250", "350", "450",
"550", "650", "750", "850", "950",
"060", "160", "260", "360", "460",
"560", "660", "760", "860", "960",
"070", "170", "270", "370", "470",
"570", "670", "770", "870", "970",
"080", "180", "280", "380", "480",
"580", "680", "780", "880", "980",
"090", "190", "290", "390", "490",
"590", "690", "790", "890", "990",
"001", "101", "201", "301", "401",
"501", "601", "701", "801", "901",
"011", "111", "211", "311", "411",
"511", "611", "711", "811", "911",
"021", "121", "221", "321", "421",
"521", "621", "721", "821", "921",
"031", "131", "231", "331", "431",
"531", "631", "731", "831", "931",
"041", "141", "241", "341", "441",
"541", "641", "741", "841", "941",
"051", "151", "251", "351", "451",
"551", "651", "751", "851", "951",
"061", "161", "261", "361", "461",
"561", "661", "761", "861", "961",
"071", "171", "271", "371", "471",
"571", "671", "771", "871", "971",
"081", "181", "281", "381", "481",
"581", "681", "781", "881", "981",
"091", "191", "291", "391", "491",
"591", "691", "791", "891", "991",
"002", "102", "202", "302", "402",
"502", "602", "702", "802", "902",
"012", "112", "212", "312", "412",
"512", "612", "712", "812", "912",
"022", "122", "222", "322", "422",
"522", "622", "722", "822", "922",
"032", "132", "232", "332", "432",
"532", "632", "732", "832", "932",
"042", "142", "242", "342", "442",
"542", "642", "742", "842", "942",
"052", "152", "252", "352", "452",
"552", "652", "752", "852", "952",
"062", "162", "262", "362", "462",
"562", "662", "762", "862", "962",
"072", "172", "272", "372", "472",
"572", "672", "772", "872", "972",
"082", "182", "282", "382", "482",
"582", "682", "782", "882", "982",
"092", "192", "292", "392", "492",
"592", "692", "792", "892", "992",
"003", "103", "203", "303", "403",
"503", "603", "703", "803", "903",
"013", "113", "213", "313", "413",
"513", "613", "713", "813", "913",
"023", "123", "223", "323", "423",
"523", "623", "723", "823", "923",
"033", "133", "233", "333", "433",
"533", "633", "733", "833", "933",
"043", "143", "243", "343", "443",
"543", "643", "743", "843", "943",
"053", "153", "253", "353", "453",
"553", "653", "753", "853", "953",
"063", "163", "263", "363", "463",
"563", "663", "763", "863", "963",
"073", "173", "273", "373", "473",
"573", "673", "773", "873", "973",
"083", "183", "283", "383", "483",
"583", "683", "783", "883", "983",
"093", "193", "293", "393", "493",
"593", "693", "793", "893", "993",
"004", "104", "204", "304", "404",
"504", "604", "704", "804", "904",
"014", "114", "214", "314", "414",
"514", "614", "714", "814", "914",
"024", "124", "224", "324", "424",
"524", "624", "724", "824", "924",
"034", "134", "234", "334", "434",
"534", "634", "734", "834", "934",
"044", "144", "244", "344", "444",
"544", "644", "744", "844", "944",
"054", "154", "254", "354", "454",
"554", "654", "754", "854", "954",
"064", "164", "264", "364", "464",
"564", "664", "764", "864", "964",
"074", "174", "274", "374", "474",
"574", "674", "774", "874", "974",
"084", "184", "284", "384", "484",
"584", "684", "784", "884", "984",
"094", "194", "294", "394", "494",
"594", "694", "794", "894", "994",
"005", "105", "205", "305", "405",
"505", "605", "705", "805", "905",
"015", "115", "215", "315", "415",
"515", "615", "715", "815", "915",
"025", "125", "225", "325", "425",
"525", "625", "725", "825", "925",
"035", "135", "235", "335", "435",
"535", "635", "735", "835", "935",
"045", "145", "245", "345", "445",
"545", "645", "745", "845", "945",
"055", "155", "255", "355", "455",
"555", "655", "755", "855", "955",
"065", "165", "265", "365", "465",
"565", "665", "765", "865", "965",
"075", "175", "275", "375", "475",
"575", "675", "775", "875", "975",
"085", "185", "285", "385", "485",
"585", "685", "785", "885", "985",
"095", "195", "295", "395", "495",
"595", "695", "795", "895", "995",
"006", "106", "206", "306", "406",
"506", "606", "706", "806", "906",
"016", "116", "216", "316", "416",
"516", "616", "716", "816", "916",
"026", "126", "226", "326", "426",
"526", "626", "726", "826", "926",
"036", "136", "236", "336", "436",
"536", "636", "736", "836", "936",
"046", "146", "246", "346", "446",
"546", "646", "746", "846", "946",
"056", "156", "256", "356", "456",
"556", "656", "756", "856", "956",
"066", "166", "266", "366", "466",
"566", "666", "766", "866", "966",
"076", "176", "276", "376", "476",
"576", "676", "776", "876", "976",
"086", "186", "286", "386", "486",
"586", "686", "786", "886", "986",
"096", "196", "296", "396", "496",
"596", "696", "796", "896", "996",
"007", "107", "207", "307", "407",
"507", "607", "707", "807", "907",
"017", "117", "217", "317", "417",
"517", "617", "717", "817", "917",
"027", "127", "227", "327", "427",
"527", "627", "727", "827", "927",
"037", "137", "237", "337", "437",
"537", "637", "737", "837", "937",
"047", "147", "247", "347", "447",
"547", "647", "747", "847", "947",
"057", "157", "257", "357", "457",
"557", "657", "757", "857", "957",
"067", "167", "267", "367", "467",
"567", "667", "767", "867", "967",
"077", "177", "277", "377", "477",
"577", "677", "777", "877", "977",
"087", "187", "287", "387", "487",
"587", "687", "787", "887", "987",
"097", "197", "297", "397", "497",
"597", "697", "797", "897", "997",
"008", "108", "208", "308", "408",
"508", "608", "708", "808", "908",
"018", "118", "218", "318", "418",
"518", "618", "718", "818", "918",
"028", "128", "228", "328", "428",
"528", "628", "728", "828", "928",
"038", "138", "238", "338", "438",
"538", "638", "738", "838", "938",
"048", "148", "248", "348", "448",
"548", "648", "748", "848", "948",
"058", "158", "258", "358", "458",
"558", "658", "758", "858", "958",
"068", "168", "268", "368", "468",
"568", "668", "768", "868", "968",
"078", "178", "278", "378", "478",
"578", "678", "778", "878", "978",
"088", "188", "288", "388", "488",
"588", "688", "788", "888", "988",
"098", "198", "298", "398", "498",
"598", "698", "798", "898", "998",
"009", "109", "209", "309", "409",
"509", "609", "709", "809", "909",
"019", "119", "219", "319", "419",
"519", "619", "719", "819", "919",
"029", "129", "229", "329", "429",
"529", "629", "729", "829", "929",
"039", "139", "239", "339", "439",
"539", "639", "739", "839", "939",
"049", "149", "249", "349", "449",
"549", "649", "749", "849", "949",
"059", "159", "259", "359", "459",
"559", "659", "759", "859", "959",
"069", "169", "269", "369", "469",
"569", "669", "769", "869", "969",
"079", "179", "279", "379", "479",
"579", "679", "779", "879", "979",
"089", "189", "289", "389", "489",
"589", "689", "789", "889", "989",
"099", "199", "299", "399", "499",
"599", "699", "799", "899", "999"
};
/*
* Since we calculate the right-most digits for %d %u etc first,
* we need a temporary buffer to store them in until we get
* to the left-most digits
*/
#define TEMPBUF_MAX 20
static char TempBuffer[TEMPBUF_MAX];
/*
vSnprintf()
Backend to Snprintf() - performs the construction of 'dest'
using the string 'format' and the given arguments. Also makes sure
not more than 'bytes' characters are copied to 'dest'
We always allow room for a terminating \0 character, so at most,
bytes - 1 characters will be written to dest.
Return: Number of characters written, NOT including the terminating
\0 character which is *always* placed at the end of the string
NOTE: This function handles the following flags only:
%s %d %c %u %ld %lu
In addition, this function performs *NO* precision, padding,
or width formatting. If it receives an unknown % character,
it will call vsprintf() to complete the remainder of the
string.
*/
int
ircvsnprintf(char *dest, const size_t bytes, const char *format, va_list args)
{
char ch;
int written = 0; /* bytes written so far */
int maxbytes = bytes - 1;
while ((ch = *format++) && (written < maxbytes))
{
if(ch == '%')
{
/*
* Advance past the %
*/
ch = *format++;
/*
* Put the most common cases first - %s %d etc
*/
if(ch == 's')
{
const char *str = va_arg(args, const char *);
while ((*dest = *str))
{
++dest;
++str;
if(++written >= maxbytes)
break;
}
continue;
}
if(ch == 'd')
{
int num = va_arg(args, int);
int quotient;
const char *str;
char *digitptr = TempBuffer;
/*
* We have to special-case "0" unfortunately
*/
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
if(num < 0)
{
*dest++ = '-';
if(++written >= maxbytes)
continue;
num = -num;
}
do
{
quotient = num / TABLE_MAX;
/*
* We'll start with the right-most digits of 'num'.
* Dividing by TABLE_MAX cuts off all but the X
* right-most digits, where X is such that:
*
* 10^X = TABLE_MAX
*
* For example, if num = 1200, and TABLE_MAX = 1000,
* quotient will be 1. Multiplying this by 1000 and
* subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
* We then go right to slot 200 in our array and behold!
* The string "002" (200 backwards) is conveniently
* waiting for us. Then repeat the process with the
* digits left.
*
* The reason we need to have the integers written
* backwards, is because we don't know how many digits
* there are. If we want to express the number 12130
* for example, our first pass would leave us with 130,
* whose slot in the array yields "031", which we
* plug into our TempBuffer[]. The next pass gives us
* 12, whose slot yields "21" which we append to
* TempBuffer[], leaving us with "03121". This is the
* exact number we want, only backwards, so it is
* a simple matter to reverse the string. If we used
* straightfoward numbers, we would have a TempBuffer
* looking like this: "13012" which would be a nightmare
* to deal with.
*/
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
/*
* If the last quotient was a 1 or 2 digit number, there
* will be one or more leading zeroes in TempBuffer[] -
* get rid of them.
*/
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
if(++written >= maxbytes)
break;
}
continue;
} /* if (ch == 'd') */
if(ch == 'c')
{
*dest++ = va_arg(args, int);
++written;
continue;
} /* if (ch == 'c') */
if(ch == 'u')
{
unsigned int num = va_arg(args, unsigned int);
unsigned int quotient;
const char *str;
char *digitptr = TempBuffer;
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
do
{
quotient = num / TABLE_MAX;
/*
* Very similar to case 'd'
*/
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
if(++written >= maxbytes)
break;
}
continue;
} /* if (ch == 'u') */
if(ch == 'l')
{
if(*format == 'u')
{
unsigned long num = va_arg(args, unsigned long);
unsigned long quotient;
const char *str;
char *digitptr = TempBuffer;
++format;
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
do
{
quotient = num / TABLE_MAX;
/*
* Very similar to case 'u'
*/
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
if(++written >= maxbytes)
break;
}
continue;
} else /* if (*format == 'u') */
if(*format == 'd')
{
long num = va_arg(args, long);
long quotient;
const char *str;
char *digitptr = TempBuffer;
++format;
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
if(num < 0)
{
*dest++ = '-';
if(++written >= maxbytes)
continue;
num = -num;
}
do
{
quotient = num / TABLE_MAX;
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
if(++written >= maxbytes)
break;
}
continue;
} else /* if (*format == 'd') */
{
int ret;
format -= 2;
#ifdef HAVE_VSNPRINTF
ret = vsnprintf(dest, maxbytes - written, format, args);
#else
ret = vsprintf(dest, format, args);
#endif
dest += ret;
written += ret;
break;
}
} /* if (ch == 'l') */
if(ch != '%')
{
int ret;
/*
* The character might be invalid, or be a precision,
* padding, or width specification - call vsprintf()
* to finish off the string
*/
format -= 2;
#ifdef HAVE_VSNPRINTF
ret = vsnprintf(dest, maxbytes - written, format, args);
#else
ret = vsprintf(dest, format, args);
#endif
dest += ret;
written += ret;
break;
} /* if (ch != '%') */
} /* if (ch == '%') */
*dest++ = ch;
++written;
} /* while ((ch = *format++) && (written < maxbytes)) */
/*
* Terminate the destination buffer with a \0
*/
*dest = '\0';
return (written);
} /* vSnprintf() */
/*
ircvsprintf()
Backend to Sprintf() - performs the construction of 'dest'
using the string 'format' and the given arguments.
We always place a \0 character onto the end of 'dest'.
Return: Number of characters written, NOT including the terminating
\0 character which is *always* placed at the end of the string
NOTE: This function handles the following flags only:
%s %d %c %u %ld %lu
In addition, this function performs *NO* precision, padding,
or width formatting. If it receives an unknown % character,
it will call vsprintf() to complete the remainder of the
string.
*/
int
ircvsprintf(char *dest, const char *format, va_list args)
{
char ch;
int written = 0; /* bytes written so far */
while ((ch = *format++))
{
if(ch == '%')
{
/*
* Advance past the %
*/
ch = *format++;
/*
* Put the most common cases first - %s %d etc
*/
if(ch == 's')
{
const char *str = va_arg(args, const char *);
while ((*dest = *str))
{
++dest;
++str;
++written;
}
continue;
} /* if (ch == 's') */
if(ch == 'd')
{
int num = va_arg(args, int);
int quotient;
const char *str;
char *digitptr = TempBuffer;
/*
* We have to special-case "0" unfortunately
*/
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
if(num < 0)
{
*dest++ = '-';
++written;
num = -num;
}
do
{
quotient = num / TABLE_MAX;
/*
* We'll start with the right-most digits of 'num'.
* Dividing by TABLE_MAX cuts off all but the X
* right-most digits, where X is such that:
*
* 10^X = TABLE_MAX
*
* For example, if num = 1200, and TABLE_MAX = 1000,
* quotient will be 1. Multiplying this by 1000 and
* subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
* We then go right to slot 200 in our array and behold!
* The string "002" (200 backwards) is conveniently
* waiting for us. Then repeat the process with the
* digits left.
*
* The reason we need to have the integers written
* backwards, is because we don't know how many digits
* there are. If we want to express the number 12130
* for example, our first pass would leave us with 130,
* whose slot in the array yields "031", which we
* plug into our TempBuffer[]. The next pass gives us
* 12, whose slot yields "21" which we append to
* TempBuffer[], leaving us with "03121". This is the
* exact number we want, only backwards, so it is
* a simple matter to reverse the string. If we used
* straightfoward numbers, we would have a TempBuffer
* looking like this: "13012" which would be a nightmare
* to deal with.
*/
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
/*
* If the last quotient was a 1 or 2 digit number, there
* will be one or more leading zeroes in TempBuffer[] -
* get rid of them.
*/
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
++written;
}
continue;
} /* if (ch == 'd') */
if(ch == 'c')
{
*dest++ = va_arg(args, int);
++written;
continue;
} /* if (ch == 'c') */
if(ch == 'u')
{
unsigned int num = va_arg(args, unsigned int);
unsigned int quotient;
const char *str;
char *digitptr = TempBuffer;
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
do
{
quotient = num / TABLE_MAX;
/*
* Very similar to case 'd'
*/
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
++written;
}
continue;
} /* if (ch == 'u') */
if(ch == 'l')
{
if(*format == 'u')
{
unsigned long num = va_arg(args, unsigned long);
unsigned long quotient;
const char *str;
char *digitptr = TempBuffer;
++format;
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
do
{
quotient = num / TABLE_MAX;
/*
* Very similar to case 'u'
*/
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
++written;
}
continue;
} /* if (*format == 'u') */
if(*format == 'd')
{
long num = va_arg(args, long);
long quotient;
const char *str;
char *digitptr = TempBuffer;
++format;
if(num == 0)
{
*dest++ = '0';
++written;
continue;
}
if(num < 0)
{
*dest++ = '-';
++written;
num = -num;
}
do
{
quotient = num / TABLE_MAX;
str = IntTable[num - (quotient * TABLE_MAX)];
while ((*digitptr = *str))
{
++digitptr;
++str;
}
}
while ((num = quotient) != 0);
while (*(digitptr - 1) == '0')
--digitptr;
while (digitptr != TempBuffer)
{
*dest++ = *--digitptr;
++written;
}
continue;
} /* if (*format == 'd') */
continue;
} /* if (ch == 'l') */
if(ch != '%')
{
int ret;
format -= 2;
ret = vsprintf(dest, format, args);
dest += ret;
written += ret;
break;
} /* if (ch != '%') */
} /* if (ch == '%') */
*dest++ = ch;
++written;
} /* while ((ch = *format++)) */
/*
* Terminate the destination buffer with a \0
*/
*dest = '\0';
return (written);
} /* vSprintf() */
/*
ircsnprintf()
Optimized version of snprintf().
Inputs: dest - destination string
bytes - number of bytes to copy
format - formatted string
args - args to 'format'
Return: number of characters copied, NOT including the terminating
NULL which is always placed at the end of the string
*/
int
ircsnprintf(char *dest, const size_t bytes, const char *format, ...)
{
va_list args;
int count;
va_start(args, format);
count = ircvsnprintf(dest, bytes, format, args);
va_end(args);
return (count);
} /* Snprintf() */
/*
ircsprintf()
Optimized version of sprintf()
Inputs: dest - destination string
format - formatted string
args - arguments to 'format'
Return: number of characters copied, NOT including the terminating
NULL which is always placed at the end of the string
*/
int
ircsprintf(char *dest, const char *format, ...)
{
va_list args;
int count;
va_start(args, format);
count = ircvsprintf(dest, format, args);
va_end(args);
return (count);
} /* Sprintf() */

View file

@ -1,99 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* tools.c: Various functions needed here and there.
*
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* 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
*
* $Id: tools.c 3201 2007-02-04 01:59:38Z jilles $
*
* Here is the original header:
*
* Useful stuff, ripped from places ..
* adrian chadd <adrian@creative.net.au>
*
* When you update these functions make sure you update the ones in tools.h
* as well!!!
*/
#include "stdinc.h"
#define TOOLS_C
#include "tools.h"
#include "balloc.h"
#include "s_user.h"
#ifndef NDEBUG
/*
* frob some memory. debugging time.
* -- adrian
*/
void
mem_frob(void *data, int len)
{
unsigned long x = 0xdeadbeef;
unsigned char *b = (unsigned char *)&x;
int i;
char *cdata = data;
for (i = 0; i < len; i++)
{
*cdata = b[i % 4];
cdata++;
}
}
#endif
/*
* init_dlink_nodes
*
*/
extern BlockHeap *dnode_heap;
void
init_dlink_nodes(void)
{
dnode_heap = BlockHeapCreate(sizeof(dlink_node), DNODE_HEAP_SIZE);
if(dnode_heap == NULL)
outofmemory();
}
/*
* make_dlink_node
*
* inputs - NONE
* output - pointer to new dlink_node
* side effects - NONE
*/
dlink_node *
make_dlink_node(void)
{
return(BlockHeapAlloc(dnode_heap));
}
/*
* free_dlink_node
*
* inputs - pointer to dlink_node
* output - NONE
* side effects - free given dlink_node
*/
void
free_dlink_node(dlink_node * ptr)
{
assert(ptr != NULL);
BlockHeapFree(dnode_heap, ptr);
}

View file

@ -1,378 +0,0 @@
/*
* ircd-ratbox: A slightly useful ircd.
* tools.h: Header for the various tool functions.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2004 ircd-ratbox development team
*
* 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
*
* $Id: tools.h 3201 2007-02-04 01:59:38Z jilles $
*/
#ifndef __LIBCHARYBDIS_TOOLS_H__
#define __LIBCHARYBDIS_TOOLS_H__
/*
* double-linked-list stuff
*/
typedef struct _dlink_node dlink_node;
typedef struct _dlink_list dlink_list;
struct _dlink_node
{
void *data;
dlink_node *prev;
dlink_node *next;
};
struct _dlink_list
{
dlink_node *head;
dlink_node *tail;
unsigned long length;
};
dlink_node *make_dlink_node(void);
void free_dlink_node(dlink_node * lp);
void init_dlink_nodes(void);
#ifndef NDEBUG
void mem_frob(void *data, int len);
#else
#define mem_frob(x, y)
#endif
/* This macros are basically swiped from the linux kernel
* they are simple yet effective
*/
/*
* Walks forward of a list.
* pos is your node
* head is your list head
*/
#define DLINK_FOREACH(pos, head) for (pos = (head); pos != NULL; pos = pos->next)
/*
* Walks forward of a list safely while removing nodes
* pos is your node
* n is another list head for temporary storage
* head is your list head
*/
#define DLINK_FOREACH_SAFE(pos, n, head) for (pos = (head), n = pos ? pos->next : NULL; pos != NULL; pos = n, n = pos ? pos->next : NULL)
#define DLINK_FOREACH_PREV(pos, head) for (pos = (head); pos != NULL; pos = pos->prev)
/* Returns the list length */
#define dlink_list_length(list) (list)->length
#define dlink_move_list(oldlist, newlist, node)
#define dlinkAddAlloc(data, list) dlinkAdd(data, make_dlink_node(), list)
#define dlinkAddTailAlloc(data, list) dlinkAddTail(data, make_dlink_node(), list)
#define dlinkDestroy(node, list) do { dlinkDelete(node, list); free_dlink_node(node); } while(0)
/*
* The functions below are included for the sake of inlining
* hopefully this will speed up things just a bit
*
*/
/*
* dlink_ routines are stolen from squid, except for dlinkAddBefore,
* which is mine.
* -- adrian
*/
/* I hate C sometimes */
#if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ && !defined __NO_INLINE__
#define INLINE_FUNC extern inline
#define NEED_INLINES
#else
#undef INLINE_FUNC
#define INLINE_FUNC
#endif
#ifdef TOOLS_C
#undef INLINE_FUNC
#define INLINE_FUNC
#endif
void dlinkMoveNode(dlink_node * m, dlink_list * oldlist, dlink_list * newlist);
void dlinkAdd(void *data, dlink_node * m, dlink_list * list);
void dlinkAddBefore(dlink_node * b, void *data, dlink_node * m, dlink_list * list);
void dlinkMoveTail(dlink_node *m, dlink_list *list);
void dlinkAddTail(void *data, dlink_node * m, dlink_list * list);
void dlinkDelete(dlink_node * m, dlink_list * list);
dlink_node *dlinkFindDelete(void *data, dlink_list *list);
int dlinkFindDestroy(void *data, dlink_list *list);
dlink_node *dlinkFind(void *data, dlink_list *list);
void dlinkMoveList(dlink_list * from, dlink_list * to);
#if defined(NEED_INLINES) || defined(TOOLS_C)
INLINE_FUNC void
dlinkMoveNode(dlink_node * m, dlink_list * oldlist, dlink_list * newlist)
{
/* Assumption: If m->next == NULL, then list->tail == m
* and: If m->prev == NULL, then list->head == m
*/
assert(m != NULL);
assert(oldlist != NULL);
assert(newlist != NULL);
if(m->next)
m->next->prev = m->prev;
else
oldlist->tail = m->prev;
if(m->prev)
m->prev->next = m->next;
else
oldlist->head = m->next;
m->prev = NULL;
m->next = newlist->head;
if(newlist->head != NULL)
newlist->head->prev = m;
else if(newlist->tail == NULL)
newlist->tail = m;
newlist->head = m;
oldlist->length--;
newlist->length++;
}
INLINE_FUNC void
dlinkAdd(void *data, dlink_node * m, dlink_list * list)
{
assert(data != NULL);
assert(m != NULL);
assert(list != NULL);
m->data = data;
m->prev = NULL;
m->next = list->head;
/* Assumption: If list->tail != NULL, list->head != NULL */
if(list->head != NULL)
list->head->prev = m;
else if(list->tail == NULL)
list->tail = m;
list->head = m;
list->length++;
}
INLINE_FUNC void
dlinkAddBefore(dlink_node * b, void *data, dlink_node * m, dlink_list * list)
{
assert(b != NULL);
assert(data != NULL);
assert(m != NULL);
assert(list != NULL);
/* Shortcut - if its the first one, call dlinkAdd only */
if(b == list->head)
{
dlinkAdd(data, m, list);
}
else
{
m->data = data;
b->prev->next = m;
m->prev = b->prev;
b->prev = m;
m->next = b;
list->length++;
}
}
INLINE_FUNC void
dlinkMoveTail(dlink_node *m, dlink_list *list)
{
if(list->tail == m)
return;
/* From here assume that m->next != NULL as that can only
* be at the tail and assume that the node is on the list
*/
m->next->prev = m->prev;
if(m->prev != NULL)
m->prev->next = m->next;
else
list->head = m->next;
list->tail->next = m;
m->prev = list->tail;
m->next = NULL;
list->tail = m;
}
INLINE_FUNC void
dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
{
assert(m != NULL);
assert(list != NULL);
assert(data != NULL);
m->data = data;
m->next = NULL;
m->prev = list->tail;
/* Assumption: If list->tail != NULL, list->head != NULL */
if(list->tail != NULL)
list->tail->next = m;
else if(list->head == NULL)
list->head = m;
list->tail = m;
list->length++;
}
/* Execution profiles show that this function is called the most
* often of all non-spontaneous functions. So it had better be
* efficient. */
INLINE_FUNC void
dlinkDelete(dlink_node * m, dlink_list * list)
{
assert(m != NULL);
assert(list != NULL);
/* Assumption: If m->next == NULL, then list->tail == m
* and: If m->prev == NULL, then list->head == m
*/
if(m->next)
m->next->prev = m->prev;
else
list->tail = m->prev;
if(m->prev)
m->prev->next = m->next;
else
list->head = m->next;
m->next = m->prev = NULL;
list->length--;
}
INLINE_FUNC dlink_node *
dlinkFindDelete(void *data, dlink_list *list)
{
dlink_node *m;
assert(list != NULL);
assert(data != NULL);
DLINK_FOREACH(m, list->head)
{
if(m->data != data)
continue;
if(m->next)
m->next->prev = m->prev;
else
list->tail = m->prev;
if(m->prev)
m->prev->next = m->next;
else
list->head = m->next;
m->next = m->prev = NULL;
list->length--;
return m;
}
return NULL;
}
INLINE_FUNC int
dlinkFindDestroy(void *data, dlink_list *list)
{
void *ptr;
assert(list != NULL);
assert(data != NULL);
ptr = dlinkFindDelete(data, list);
if(ptr != NULL)
{
free_dlink_node(ptr);
return 1;
}
return 0;
}
/*
* dlinkFind
* inputs - list to search
* - data
* output - pointer to link or NULL if not found
* side effects - Look for ptr in the linked listed pointed to by link.
*/
INLINE_FUNC dlink_node *
dlinkFind(void *data, dlink_list *list)
{
dlink_node *ptr;
assert(list != NULL);
assert(data != NULL);
DLINK_FOREACH(ptr, list->head)
{
if(ptr->data == data)
return (ptr);
}
return (NULL);
}
INLINE_FUNC void
dlinkMoveList(dlink_list * from, dlink_list * to)
{
assert(from != NULL);
assert(to != NULL);
/* There are three cases */
/* case one, nothing in from list */
if(from->head == NULL)
return;
/* case two, nothing in to list */
if(to->head == NULL)
{
to->head = from->head;
to->tail = from->tail;
from->head = from->tail = NULL;
to->length = from->length;
from->length = 0;
return;
}
/* third case play with the links */
from->tail->next = to->head;
to->head->prev = from->tail;
to->head = from->head;
from->head = from->tail = NULL;
to->length += from->length;
from->length = 0;
}
#endif
#endif /* __TOOLS_H__ */