libratbox is the new libcharybdis... thanks to androsyn and jilles on making something sane where previous attempts failed. ;)
This commit is contained in:
parent
954012d39b
commit
5ae4cce9e1
21 changed files with 0 additions and 6147 deletions
|
@ -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.
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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... >_<!");
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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() */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
Loading…
Reference in a new issue