Move source from lib/ to src/.
The utility functions in the lib/ directory do not really form a library. Also, now that we build two binaries, tincctl does not need everything that was in libvpn.a, so it is wasteful to link to it.
This commit is contained in:
parent
41497246ee
commit
35b1c25093
28 changed files with 12 additions and 25 deletions
|
@ -4,11 +4,15 @@ sbin_PROGRAMS = tincd tincctl
|
|||
|
||||
EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
|
||||
|
||||
tincd_SOURCES = cipher.c conf.c connection.c control.c crypto.c digest.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
tincd_SOURCES = \
|
||||
xmalloc.c utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
|
||||
cipher.c conf.c connection.c control.c crypto.c digest.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c route.c rsa.c subnet.c tincd.c
|
||||
|
||||
tincctl_SOURCES = tincctl.c rsagen.c
|
||||
tincctl_SOURCES = \
|
||||
xmalloc.c utils.c getopt.c getopt1.c \
|
||||
tincctl.c rsagen.c
|
||||
|
||||
if TUNEMU
|
||||
tincd_SOURCES += bsd/tunemu.c
|
||||
|
@ -18,9 +22,11 @@ nodist_tincd_SOURCES = device.c
|
|||
|
||||
DEFAULT_INCLUDES =
|
||||
|
||||
INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib
|
||||
INCLUDES = @INCLUDES@ -I$(top_builddir)
|
||||
|
||||
noinst_HEADERS = cipher.h conf.h connection.h control.h control_common.h crypto.h device.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
noinst_HEADERS = \
|
||||
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
|
||||
cipher.h conf.h connection.h control.h control_common.h crypto.h device.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h rsa.h rsagen.h subnet.h bsd/tunemu.h
|
||||
|
||||
LIBS = @LIBS@ @LIBGCRYPT_LIBS@
|
||||
|
@ -29,12 +35,6 @@ if TUNEMU
|
|||
LIBS += -lpcap
|
||||
endif
|
||||
|
||||
tincd_LDADD = \
|
||||
$(top_builddir)/lib/libvpn.a
|
||||
|
||||
tincctl_LDADD = \
|
||||
$(top_builddir)/lib/libvpn.a
|
||||
|
||||
AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
|
||||
|
||||
dist-hook:
|
||||
|
|
494
src/alloca.c
Normal file
494
src/alloca.c
Normal file
|
@ -0,0 +1,494 @@
|
|||
/* alloca.c -- allocate automatically reclaimed memory
|
||||
(Mostly) portable public-domain implementation -- D A Gwyn
|
||||
|
||||
This implementation of the PWB library alloca function,
|
||||
which is used to allocate space off the run-time stack so
|
||||
that it is automatically reclaimed upon procedure exit,
|
||||
was inspired by discussions with J. Q. Johnson of Cornell.
|
||||
J.Otto Tennant <jot@cray.com> contributed the Cray support.
|
||||
|
||||
There are some preprocessor constants that can
|
||||
be defined when compiling for your specific system, for
|
||||
improved efficiency; however, the defaults should be okay.
|
||||
|
||||
The general concept of this implementation is to keep
|
||||
track of all alloca-allocated blocks, and reclaim any
|
||||
that are found to be deeper in the stack than the current
|
||||
invocation. This heuristic does not reclaim storage as
|
||||
soon as it becomes invalid, but it will do so eventually.
|
||||
|
||||
As a special case, alloca(0) reclaims storage without
|
||||
allocating any. It is a good idea to use alloca(0) in
|
||||
your main control loop, etc. to force garbage collection. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef emacs
|
||||
# include "blockinput.h"
|
||||
#endif
|
||||
|
||||
/* If compiling with GCC 2, this file's not needed. */
|
||||
#if !defined (__GNUC__) || __GNUC__ < 2
|
||||
|
||||
/* If someone has defined alloca as a macro,
|
||||
there must be some other way alloca is supposed to work. */
|
||||
# ifndef alloca
|
||||
|
||||
# ifdef emacs
|
||||
# ifdef static
|
||||
/* actually, only want this if static is defined as ""
|
||||
-- this is for usg, in which emacs must undefine static
|
||||
in order to make unexec workable
|
||||
*/
|
||||
# ifndef STACK_DIRECTION
|
||||
you
|
||||
lose
|
||||
-- must know STACK_DIRECTION at compile-time
|
||||
# endif /* STACK_DIRECTION undefined */
|
||||
# endif /* static */
|
||||
# endif /* emacs */
|
||||
|
||||
/* If your stack is a linked list of frames, you have to
|
||||
provide an "address metric" ADDRESS_FUNCTION macro. */
|
||||
|
||||
# if defined (CRAY) && defined (CRAY_STACKSEG_END)
|
||||
long i00afunc ();
|
||||
# define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
|
||||
# else
|
||||
# define ADDRESS_FUNCTION(arg) &(arg)
|
||||
# endif
|
||||
|
||||
# if __STDC__
|
||||
typedef void *pointer;
|
||||
# else
|
||||
typedef char *pointer;
|
||||
# endif
|
||||
|
||||
# ifndef NULL
|
||||
# define NULL 0
|
||||
# endif
|
||||
|
||||
/* Different portions of Emacs need to call different versions of
|
||||
malloc. The Emacs executable needs alloca to call xmalloc, because
|
||||
ordinary malloc isn't protected from input signals. On the other
|
||||
hand, the utilities in lib-src need alloca to call malloc; some of
|
||||
them are very simple, and don't have an xmalloc routine.
|
||||
|
||||
Non-Emacs programs expect this to call xmalloc.
|
||||
|
||||
Callers below should use malloc. */
|
||||
|
||||
# ifndef emacs
|
||||
# define malloc xmalloc
|
||||
# endif
|
||||
extern pointer malloc ();
|
||||
|
||||
/* Define STACK_DIRECTION if you know the direction of stack
|
||||
growth for your system; otherwise it will be automatically
|
||||
deduced at run-time.
|
||||
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
|
||||
# ifndef STACK_DIRECTION
|
||||
# define STACK_DIRECTION 0 /* Direction unknown. */
|
||||
# endif
|
||||
|
||||
# if STACK_DIRECTION != 0
|
||||
|
||||
# define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
|
||||
|
||||
# else /* STACK_DIRECTION == 0; need run-time code. */
|
||||
|
||||
static int stack_dir; /* 1 or -1 once known. */
|
||||
# define STACK_DIR stack_dir
|
||||
|
||||
static void
|
||||
find_stack_direction ()
|
||||
{
|
||||
static char *addr = NULL; /* Address of first `dummy', once known. */
|
||||
auto char dummy; /* To get stack address. */
|
||||
|
||||
if (addr == NULL)
|
||||
{ /* Initial entry. */
|
||||
addr = ADDRESS_FUNCTION (dummy);
|
||||
|
||||
find_stack_direction (); /* Recurse once. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Second entry. */
|
||||
if (ADDRESS_FUNCTION (dummy) > addr)
|
||||
stack_dir = 1; /* Stack grew upward. */
|
||||
else
|
||||
stack_dir = -1; /* Stack grew downward. */
|
||||
}
|
||||
}
|
||||
|
||||
# endif /* STACK_DIRECTION == 0 */
|
||||
|
||||
/* An "alloca header" is used to:
|
||||
(a) chain together all alloca'ed blocks;
|
||||
(b) keep track of stack depth.
|
||||
|
||||
It is very important that sizeof(header) agree with malloc
|
||||
alignment chunk size. The following default should work okay. */
|
||||
|
||||
# ifndef ALIGN_SIZE
|
||||
# define ALIGN_SIZE sizeof(double)
|
||||
# endif
|
||||
|
||||
typedef union hdr
|
||||
{
|
||||
char align[ALIGN_SIZE]; /* To force sizeof(header). */
|
||||
struct
|
||||
{
|
||||
union hdr *next; /* For chaining headers. */
|
||||
char *deep; /* For stack depth measure. */
|
||||
} h;
|
||||
} header;
|
||||
|
||||
static header *last_alloca_header = NULL; /* -> last alloca header. */
|
||||
|
||||
/* Return a pointer to at least SIZE bytes of storage,
|
||||
which will be automatically reclaimed upon exit from
|
||||
the procedure that called alloca. Originally, this space
|
||||
was supposed to be taken from the current stack frame of the
|
||||
caller, but that method cannot be made to work for some
|
||||
implementations of C, for example under Gould's UTX/32. */
|
||||
|
||||
pointer
|
||||
alloca (size)
|
||||
unsigned size;
|
||||
{
|
||||
auto char probe; /* Probes stack depth: */
|
||||
register char *depth = ADDRESS_FUNCTION (probe);
|
||||
|
||||
# if STACK_DIRECTION == 0
|
||||
if (STACK_DIR == 0) /* Unknown growth direction. */
|
||||
find_stack_direction ();
|
||||
# endif
|
||||
|
||||
/* Reclaim garbage, defined as all alloca'd storage that
|
||||
was allocated from deeper in the stack than currently. */
|
||||
|
||||
{
|
||||
register header *hp; /* Traverses linked list. */
|
||||
|
||||
# ifdef emacs
|
||||
BLOCK_INPUT;
|
||||
# endif
|
||||
|
||||
for (hp = last_alloca_header; hp != NULL;)
|
||||
if ((STACK_DIR > 0 && hp->h.deep > depth)
|
||||
|| (STACK_DIR < 0 && hp->h.deep < depth))
|
||||
{
|
||||
register header *np = hp->h.next;
|
||||
|
||||
free ((pointer) hp); /* Collect garbage. */
|
||||
|
||||
hp = np; /* -> next header. */
|
||||
}
|
||||
else
|
||||
break; /* Rest are not deeper. */
|
||||
|
||||
last_alloca_header = hp; /* -> last valid storage. */
|
||||
|
||||
# ifdef emacs
|
||||
UNBLOCK_INPUT;
|
||||
# endif
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return NULL; /* No allocation required. */
|
||||
|
||||
/* Allocate combined header + user data storage. */
|
||||
|
||||
{
|
||||
register pointer new = malloc (sizeof (header) + size);
|
||||
/* Address of header. */
|
||||
|
||||
((header *) new)->h.next = last_alloca_header;
|
||||
((header *) new)->h.deep = depth;
|
||||
|
||||
last_alloca_header = (header *) new;
|
||||
|
||||
/* User storage begins just after header. */
|
||||
|
||||
return (pointer) ((char *) new + sizeof (header));
|
||||
}
|
||||
}
|
||||
|
||||
# if defined (CRAY) && defined (CRAY_STACKSEG_END)
|
||||
|
||||
# ifdef DEBUG_I00AFUNC
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
|
||||
# ifndef CRAY_STACK
|
||||
# define CRAY_STACK
|
||||
# ifndef CRAY2
|
||||
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
|
||||
struct stack_control_header
|
||||
{
|
||||
long shgrow:32; /* Number of times stack has grown. */
|
||||
long shaseg:32; /* Size of increments to stack. */
|
||||
long shhwm:32; /* High water mark of stack. */
|
||||
long shsize:32; /* Current size of stack (all segments). */
|
||||
};
|
||||
|
||||
/* The stack segment linkage control information occurs at
|
||||
the high-address end of a stack segment. (The stack
|
||||
grows from low addresses to high addresses.) The initial
|
||||
part of the stack segment linkage control information is
|
||||
0200 (octal) words. This provides for register storage
|
||||
for the routine which overflows the stack. */
|
||||
|
||||
struct stack_segment_linkage
|
||||
{
|
||||
long ss[0200]; /* 0200 overflow words. */
|
||||
long sssize:32; /* Number of words in this segment. */
|
||||
long ssbase:32; /* Offset to stack base. */
|
||||
long:32;
|
||||
long sspseg:32; /* Offset to linkage control of previous
|
||||
segment of stack. */
|
||||
long:32;
|
||||
long sstcpt:32; /* Pointer to task common address block. */
|
||||
long sscsnm; /* Private control structure number for
|
||||
microtasking. */
|
||||
long ssusr1; /* Reserved for user. */
|
||||
long ssusr2; /* Reserved for user. */
|
||||
long sstpid; /* Process ID for pid based multi-tasking. */
|
||||
long ssgvup; /* Pointer to multitasking thread giveup. */
|
||||
long sscray[7]; /* Reserved for Cray Research. */
|
||||
long ssa0;
|
||||
long ssa1;
|
||||
long ssa2;
|
||||
long ssa3;
|
||||
long ssa4;
|
||||
long ssa5;
|
||||
long ssa6;
|
||||
long ssa7;
|
||||
long sss0;
|
||||
long sss1;
|
||||
long sss2;
|
||||
long sss3;
|
||||
long sss4;
|
||||
long sss5;
|
||||
long sss6;
|
||||
long sss7;
|
||||
};
|
||||
|
||||
# else /* CRAY2 */
|
||||
/* The following structure defines the vector of words
|
||||
returned by the STKSTAT library routine. */
|
||||
struct stk_stat
|
||||
{
|
||||
long now; /* Current total stack size. */
|
||||
long maxc; /* Amount of contiguous space which would
|
||||
be required to satisfy the maximum
|
||||
stack demand to date. */
|
||||
long high_water; /* Stack high-water mark. */
|
||||
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
|
||||
long hits; /* Number of internal buffer hits. */
|
||||
long extends; /* Number of block extensions. */
|
||||
long stko_mallocs; /* Block allocations by $STKOFEN. */
|
||||
long underflows; /* Number of stack underflow calls ($STKRETN). */
|
||||
long stko_free; /* Number of deallocations by $STKRETN. */
|
||||
long stkm_free; /* Number of deallocations by $STKMRET. */
|
||||
long segments; /* Current number of stack segments. */
|
||||
long maxs; /* Maximum number of stack segments so far. */
|
||||
long pad_size; /* Stack pad size. */
|
||||
long current_address; /* Current stack segment address. */
|
||||
long current_size; /* Current stack segment size. This
|
||||
number is actually corrupted by STKSTAT to
|
||||
include the fifteen word trailer area. */
|
||||
long initial_address; /* Address of initial segment. */
|
||||
long initial_size; /* Size of initial segment. */
|
||||
};
|
||||
|
||||
/* The following structure describes the data structure which trails
|
||||
any stack segment. I think that the description in 'asdef' is
|
||||
out of date. I only describe the parts that I am sure about. */
|
||||
|
||||
struct stk_trailer
|
||||
{
|
||||
long this_address; /* Address of this block. */
|
||||
long this_size; /* Size of this block (does not include
|
||||
this trailer). */
|
||||
long unknown2;
|
||||
long unknown3;
|
||||
long link; /* Address of trailer block of previous
|
||||
segment. */
|
||||
long unknown5;
|
||||
long unknown6;
|
||||
long unknown7;
|
||||
long unknown8;
|
||||
long unknown9;
|
||||
long unknown10;
|
||||
long unknown11;
|
||||
long unknown12;
|
||||
long unknown13;
|
||||
long unknown14;
|
||||
};
|
||||
|
||||
# endif /* CRAY2 */
|
||||
# endif /* not CRAY_STACK */
|
||||
|
||||
# ifdef CRAY2
|
||||
/* Determine a "stack measure" for an arbitrary ADDRESS.
|
||||
I doubt that "lint" will like this much. */
|
||||
|
||||
static long
|
||||
i00afunc (long *address)
|
||||
{
|
||||
struct stk_stat status;
|
||||
struct stk_trailer *trailer;
|
||||
long *block, size;
|
||||
long result = 0;
|
||||
|
||||
/* We want to iterate through all of the segments. The first
|
||||
step is to get the stack status structure. We could do this
|
||||
more quickly and more directly, perhaps, by referencing the
|
||||
$LM00 common block, but I know that this works. */
|
||||
|
||||
STKSTAT (&status);
|
||||
|
||||
/* Set up the iteration. */
|
||||
|
||||
trailer = (struct stk_trailer *) (status.current_address
|
||||
+ status.current_size
|
||||
- 15);
|
||||
|
||||
/* There must be at least one stack segment. Therefore it is
|
||||
a fatal error if "trailer" is null. */
|
||||
|
||||
if (trailer == 0)
|
||||
abort ();
|
||||
|
||||
/* Discard segments that do not contain our argument address. */
|
||||
|
||||
while (trailer != 0)
|
||||
{
|
||||
block = (long *) trailer->this_address;
|
||||
size = trailer->this_size;
|
||||
if (block == 0 || size == 0)
|
||||
abort ();
|
||||
trailer = (struct stk_trailer *) trailer->link;
|
||||
if ((block <= address) && (address < (block + size)))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the result to the offset in this segment and add the sizes
|
||||
of all predecessor segments. */
|
||||
|
||||
result = address - block;
|
||||
|
||||
if (trailer == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (trailer->this_size <= 0)
|
||||
abort ();
|
||||
result += trailer->this_size;
|
||||
trailer = (struct stk_trailer *) trailer->link;
|
||||
}
|
||||
while (trailer != 0);
|
||||
|
||||
/* We are done. Note that if you present a bogus address (one
|
||||
not in any segment), you will get a different number back, formed
|
||||
from subtracting the address of the first block. This is probably
|
||||
not what you want. */
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
# else /* not CRAY2 */
|
||||
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
|
||||
Determine the number of the cell within the stack,
|
||||
given the address of the cell. The purpose of this
|
||||
routine is to linearize, in some sense, stack addresses
|
||||
for alloca. */
|
||||
|
||||
static long
|
||||
i00afunc (long address)
|
||||
{
|
||||
long stkl = 0;
|
||||
|
||||
long size, pseg, this_segment, stack;
|
||||
long result = 0;
|
||||
|
||||
struct stack_segment_linkage *ssptr;
|
||||
|
||||
/* Register B67 contains the address of the end of the
|
||||
current stack segment. If you (as a subprogram) store
|
||||
your registers on the stack and find that you are past
|
||||
the contents of B67, you have overflowed the segment.
|
||||
|
||||
B67 also points to the stack segment linkage control
|
||||
area, which is what we are really interested in. */
|
||||
|
||||
stkl = CRAY_STACKSEG_END ();
|
||||
ssptr = (struct stack_segment_linkage *) stkl;
|
||||
|
||||
/* If one subtracts 'size' from the end of the segment,
|
||||
one has the address of the first word of the segment.
|
||||
|
||||
If this is not the first segment, 'pseg' will be
|
||||
nonzero. */
|
||||
|
||||
pseg = ssptr->sspseg;
|
||||
size = ssptr->sssize;
|
||||
|
||||
this_segment = stkl - size;
|
||||
|
||||
/* It is possible that calling this routine itself caused
|
||||
a stack overflow. Discard stack segments which do not
|
||||
contain the target address. */
|
||||
|
||||
while (!(this_segment <= address && address <= stkl))
|
||||
{
|
||||
# ifdef DEBUG_I00AFUNC
|
||||
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
|
||||
# endif
|
||||
if (pseg == 0)
|
||||
break;
|
||||
stkl = stkl - pseg;
|
||||
ssptr = (struct stack_segment_linkage *) stkl;
|
||||
size = ssptr->sssize;
|
||||
pseg = ssptr->sspseg;
|
||||
this_segment = stkl - size;
|
||||
}
|
||||
|
||||
result = address - this_segment;
|
||||
|
||||
/* If you subtract pseg from the current end of the stack,
|
||||
you get the address of the previous stack segment's end.
|
||||
This seems a little convoluted to me, but I'll bet you save
|
||||
a cycle somewhere. */
|
||||
|
||||
while (pseg != 0)
|
||||
{
|
||||
# ifdef DEBUG_I00AFUNC
|
||||
fprintf (stderr, "%011o %011o\n", pseg, size);
|
||||
# endif
|
||||
stkl = stkl - pseg;
|
||||
ssptr = (struct stack_segment_linkage *) stkl;
|
||||
size = ssptr->sssize;
|
||||
pseg = ssptr->sspseg;
|
||||
result += size;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
# endif /* not CRAY2 */
|
||||
# endif /* CRAY */
|
||||
|
||||
# endif /* no alloca */
|
||||
#endif /* not GCC version 2 */
|
165
src/dropin.c
Normal file
165
src/dropin.c
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
dropin.c -- a set of drop-in replacements for libc functions
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
/*
|
||||
Replacement for the daemon() function.
|
||||
|
||||
The daemon() function is for programs wishing to detach themselves
|
||||
from the controlling terminal and run in the background as system
|
||||
daemons.
|
||||
|
||||
Unless the argument nochdir is non-zero, daemon() changes the
|
||||
current working directory to the root (``/'').
|
||||
|
||||
Unless the argument noclose is non-zero, daemon() will redirect
|
||||
standard input, standard output and standard error to /dev/null.
|
||||
*/
|
||||
int daemon(int nochdir, int noclose) {
|
||||
#ifdef HAVE_FORK
|
||||
pid_t pid;
|
||||
int fd;
|
||||
|
||||
pid = fork();
|
||||
|
||||
/* Check if forking failed */
|
||||
if(pid < 0) {
|
||||
perror("fork");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* If we are the parent, terminate */
|
||||
if(pid)
|
||||
exit(0);
|
||||
|
||||
/* Detach by becoming the new process group leader */
|
||||
if(setsid() < 0) {
|
||||
perror("setsid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Change working directory to the root (to avoid keeping mount
|
||||
points busy) */
|
||||
if(!nochdir) {
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
/* Redirect stdin/out/err to /dev/null */
|
||||
if(!noclose) {
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
|
||||
if(fd < 0) {
|
||||
perror("opening /dev/null");
|
||||
return -1;
|
||||
} else {
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
/*
|
||||
Replacement for the GNU get_current_dir_name function:
|
||||
|
||||
get_current_dir_name will malloc(3) an array big enough to hold the
|
||||
current directory name. If the environment variable PWD is set, and
|
||||
its value is correct, then that value will be returned.
|
||||
*/
|
||||
char *get_current_dir_name(void) {
|
||||
size_t size;
|
||||
char *buf;
|
||||
char *r;
|
||||
|
||||
/* Start with 100 bytes. If this turns out to be insufficient to
|
||||
contain the working directory, double the size. */
|
||||
size = 100;
|
||||
buf = xmalloc(size);
|
||||
|
||||
errno = 0; /* Success */
|
||||
r = getcwd(buf, size);
|
||||
|
||||
/* getcwd returns NULL and sets errno to ERANGE if the bufferspace
|
||||
is insufficient to contain the entire working directory. */
|
||||
while(r == NULL && errno == ERANGE) {
|
||||
free(buf);
|
||||
size <<= 1; /* double the size */
|
||||
buf = xmalloc(size);
|
||||
r = getcwd(buf, size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **buf, const char *fmt, ...) {
|
||||
int result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = vasprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
int vasprintf(char **buf, const char *fmt, va_list ap) {
|
||||
int status;
|
||||
va_list aq;
|
||||
int len;
|
||||
|
||||
len = 4096;
|
||||
*buf = xmalloc(len);
|
||||
|
||||
va_copy(aq, ap);
|
||||
status = vsnprintf(*buf, len, fmt, aq);
|
||||
va_end(aq);
|
||||
|
||||
if(status >= 0)
|
||||
*buf = xrealloc(*buf, status + 1);
|
||||
|
||||
if(status > len - 1) {
|
||||
len = status;
|
||||
va_copy(aq, ap);
|
||||
status = vsnprintf(*buf, len, fmt, aq);
|
||||
va_end(aq);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
int gettimeofday(struct timeval *tv, void *tz) {
|
||||
tv->tv_sec = time(NULL);
|
||||
tv->tv_usec = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
44
src/dropin.h
Normal file
44
src/dropin.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
dropin.h -- header file for dropin.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __DROPIN_H__
|
||||
#define __DROPIN_H__
|
||||
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "fake-getnameinfo.h"
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
extern int daemon(int, int);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
extern char *get_current_dir_name(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
extern int asprintf(char **, const char *, ...);
|
||||
extern int vasprintf(char **, const char *, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
extern int gettimeofday(struct timeval *, void *);
|
||||
#endif
|
||||
|
||||
#endif /* __DROPIN_H__ */
|
85
src/ethernet.h
Normal file
85
src/ethernet.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
ethernet.h -- missing Ethernet related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_ETHERNET_H__
|
||||
#define __TINC_ETHERNET_H__
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
|
||||
#ifndef ARPHRD_ETHER
|
||||
#define ARPHRD_ETHER 1
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_IP
|
||||
#define ETH_P_IP 0x0800
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_ARP
|
||||
#define ETH_P_ARP 0x0806
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_IPV6
|
||||
#define ETH_P_IPV6 0x86DD
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ETHER_HEADER
|
||||
struct ether_header {
|
||||
uint8_t ether_dhost[ETH_ALEN];
|
||||
uint8_t ether_shost[ETH_ALEN];
|
||||
uint16_t ether_type;
|
||||
} __attribute__ ((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ARPHDR
|
||||
struct arphdr {
|
||||
uint16_t ar_hrd;
|
||||
uint16_t ar_pro;
|
||||
uint8_t ar_hln;
|
||||
uint8_t ar_pln;
|
||||
uint16_t ar_op;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define ARPOP_REQUEST 1
|
||||
#define ARPOP_REPLY 2
|
||||
#define ARPOP_RREQUEST 3
|
||||
#define ARPOP_RREPLY 4
|
||||
#define ARPOP_InREQUEST 8
|
||||
#define ARPOP_InREPLY 9
|
||||
#define ARPOP_NAK 10
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ETHER_ARP
|
||||
struct ether_arp {
|
||||
struct arphdr ea_hdr;
|
||||
uint8_t arp_sha[ETH_ALEN];
|
||||
uint8_t arp_spa[4];
|
||||
uint8_t arp_tha[ETH_ALEN];
|
||||
uint8_t arp_tpa[4];
|
||||
} __attribute__ ((__packed__));
|
||||
#define arp_hrd ea_hdr.ar_hrd
|
||||
#define arp_pro ea_hdr.ar_pro
|
||||
#define arp_hln ea_hdr.ar_hln
|
||||
#define arp_pln ea_hdr.ar_pln
|
||||
#define arp_op ea_hdr.ar_op
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_ETHERNET_H__ */
|
19
src/fake-gai-errnos.h
Normal file
19
src/fake-gai-errnos.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file is included in getaddrinfo.c and getnameinfo.c.
|
||||
* See getaddrinfo.c and getnameinfo.c.
|
||||
*/
|
||||
|
||||
/* for old netdb.h */
|
||||
#ifndef EAI_NODATA
|
||||
#define EAI_NODATA 1
|
||||
#endif
|
||||
|
||||
#ifndef EAI_MEMORY
|
||||
#define EAI_MEMORY 2
|
||||
#endif
|
||||
|
||||
#ifndef EAI_FAMILY
|
||||
#define EAI_FAMILY 3
|
||||
#endif
|
102
src/fake-getaddrinfo.c
Normal file
102
src/fake-getaddrinfo.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
|
||||
* These funtions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For exapmle, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode) {
|
||||
switch (ecode) {
|
||||
case EAI_NODATA:
|
||||
return "No address associated with hostname";
|
||||
case EAI_MEMORY:
|
||||
return "Memory allocation failure";
|
||||
case EAI_FAMILY:
|
||||
return "Address family not supported";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai) {
|
||||
struct addrinfo *next;
|
||||
|
||||
while(ai) {
|
||||
next = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
|
||||
struct addrinfo *ai;
|
||||
|
||||
ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
|
||||
ai->ai_addr = (struct sockaddr *)(ai + 1);
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
|
||||
struct addrinfo *prev = NULL;
|
||||
struct hostent *hp;
|
||||
struct in_addr in = {0};
|
||||
int i;
|
||||
uint16_t port = 0;
|
||||
|
||||
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)
|
||||
return EAI_FAMILY;
|
||||
|
||||
if (servname)
|
||||
port = htons(atoi(servname));
|
||||
|
||||
if (hints && hints->ai_flags & AI_PASSIVE) {
|
||||
*res = malloc_ai(port, htonl(0x00000000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hostname) {
|
||||
*res = malloc_ai(port, htonl(0x7f000001));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
|
||||
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0])
|
||||
return EAI_NODATA;
|
||||
|
||||
for (i = 0; hp->h_addr_list[i]; i++) {
|
||||
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
|
||||
|
||||
if(prev)
|
||||
prev->ai_next = *res;
|
||||
|
||||
prev = *res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETADDRINFO */
|
47
src/fake-getaddrinfo.h
Normal file
47
src/fake-getaddrinfo.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef _FAKE_GETADDRINFO_H
|
||||
#define _FAKE_GETADDRINFO_H
|
||||
|
||||
#include "fake-gai-errnos.h"
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
# define AI_PASSIVE 1
|
||||
# define AI_CANONNAME 2
|
||||
#endif
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
# define NI_NUMERICHOST 2
|
||||
# define NI_NAMEREQD 4
|
||||
# define NI_NUMERICSERV 8
|
||||
#endif
|
||||
|
||||
#ifndef AI_NUMERICHOST
|
||||
#define AI_NUMERICHOST 4
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
int getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai);
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#endif /* _FAKE_GETADDRINFO_H */
|
54
src/fake-getnameinfo.c
Normal file
54
src/fake-getnameinfo.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getnameinfo().
|
||||
* These funtions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For exapmle, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "fake-getnameinfo.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
struct hostent *hp;
|
||||
int len;
|
||||
|
||||
if(sa->sa_family != AF_INET)
|
||||
return EAI_FAMILY;
|
||||
|
||||
if(serv && servlen) {
|
||||
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
|
||||
if(len < 0 || len >= servlen)
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
if(!host || !hostlen)
|
||||
return 0;
|
||||
|
||||
if(flags & NI_NUMERICHOST) {
|
||||
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
|
||||
if(len < 0 || len >= hostlen)
|
||||
return EAI_MEMORY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
|
||||
|
||||
if(!hp || !hp->h_name || !hp->h_name[0])
|
||||
return EAI_NODATA;
|
||||
|
||||
len = snprintf(host, hostlen, "%s", hp->h_name);
|
||||
if(len < 0 || len >= hostlen)
|
||||
return EAI_MEMORY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
16
src/fake-getnameinfo.h
Normal file
16
src/fake-getnameinfo.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef _FAKE_GETNAMEINFO_H
|
||||
#define _FAKE_GETNAMEINFO_H
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXSERV */
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#endif /* _FAKE_GETNAMEINFO_H */
|
1042
src/getopt.c
Normal file
1042
src/getopt.c
Normal file
File diff suppressed because it is too large
Load diff
133
src/getopt.h
Normal file
133
src/getopt.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
/* Declarations for getopt.
|
||||
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
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, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
#if defined (__STDC__) && __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#if defined (__STDC__) && __STDC__
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
#endif /* __GNU_LIBRARY__ */
|
||||
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H */
|
189
src/getopt1.c
Normal file
189
src/getopt1.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/* getopt_long and getopt_long_only entry points for GNU getopt.
|
||||
Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
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, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#if !defined (__STDC__) || !__STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
#define GETOPT_INTERFACE_VERSION 2
|
||||
#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
|
||||
#include <gnu-versions.h>
|
||||
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
|
||||
#define ELIDE_CODE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ELIDE_CODE
|
||||
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
getopt_long (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
|
||||
}
|
||||
|
||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
|
||||
If an option that starts with '-' (not '--') doesn't match a long option,
|
||||
but does match a short option, it is parsed as a short option
|
||||
instead. */
|
||||
|
||||
int
|
||||
getopt_long_only (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* Not ELIDE_CODE. */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf ("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
137
src/ipv4.h
Normal file
137
src/ipv4.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
ipv4.h -- missing IPv4 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_IPV4_H__
|
||||
#define __TINC_IPV4_H__
|
||||
|
||||
#ifndef AF_INET
|
||||
#define AF_INET 2
|
||||
#endif
|
||||
|
||||
#ifndef IPPROTO_ICMP
|
||||
#define IPPROTO_ICMP 1
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_DEST_UNREACH
|
||||
#define ICMP_DEST_UNREACH 3
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_FRAG_NEEDED
|
||||
#define ICMP_FRAG_NEEDED 4
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_NET_UNKNOWN
|
||||
#define ICMP_NET_UNKNOWN 6
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_NET_UNREACH
|
||||
#define ICMP_NET_UNREACH 0
|
||||
#endif
|
||||
|
||||
#ifndef IP_MSS
|
||||
#define IP_MSS 576
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IP
|
||||
struct ip {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned int ip_hl:4;
|
||||
unsigned int ip_v:4;
|
||||
#else
|
||||
unsigned int ip_v:4;
|
||||
unsigned int ip_hl:4;
|
||||
#endif
|
||||
uint8_t ip_tos;
|
||||
uint16_t ip_len;
|
||||
uint16_t ip_id;
|
||||
uint16_t ip_off;
|
||||
#define IP_RF 0x8000
|
||||
#define IP_DF 0x4000
|
||||
#define IP_MF 0x2000
|
||||
uint8_t ip_ttl;
|
||||
uint8_t ip_p;
|
||||
uint16_t ip_sum;
|
||||
struct in_addr ip_src, ip_dst;
|
||||
} __attribute__ ((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IP_OFFMASK
|
||||
#define IP_OFFMASK 0x1fff
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ICMP
|
||||
struct icmp {
|
||||
uint8_t icmp_type;
|
||||
uint8_t icmp_code;
|
||||
uint16_t icmp_cksum;
|
||||
union {
|
||||
uint8_t ih_pptr;
|
||||
struct in_addr ih_gwaddr;
|
||||
struct ih_idseq {
|
||||
uint16_t icd_id;
|
||||
uint16_t icd_seq;
|
||||
} ih_idseq;
|
||||
uint32_t ih_void;
|
||||
|
||||
|
||||
struct ih_pmtu {
|
||||
uint16_t ipm_void;
|
||||
uint16_t ipm_nextmtu;
|
||||
} ih_pmtu;
|
||||
|
||||
struct ih_rtradv {
|
||||
uint8_t irt_num_addrs;
|
||||
uint8_t irt_wpa;
|
||||
uint16_t irt_lifetime;
|
||||
} ih_rtradv;
|
||||
} icmp_hun;
|
||||
#define icmp_pptr icmp_hun.ih_pptr
|
||||
#define icmp_gwaddr icmp_hun.ih_gwaddr
|
||||
#define icmp_id icmp_hun.ih_idseq.icd_id
|
||||
#define icmp_seq icmp_hun.ih_idseq.icd_seq
|
||||
#define icmp_void icmp_hun.ih_void
|
||||
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
|
||||
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
|
||||
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
|
||||
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
|
||||
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
|
||||
union {
|
||||
struct {
|
||||
uint32_t its_otime;
|
||||
uint32_t its_rtime;
|
||||
uint32_t its_ttime;
|
||||
} id_ts;
|
||||
struct {
|
||||
struct ip idi_ip;
|
||||
} id_ip;
|
||||
uint32_t id_mask;
|
||||
uint8_t id_data[1];
|
||||
} icmp_dun;
|
||||
#define icmp_otime icmp_dun.id_ts.its_otime
|
||||
#define icmp_rtime icmp_dun.id_ts.its_rtime
|
||||
#define icmp_ttime icmp_dun.id_ts.its_ttime
|
||||
#define icmp_ip icmp_dun.id_ip.idi_ip
|
||||
#define icmp_radv icmp_dun.id_radv
|
||||
#define icmp_mask icmp_dun.id_mask
|
||||
#define icmp_data icmp_dun.id_data
|
||||
} __attribute__ ((__packed__));
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_IPV4_H__ */
|
127
src/ipv6.h
Normal file
127
src/ipv6.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
ipv6.h -- missing IPv6 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_IPV6_H__
|
||||
#define __TINC_IPV6_H__
|
||||
|
||||
#ifndef AF_INET6
|
||||
#define AF_INET6 10
|
||||
#endif
|
||||
|
||||
#ifndef IPPROTO_ICMPV6
|
||||
#define IPPROTO_ICMPV6 58
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IN6_ADDR
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t u6_addr8[16];
|
||||
uint16_t u6_addr16[8];
|
||||
uint32_t u6_addr32[4];
|
||||
} in6_u;
|
||||
} __attribute__ ((__packed__));
|
||||
#define s6_addr in6_u.u6_addr8
|
||||
#define s6_addr16 in6_u.u6_addr16
|
||||
#define s6_addr32 in6_u.u6_addr32
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_IN6
|
||||
struct sockaddr_in6 {
|
||||
uint16_t sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
} __attribute__ ((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IN6_IS_ADDR_V4MAPPED
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((((__const uint32_t *) (a))[0] == 0) \
|
||||
&& (((__const uint32_t *) (a))[1] == 0) \
|
||||
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IP6_HDR
|
||||
struct ip6_hdr {
|
||||
union {
|
||||
struct ip6_hdrctl {
|
||||
uint32_t ip6_un1_flow;
|
||||
uint16_t ip6_un1_plen;
|
||||
uint8_t ip6_un1_nxt;
|
||||
uint8_t ip6_un1_hlim;
|
||||
} ip6_un1;
|
||||
uint8_t ip6_un2_vfc;
|
||||
} ip6_ctlun;
|
||||
struct in6_addr ip6_src;
|
||||
struct in6_addr ip6_dst;
|
||||
} __attribute__ ((__packed__));
|
||||
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
|
||||
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
|
||||
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
|
||||
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
|
||||
#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
|
||||
#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ICMP6_HDR
|
||||
struct icmp6_hdr {
|
||||
uint8_t icmp6_type;
|
||||
uint8_t icmp6_code;
|
||||
uint16_t icmp6_cksum;
|
||||
union {
|
||||
uint32_t icmp6_un_data32[1];
|
||||
uint16_t icmp6_un_data16[2];
|
||||
uint8_t icmp6_un_data8[4];
|
||||
} icmp6_dataun;
|
||||
} __attribute__ ((__packed__));
|
||||
#define ICMP6_DST_UNREACH_NOROUTE 0
|
||||
#define ICMP6_DST_UNREACH 1
|
||||
#define ICMP6_PACKET_TOO_BIG 2
|
||||
#define ICMP6_DST_UNREACH_ADDR 3
|
||||
#define ND_NEIGHBOR_SOLICIT 135
|
||||
#define ND_NEIGHBOR_ADVERT 136
|
||||
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
|
||||
#define icmp6_data16 icmp6_dataun.icmp6_un_data16
|
||||
#define icmp6_data8 icmp6_dataun.icmp6_un_data8
|
||||
#define icmp6_mtu icmp6_data32[0]
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT
|
||||
struct nd_neighbor_solicit {
|
||||
struct icmp6_hdr nd_ns_hdr;
|
||||
struct in6_addr nd_ns_target;
|
||||
} __attribute__ ((__packed__));
|
||||
#define ND_OPT_SOURCE_LINKADDR 1
|
||||
#define ND_OPT_TARGET_LINKADDR 2
|
||||
#define nd_ns_type nd_ns_hdr.icmp6_type
|
||||
#define nd_ns_code nd_ns_hdr.icmp6_code
|
||||
#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
|
||||
#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ND_OPT_HDR
|
||||
struct nd_opt_hdr {
|
||||
uint8_t nd_opt_type;
|
||||
uint8_t nd_opt_len;
|
||||
} __attribute__ ((__packed__));
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_IPV6_H__ */
|
169
src/list.c
Normal file
169
src/list.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
list.c -- functions to deal with double linked lists
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
list_t *list_alloc(list_action_t delete) {
|
||||
list_t *list;
|
||||
|
||||
list = xmalloc_and_zero(sizeof(list_t));
|
||||
list->delete = delete;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void list_free(list_t *list) {
|
||||
free(list);
|
||||
}
|
||||
|
||||
list_node_t *list_alloc_node(void) {
|
||||
return xmalloc_and_zero(sizeof(list_node_t));
|
||||
}
|
||||
|
||||
void list_free_node(list_t *list, list_node_t *node) {
|
||||
if(node->data && list->delete)
|
||||
list->delete(node->data);
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
list_node_t *list_insert_head(list_t *list, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->prev = NULL;
|
||||
node->next = list->head;
|
||||
list->head = node;
|
||||
|
||||
if(node->next)
|
||||
node->next->prev = node;
|
||||
else
|
||||
list->tail = node;
|
||||
|
||||
list->count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
list_node_t *list_insert_tail(list_t *list, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
node->prev = list->tail;
|
||||
list->tail = node;
|
||||
|
||||
if(node->prev)
|
||||
node->prev->next = node;
|
||||
else
|
||||
list->head = node;
|
||||
|
||||
list->count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void list_unlink_node(list_t *list, list_node_t *node) {
|
||||
if(node->prev)
|
||||
node->prev->next = node->next;
|
||||
else
|
||||
list->head = node->next;
|
||||
|
||||
if(node->next)
|
||||
node->next->prev = node->prev;
|
||||
else
|
||||
list->tail = node->prev;
|
||||
|
||||
list->count--;
|
||||
}
|
||||
|
||||
void list_delete_node(list_t *list, list_node_t *node) {
|
||||
list_unlink_node(list, node);
|
||||
list_free_node(list, node);
|
||||
}
|
||||
|
||||
void list_delete_head(list_t *list) {
|
||||
list_delete_node(list, list->head);
|
||||
}
|
||||
|
||||
void list_delete_tail(list_t *list) {
|
||||
list_delete_node(list, list->tail);
|
||||
}
|
||||
|
||||
/* Head/tail lookup */
|
||||
|
||||
void *list_get_head(list_t *list) {
|
||||
if(list->head)
|
||||
return list->head->data;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *list_get_tail(list_t *list) {
|
||||
if(list->tail)
|
||||
return list->tail->data;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fast list deletion */
|
||||
|
||||
void list_delete_list(list_t *list) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
list_free_node(list, node);
|
||||
}
|
||||
|
||||
list_free(list);
|
||||
}
|
||||
|
||||
/* Traversing */
|
||||
|
||||
void list_foreach_node(list_t *list, list_action_node_t action) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node);
|
||||
}
|
||||
}
|
||||
|
||||
void list_foreach(list_t *list, list_action_t action) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
if(node->data)
|
||||
action(node->data);
|
||||
}
|
||||
}
|
78
src/list.h
Normal file
78
src/list.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
list.h -- header file for list.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_LIST_H__
|
||||
#define __TINC_LIST_H__
|
||||
|
||||
typedef struct list_node_t {
|
||||
struct list_node_t *prev;
|
||||
struct list_node_t *next;
|
||||
|
||||
/* Payload */
|
||||
|
||||
void *data;
|
||||
} list_node_t;
|
||||
|
||||
typedef void (*list_action_t)(const void *);
|
||||
typedef void (*list_action_node_t)(const list_node_t *);
|
||||
|
||||
typedef struct list_t {
|
||||
list_node_t *head;
|
||||
list_node_t *tail;
|
||||
int count;
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
list_action_t delete;
|
||||
} list_t;
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
extern list_t *list_alloc(list_action_t) __attribute__ ((__malloc__));
|
||||
extern void list_free(list_t *);
|
||||
extern list_node_t *list_alloc_node(void);
|
||||
extern void list_free_node(list_t *, list_node_t *);
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
extern list_node_t *list_insert_head(list_t *, void *);
|
||||
extern list_node_t *list_insert_tail(list_t *, void *);
|
||||
|
||||
extern void list_unlink_node(list_t *, list_node_t *);
|
||||
extern void list_delete_node(list_t *, list_node_t *);
|
||||
|
||||
extern void list_delete_head(list_t *);
|
||||
extern void list_delete_tail(list_t *);
|
||||
|
||||
/* Head/tail lookup */
|
||||
|
||||
extern void *list_get_head(list_t *);
|
||||
extern void *list_get_tail(list_t *);
|
||||
|
||||
/* Fast list deletion */
|
||||
|
||||
extern void list_delete_list(list_t *);
|
||||
|
||||
/* Traversing */
|
||||
|
||||
extern void list_foreach(list_t *, list_action_t);
|
||||
extern void list_foreach_node(list_t *, list_action_node_t);
|
||||
|
||||
#endif /* __TINC_LIST_H__ */
|
39
src/malloc.c
Normal file
39
src/malloc.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* Work around bug on some systems where malloc (0) fails.
|
||||
Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
|
||||
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, 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., Foundation,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#undef malloc
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
char *malloc ();
|
||||
|
||||
/* Allocate an N-byte block of memory from the heap.
|
||||
If N is zero, allocate a 1-byte block. */
|
||||
|
||||
char *
|
||||
rpl_malloc (n)
|
||||
size_t n;
|
||||
{
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
return malloc (n);
|
||||
}
|
391
src/memcmp.c
Normal file
391
src/memcmp.c
Normal file
|
@ -0,0 +1,391 @@
|
|||
/* Copyright (C) 1991, 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
|
||||
Contributed by Torbjorn Granlund (tege@sics.se).
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
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, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#undef __ptr_t
|
||||
#if defined __cplusplus || (defined __STDC__ && __STDC__)
|
||||
# define __ptr_t void *
|
||||
#else /* Not C++ or ANSI C. */
|
||||
# undef const
|
||||
# define const
|
||||
# define __ptr_t char *
|
||||
#endif /* C++ or ANSI C. */
|
||||
|
||||
#ifndef __P
|
||||
# if defined __GNUC__ || (defined __STDC__ && __STDC__)
|
||||
# define __P(args) args
|
||||
# else
|
||||
# define __P(args) ()
|
||||
# endif /* GCC. */
|
||||
#endif /* Not __P. */
|
||||
|
||||
#if defined HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#undef memcmp
|
||||
|
||||
#ifdef _LIBC
|
||||
|
||||
# include <memcopy.h>
|
||||
|
||||
#else /* Not in the GNU C library. */
|
||||
|
||||
# include <sys/types.h>
|
||||
|
||||
/* Type to use for aligned memory operations.
|
||||
This should normally be the biggest type supported by a single load
|
||||
and store. Must be an unsigned type. */
|
||||
# define op_t unsigned long int
|
||||
# define OPSIZ (sizeof(op_t))
|
||||
|
||||
/* Threshold value for when to enter the unrolled loops. */
|
||||
# define OP_T_THRES 16
|
||||
|
||||
/* Type to use for unaligned operations. */
|
||||
typedef unsigned char byte;
|
||||
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
|
||||
# else
|
||||
# define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
|
||||
# endif
|
||||
|
||||
#endif /* In the GNU C library. */
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
|
||||
#else
|
||||
# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
|
||||
#endif
|
||||
|
||||
/* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */
|
||||
|
||||
/* The strategy of this memcmp is:
|
||||
|
||||
1. Compare bytes until one of the block pointers is aligned.
|
||||
|
||||
2. Compare using memcmp_common_alignment or
|
||||
memcmp_not_common_alignment, regarding the alignment of the other
|
||||
block after the initial byte operations. The maximum number of
|
||||
full words (of type op_t) are compared in this way.
|
||||
|
||||
3. Compare the few remaining bytes. */
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
|
||||
A and B are known to be different.
|
||||
This is needed only on little-endian machines. */
|
||||
|
||||
static int memcmp_bytes __P((op_t, op_t));
|
||||
|
||||
# ifdef __GNUC__
|
||||
__inline
|
||||
# endif
|
||||
static int
|
||||
memcmp_bytes (a, b)
|
||||
op_t a, b;
|
||||
{
|
||||
long int srcp1 = (long int) &a;
|
||||
long int srcp2 = (long int) &b;
|
||||
op_t a0, b0;
|
||||
|
||||
do
|
||||
{
|
||||
a0 = ((byte *) srcp1)[0];
|
||||
b0 = ((byte *) srcp2)[0];
|
||||
srcp1 += 1;
|
||||
srcp2 += 1;
|
||||
}
|
||||
while (a0 == b0);
|
||||
return a0 - b0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int memcmp_common_alignment __P((long, long, size_t));
|
||||
|
||||
/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
|
||||
objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for
|
||||
memory operations on `op_t's. */
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#endif
|
||||
static int
|
||||
memcmp_common_alignment (srcp1, srcp2, len)
|
||||
long int srcp1;
|
||||
long int srcp2;
|
||||
size_t len;
|
||||
{
|
||||
op_t a0, a1;
|
||||
op_t b0, b1;
|
||||
|
||||
switch (len % 4)
|
||||
{
|
||||
default: /* Avoid warning about uninitialized local variables. */
|
||||
case 2:
|
||||
a0 = ((op_t *) srcp1)[0];
|
||||
b0 = ((op_t *) srcp2)[0];
|
||||
srcp1 -= 2 * OPSIZ;
|
||||
srcp2 -= 2 * OPSIZ;
|
||||
len += 2;
|
||||
goto do1;
|
||||
case 3:
|
||||
a1 = ((op_t *) srcp1)[0];
|
||||
b1 = ((op_t *) srcp2)[0];
|
||||
srcp1 -= OPSIZ;
|
||||
srcp2 -= OPSIZ;
|
||||
len += 1;
|
||||
goto do2;
|
||||
case 0:
|
||||
if (OP_T_THRES <= 3 * OPSIZ && len == 0)
|
||||
return 0;
|
||||
a0 = ((op_t *) srcp1)[0];
|
||||
b0 = ((op_t *) srcp2)[0];
|
||||
goto do3;
|
||||
case 1:
|
||||
a1 = ((op_t *) srcp1)[0];
|
||||
b1 = ((op_t *) srcp2)[0];
|
||||
srcp1 += OPSIZ;
|
||||
srcp2 += OPSIZ;
|
||||
len -= 1;
|
||||
if (OP_T_THRES <= 3 * OPSIZ && len == 0)
|
||||
goto do0;
|
||||
/* Fall through. */
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
a0 = ((op_t *) srcp1)[0];
|
||||
b0 = ((op_t *) srcp2)[0];
|
||||
if (a1 != b1)
|
||||
return CMP_LT_OR_GT (a1, b1);
|
||||
|
||||
do3:
|
||||
a1 = ((op_t *) srcp1)[1];
|
||||
b1 = ((op_t *) srcp2)[1];
|
||||
if (a0 != b0)
|
||||
return CMP_LT_OR_GT (a0, b0);
|
||||
|
||||
do2:
|
||||
a0 = ((op_t *) srcp1)[2];
|
||||
b0 = ((op_t *) srcp2)[2];
|
||||
if (a1 != b1)
|
||||
return CMP_LT_OR_GT (a1, b1);
|
||||
|
||||
do1:
|
||||
a1 = ((op_t *) srcp1)[3];
|
||||
b1 = ((op_t *) srcp2)[3];
|
||||
if (a0 != b0)
|
||||
return CMP_LT_OR_GT (a0, b0);
|
||||
|
||||
srcp1 += 4 * OPSIZ;
|
||||
srcp2 += 4 * OPSIZ;
|
||||
len -= 4;
|
||||
}
|
||||
while (len != 0);
|
||||
|
||||
/* This is the right position for do0. Please don't move
|
||||
it into the loop. */
|
||||
do0:
|
||||
if (a1 != b1)
|
||||
return CMP_LT_OR_GT (a1, b1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memcmp_not_common_alignment __P((long, long, size_t));
|
||||
|
||||
/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
|
||||
`op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory
|
||||
operations on `op_t', but SRCP1 *should be unaligned*. */
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#endif
|
||||
static int
|
||||
memcmp_not_common_alignment (srcp1, srcp2, len)
|
||||
long int srcp1;
|
||||
long int srcp2;
|
||||
size_t len;
|
||||
{
|
||||
op_t a0, a1, a2, a3;
|
||||
op_t b0, b1, b2, b3;
|
||||
op_t x;
|
||||
int shl, shr;
|
||||
|
||||
/* Calculate how to shift a word read at the memory operation
|
||||
aligned srcp1 to make it aligned for comparison. */
|
||||
|
||||
shl = 8 * (srcp1 % OPSIZ);
|
||||
shr = 8 * OPSIZ - shl;
|
||||
|
||||
/* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
|
||||
it points in the middle of. */
|
||||
srcp1 &= -OPSIZ;
|
||||
|
||||
switch (len % 4)
|
||||
{
|
||||
default: /* Avoid warning about uninitialized local variables. */
|
||||
case 2:
|
||||
a1 = ((op_t *) srcp1)[0];
|
||||
a2 = ((op_t *) srcp1)[1];
|
||||
b2 = ((op_t *) srcp2)[0];
|
||||
srcp1 -= 1 * OPSIZ;
|
||||
srcp2 -= 2 * OPSIZ;
|
||||
len += 2;
|
||||
goto do1;
|
||||
case 3:
|
||||
a0 = ((op_t *) srcp1)[0];
|
||||
a1 = ((op_t *) srcp1)[1];
|
||||
b1 = ((op_t *) srcp2)[0];
|
||||
srcp2 -= 1 * OPSIZ;
|
||||
len += 1;
|
||||
goto do2;
|
||||
case 0:
|
||||
if (OP_T_THRES <= 3 * OPSIZ && len == 0)
|
||||
return 0;
|
||||
a3 = ((op_t *) srcp1)[0];
|
||||
a0 = ((op_t *) srcp1)[1];
|
||||
b0 = ((op_t *) srcp2)[0];
|
||||
srcp1 += 1 * OPSIZ;
|
||||
goto do3;
|
||||
case 1:
|
||||
a2 = ((op_t *) srcp1)[0];
|
||||
a3 = ((op_t *) srcp1)[1];
|
||||
b3 = ((op_t *) srcp2)[0];
|
||||
srcp1 += 2 * OPSIZ;
|
||||
srcp2 += 1 * OPSIZ;
|
||||
len -= 1;
|
||||
if (OP_T_THRES <= 3 * OPSIZ && len == 0)
|
||||
goto do0;
|
||||
/* Fall through. */
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
a0 = ((op_t *) srcp1)[0];
|
||||
b0 = ((op_t *) srcp2)[0];
|
||||
x = MERGE(a2, shl, a3, shr);
|
||||
if (x != b3)
|
||||
return CMP_LT_OR_GT (x, b3);
|
||||
|
||||
do3:
|
||||
a1 = ((op_t *) srcp1)[1];
|
||||
b1 = ((op_t *) srcp2)[1];
|
||||
x = MERGE(a3, shl, a0, shr);
|
||||
if (x != b0)
|
||||
return CMP_LT_OR_GT (x, b0);
|
||||
|
||||
do2:
|
||||
a2 = ((op_t *) srcp1)[2];
|
||||
b2 = ((op_t *) srcp2)[2];
|
||||
x = MERGE(a0, shl, a1, shr);
|
||||
if (x != b1)
|
||||
return CMP_LT_OR_GT (x, b1);
|
||||
|
||||
do1:
|
||||
a3 = ((op_t *) srcp1)[3];
|
||||
b3 = ((op_t *) srcp2)[3];
|
||||
x = MERGE(a1, shl, a2, shr);
|
||||
if (x != b2)
|
||||
return CMP_LT_OR_GT (x, b2);
|
||||
|
||||
srcp1 += 4 * OPSIZ;
|
||||
srcp2 += 4 * OPSIZ;
|
||||
len -= 4;
|
||||
}
|
||||
while (len != 0);
|
||||
|
||||
/* This is the right position for do0. Please don't move
|
||||
it into the loop. */
|
||||
do0:
|
||||
x = MERGE(a2, shl, a3, shr);
|
||||
if (x != b3)
|
||||
return CMP_LT_OR_GT (x, b3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rpl_memcmp (s1, s2, len)
|
||||
const __ptr_t s1;
|
||||
const __ptr_t s2;
|
||||
size_t len;
|
||||
{
|
||||
op_t a0;
|
||||
op_t b0;
|
||||
long int srcp1 = (long int) s1;
|
||||
long int srcp2 = (long int) s2;
|
||||
op_t res;
|
||||
|
||||
if (len >= OP_T_THRES)
|
||||
{
|
||||
/* There are at least some bytes to compare. No need to test
|
||||
for LEN == 0 in this alignment loop. */
|
||||
while (srcp2 % OPSIZ != 0)
|
||||
{
|
||||
a0 = ((byte *) srcp1)[0];
|
||||
b0 = ((byte *) srcp2)[0];
|
||||
srcp1 += 1;
|
||||
srcp2 += 1;
|
||||
res = a0 - b0;
|
||||
if (res != 0)
|
||||
return res;
|
||||
len -= 1;
|
||||
}
|
||||
|
||||
/* SRCP2 is now aligned for memory operations on `op_t'.
|
||||
SRCP1 alignment determines if we can do a simple,
|
||||
aligned compare or need to shuffle bits. */
|
||||
|
||||
if (srcp1 % OPSIZ == 0)
|
||||
res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
|
||||
else
|
||||
res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
/* Number of bytes remaining in the interval [0..OPSIZ-1]. */
|
||||
srcp1 += len & -OPSIZ;
|
||||
srcp2 += len & -OPSIZ;
|
||||
len %= OPSIZ;
|
||||
}
|
||||
|
||||
/* There are just a few bytes to compare. Use byte memory operations. */
|
||||
while (len != 0)
|
||||
{
|
||||
a0 = ((byte *) srcp1)[0];
|
||||
b0 = ((byte *) srcp2)[0];
|
||||
srcp1 += 1;
|
||||
srcp2 += 1;
|
||||
res = a0 - b0;
|
||||
if (res != 0)
|
||||
return res;
|
||||
len -= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef weak_alias
|
||||
# undef bcmp
|
||||
weak_alias (memcmp, bcmp)
|
||||
#endif
|
44
src/realloc.c
Normal file
44
src/realloc.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* Work around bug on some systems where realloc (NULL, 0) fails.
|
||||
Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
|
||||
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, 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., Foundation,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#undef realloc
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
char *malloc ();
|
||||
char *realloc ();
|
||||
|
||||
/* Change the size of an allocated block of memory P to N bytes,
|
||||
with error checking. If N is zero, change it to 1. If P is NULL,
|
||||
use malloc. */
|
||||
|
||||
char *
|
||||
rpl_realloc (p, n)
|
||||
char *p;
|
||||
size_t n;
|
||||
{
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
if (p == 0)
|
||||
return malloc (n);
|
||||
return realloc (p, n);
|
||||
}
|
561
src/splay_tree.c
Normal file
561
src/splay_tree.c
Normal file
|
@ -0,0 +1,561 @@
|
|||
/*
|
||||
splay_tree.c -- splay tree and linked list convenience
|
||||
Copyright (C) 2004-2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Splay operation */
|
||||
|
||||
static splay_node_t *splay_top_down(splay_tree_t *tree, const void *data, int *result) {
|
||||
splay_node_t left = {0}, right = {0};
|
||||
splay_node_t *leftbottom = &left, *rightbottom = &right, *child, *grandchild;
|
||||
splay_node_t *root = tree->root;
|
||||
int c;
|
||||
|
||||
if(!root) {
|
||||
if(result)
|
||||
*result = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while((c = tree->compare(data, root->data))) {
|
||||
if(c < 0 && (child = root->left)) {
|
||||
c = tree->compare(data, child->data);
|
||||
|
||||
if(c < 0 && (grandchild = child->left)) {
|
||||
rightbottom->left = child;
|
||||
child->parent = rightbottom;
|
||||
rightbottom = child;
|
||||
|
||||
if((root->left = child->right))
|
||||
child->right->parent = root;
|
||||
|
||||
child->right = root;
|
||||
root->parent = child;
|
||||
|
||||
child->left = NULL;
|
||||
grandchild->parent = NULL;
|
||||
|
||||
root = grandchild;
|
||||
} else if (c > 0 && (grandchild = child->right)) {
|
||||
leftbottom->right = child;
|
||||
child->parent = leftbottom;
|
||||
leftbottom = child;
|
||||
|
||||
child->right = NULL;
|
||||
grandchild->parent = NULL;
|
||||
|
||||
rightbottom->left = root;
|
||||
root->parent = rightbottom;
|
||||
rightbottom = root;
|
||||
|
||||
root->left = NULL;
|
||||
|
||||
root = grandchild;
|
||||
} else {
|
||||
rightbottom->left = root;
|
||||
root->parent = rightbottom;
|
||||
rightbottom = root;
|
||||
|
||||
root->left = NULL;
|
||||
child->parent = NULL;
|
||||
|
||||
root = child;
|
||||
break;
|
||||
}
|
||||
} else if(c > 0 && (child = root->right)) {
|
||||
c = tree->compare(data, child->data);
|
||||
|
||||
if(c > 0 && (grandchild = child->right)) {
|
||||
leftbottom->right = child;
|
||||
child->parent = leftbottom;
|
||||
leftbottom = child;
|
||||
|
||||
if((root->right = child->left))
|
||||
child->left->parent = root;
|
||||
|
||||
child->left = root;
|
||||
root->parent = child;
|
||||
|
||||
child->right = NULL;
|
||||
grandchild->parent = NULL;
|
||||
|
||||
root = grandchild;
|
||||
} else if (c < 0 && (grandchild = child->left)) {
|
||||
rightbottom->left = child;
|
||||
child->parent = rightbottom;
|
||||
rightbottom = child;
|
||||
|
||||
child->left = NULL;
|
||||
grandchild->parent = NULL;
|
||||
|
||||
leftbottom->right = root;
|
||||
root->parent = leftbottom;
|
||||
leftbottom = root;
|
||||
|
||||
root->right = NULL;
|
||||
|
||||
root = grandchild;
|
||||
} else {
|
||||
leftbottom->right = root;
|
||||
root->parent = leftbottom;
|
||||
leftbottom = root;
|
||||
|
||||
root->right = NULL;
|
||||
child->parent = NULL;
|
||||
|
||||
root = child;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge trees */
|
||||
|
||||
if(left.right) {
|
||||
if(root->left) {
|
||||
leftbottom->right = root->left;
|
||||
root->left->parent = leftbottom;
|
||||
}
|
||||
root->left = left.right;
|
||||
left.right->parent = root;
|
||||
}
|
||||
|
||||
if(right.left) {
|
||||
if(root->right) {
|
||||
rightbottom->left = root->right;
|
||||
root->right->parent = rightbottom;
|
||||
}
|
||||
root->right = right.left;
|
||||
right.left->parent = root;
|
||||
}
|
||||
|
||||
/* Return result */
|
||||
|
||||
tree->root = root;
|
||||
if(result)
|
||||
*result = c;
|
||||
|
||||
return tree->root;
|
||||
}
|
||||
|
||||
static void splay_bottom_up(splay_tree_t *tree, splay_node_t *node) {
|
||||
splay_node_t *parent, *grandparent, *greatgrandparent;
|
||||
|
||||
while((parent = node->parent)) {
|
||||
if(!(grandparent = parent->parent)) { /* zig */
|
||||
if(node == parent->left) {
|
||||
if((parent->left = node->right))
|
||||
parent->left->parent = parent;
|
||||
node->right = parent;
|
||||
} else {
|
||||
if((parent->right = node->left))
|
||||
parent->right->parent = parent;
|
||||
node->left = parent;
|
||||
}
|
||||
|
||||
parent->parent = node;
|
||||
node->parent = NULL;
|
||||
} else {
|
||||
greatgrandparent = grandparent->parent;
|
||||
|
||||
if(node == parent->left && parent == grandparent->left) { /* left zig-zig */
|
||||
if((grandparent->left = parent->right))
|
||||
grandparent->left->parent = grandparent;
|
||||
parent->right = grandparent;
|
||||
grandparent->parent = parent;
|
||||
|
||||
if((parent->left = node->right))
|
||||
parent->left->parent = parent;
|
||||
node->right = parent;
|
||||
parent->parent = node;
|
||||
} else if(node == parent->right && parent == grandparent->right) { /* right zig-zig */
|
||||
if((grandparent->right = parent->left))
|
||||
grandparent->right->parent = grandparent;
|
||||
parent->left = grandparent;
|
||||
grandparent->parent = parent;
|
||||
|
||||
if((parent->right = node->left))
|
||||
parent->right->parent = parent;
|
||||
node->left = parent;
|
||||
parent->parent = node;
|
||||
} else if(node == parent->right && parent == grandparent->left) { /* left-right zig-zag */
|
||||
if((parent->right = node->left))
|
||||
parent->right->parent = parent;
|
||||
node->left = parent;
|
||||
parent->parent = node;
|
||||
|
||||
if((grandparent->left = node->right))
|
||||
grandparent->left->parent = grandparent;
|
||||
node->right = grandparent;
|
||||
grandparent->parent = node;
|
||||
} else { /* right-left zig-zag */
|
||||
if((parent->left = node->right))
|
||||
parent->left->parent = parent;
|
||||
node->right = parent;
|
||||
parent->parent = node;
|
||||
|
||||
if((grandparent->right = node->left))
|
||||
grandparent->right->parent = grandparent;
|
||||
node->left = grandparent;
|
||||
grandparent->parent = node;
|
||||
}
|
||||
|
||||
if((node->parent = greatgrandparent)) {
|
||||
if(grandparent == greatgrandparent->left)
|
||||
greatgrandparent->left = node;
|
||||
else
|
||||
greatgrandparent->right = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tree->root = node;
|
||||
}
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
splay_tree_t *splay_alloc_tree(splay_compare_t compare, splay_action_t delete) {
|
||||
splay_tree_t *tree;
|
||||
|
||||
tree = xmalloc_and_zero(sizeof(splay_tree_t));
|
||||
tree->compare = compare;
|
||||
tree->delete = delete;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void splay_free_tree(splay_tree_t *tree) {
|
||||
free(tree);
|
||||
}
|
||||
|
||||
splay_node_t *splay_alloc_node(void) {
|
||||
return xmalloc_and_zero(sizeof(splay_node_t));
|
||||
}
|
||||
|
||||
void splay_free_node(splay_tree_t *tree, splay_node_t *node) {
|
||||
if(node->data && tree->delete)
|
||||
tree->delete(node->data);
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Searching */
|
||||
|
||||
void *splay_search(splay_tree_t *tree, const void *data) {
|
||||
splay_node_t *node;
|
||||
|
||||
node = splay_search_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *splay_search_closest(splay_tree_t *tree, const void *data, int *result) {
|
||||
splay_node_t *node;
|
||||
|
||||
node = splay_search_closest_node(tree, data, result);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *splay_search_closest_smaller(splay_tree_t *tree, const void *data) {
|
||||
splay_node_t *node;
|
||||
|
||||
node = splay_search_closest_smaller_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *splay_search_closest_greater(splay_tree_t *tree, const void *data) {
|
||||
splay_node_t *node;
|
||||
|
||||
node = splay_search_closest_greater_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
splay_node_t *splay_search_node(splay_tree_t *tree, const void *data) {
|
||||
splay_node_t *node;
|
||||
int result;
|
||||
|
||||
node = splay_search_closest_node(tree, data, &result);
|
||||
|
||||
return result ? NULL : node;
|
||||
}
|
||||
|
||||
splay_node_t *splay_search_closest_node_nosplay(const splay_tree_t *tree, const void *data, int *result) {
|
||||
splay_node_t *node;
|
||||
int c;
|
||||
|
||||
node = tree->root;
|
||||
|
||||
if(!node) {
|
||||
if(result)
|
||||
*result = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
c = tree->compare(data, node->data);
|
||||
|
||||
if(c < 0) {
|
||||
if(node->left)
|
||||
node = node->left;
|
||||
else
|
||||
break;
|
||||
} else if(c > 0) {
|
||||
if(node->right)
|
||||
node = node->right;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(result)
|
||||
*result = c;
|
||||
return node;
|
||||
}
|
||||
|
||||
splay_node_t *splay_search_closest_node(splay_tree_t *tree, const void *data, int *result) {
|
||||
return splay_top_down(tree, data, result);
|
||||
}
|
||||
|
||||
splay_node_t *splay_search_closest_smaller_node(splay_tree_t *tree, const void *data) {
|
||||
splay_node_t *node;
|
||||
int result;
|
||||
|
||||
node = splay_search_closest_node(tree, data, &result);
|
||||
|
||||
if(result < 0)
|
||||
node = node->prev;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
splay_node_t *splay_search_closest_greater_node(splay_tree_t *tree, const void *data) {
|
||||
splay_node_t *node;
|
||||
int result;
|
||||
|
||||
node = splay_search_closest_node(tree, data, &result);
|
||||
|
||||
if(result > 0)
|
||||
node = node->next;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
splay_node_t *splay_insert(splay_tree_t *tree, void *data) {
|
||||
splay_node_t *closest, *new;
|
||||
int result;
|
||||
|
||||
if(!tree->root) {
|
||||
new = splay_alloc_node();
|
||||
new->data = data;
|
||||
splay_insert_top(tree, new);
|
||||
} else {
|
||||
closest = splay_search_closest_node(tree, data, &result);
|
||||
|
||||
if(!result)
|
||||
return NULL;
|
||||
|
||||
new = splay_alloc_node();
|
||||
new->data = data;
|
||||
|
||||
if(result < 0)
|
||||
splay_insert_before(tree, closest, new);
|
||||
else
|
||||
splay_insert_after(tree, closest, new);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
splay_node_t *splay_insert_node(splay_tree_t *tree, splay_node_t *node) {
|
||||
splay_node_t *closest;
|
||||
int result;
|
||||
|
||||
if(!tree->root)
|
||||
splay_insert_top(tree, node);
|
||||
else {
|
||||
closest = splay_search_closest_node(tree, node->data, &result);
|
||||
|
||||
if(!result)
|
||||
return NULL;
|
||||
|
||||
if(result < 0)
|
||||
splay_insert_before(tree, closest, node);
|
||||
else
|
||||
splay_insert_after(tree, closest, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void splay_insert_top(splay_tree_t *tree, splay_node_t *node) {
|
||||
node->prev = node->next = node->left = node->right = node->parent = NULL;
|
||||
tree->head = tree->tail = tree->root = node;
|
||||
}
|
||||
|
||||
void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t *node) {
|
||||
if(!before) {
|
||||
if(tree->tail)
|
||||
splay_insert_after(tree, tree->tail, node);
|
||||
else
|
||||
splay_insert_top(tree, node);
|
||||
return;
|
||||
}
|
||||
|
||||
node->next = before;
|
||||
if((node->prev = before->prev))
|
||||
before->prev->next = node;
|
||||
else
|
||||
tree->head = node;
|
||||
before->prev = node;
|
||||
|
||||
splay_bottom_up(tree, before);
|
||||
|
||||
node->right = before;
|
||||
before->parent = node;
|
||||
if((node->left = before->left))
|
||||
before->left->parent = node;
|
||||
before->left = NULL;
|
||||
|
||||
node->parent = NULL;
|
||||
tree->root = node;
|
||||
}
|
||||
|
||||
void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *node) {
|
||||
if(!after) {
|
||||
if(tree->head)
|
||||
splay_insert_before(tree, tree->head, node);
|
||||
else
|
||||
splay_insert_top(tree, node);
|
||||
return;
|
||||
}
|
||||
|
||||
node->prev = after;
|
||||
if((node->next = after->next))
|
||||
after->next->prev = node;
|
||||
else
|
||||
tree->tail = node;
|
||||
after->next = node;
|
||||
|
||||
splay_bottom_up(tree, after);
|
||||
|
||||
node->left = after;
|
||||
after->parent = node;
|
||||
if((node->right = after->right))
|
||||
after->right->parent = node;
|
||||
after->right = NULL;
|
||||
|
||||
node->parent = NULL;
|
||||
tree->root = node;
|
||||
}
|
||||
|
||||
splay_node_t *splay_unlink(splay_tree_t *tree, void *data) {
|
||||
splay_node_t *node;
|
||||
|
||||
node = splay_search_node(tree, data);
|
||||
|
||||
if(node)
|
||||
splay_unlink_node(tree, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void splay_unlink_node(splay_tree_t *tree, splay_node_t *node) {
|
||||
if(node->prev)
|
||||
node->prev->next = node->next;
|
||||
else
|
||||
tree->head = node->next;
|
||||
|
||||
if(node->next)
|
||||
node->next->prev = node->prev;
|
||||
else
|
||||
tree->tail = node->prev;
|
||||
|
||||
splay_bottom_up(tree, node);
|
||||
|
||||
if(node->prev) {
|
||||
node->left->parent = NULL;
|
||||
tree->root = node->left;
|
||||
if((node->prev->right = node->right))
|
||||
node->right->parent = node->prev;
|
||||
} else if(node->next) {
|
||||
tree->root = node->right;
|
||||
node->right->parent = NULL;
|
||||
} else {
|
||||
tree->root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void splay_delete_node(splay_tree_t *tree, splay_node_t *node) {
|
||||
splay_unlink_node(tree, node);
|
||||
splay_free_node(tree, node);
|
||||
}
|
||||
|
||||
void splay_delete(splay_tree_t *tree, void *data) {
|
||||
splay_node_t *node;
|
||||
|
||||
node = splay_search_node(tree, data);
|
||||
|
||||
if(node)
|
||||
splay_delete_node(tree, node);
|
||||
}
|
||||
|
||||
/* Fast tree cleanup */
|
||||
|
||||
void splay_delete_tree(splay_tree_t *tree) {
|
||||
splay_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
splay_free_node(tree, node);
|
||||
}
|
||||
|
||||
splay_free_tree(tree);
|
||||
}
|
||||
|
||||
/* Tree walking */
|
||||
|
||||
void splay_foreach(const splay_tree_t *tree, splay_action_t action) {
|
||||
splay_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node->data);
|
||||
}
|
||||
}
|
||||
|
||||
void splay_foreach_node(const splay_tree_t *tree, splay_action_t action) {
|
||||
splay_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node);
|
||||
}
|
||||
}
|
107
src/splay_tree.h
Normal file
107
src/splay_tree.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
splay_tree.h -- header file for splay_tree.c
|
||||
Copyright (C) 2004-2006 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __SPLAY_TREE_H__
|
||||
#define __SPLAY_TREE_H__
|
||||
|
||||
typedef struct splay_node_t {
|
||||
|
||||
/* Linked list part */
|
||||
|
||||
struct splay_node_t *next;
|
||||
struct splay_node_t *prev;
|
||||
|
||||
/* Tree part */
|
||||
|
||||
struct splay_node_t *parent;
|
||||
struct splay_node_t *left;
|
||||
struct splay_node_t *right;
|
||||
|
||||
/* Payload */
|
||||
|
||||
void *data;
|
||||
|
||||
} splay_node_t;
|
||||
|
||||
typedef int (*splay_compare_t)(const void *, const void *);
|
||||
typedef void (*splay_action_t)(const void *);
|
||||
typedef void (*splay_action_node_t)(const splay_node_t *);
|
||||
|
||||
typedef struct splay_tree_t {
|
||||
|
||||
/* Linked list part */
|
||||
|
||||
splay_node_t *head;
|
||||
splay_node_t *tail;
|
||||
|
||||
/* Tree part */
|
||||
|
||||
splay_node_t *root;
|
||||
|
||||
splay_compare_t compare;
|
||||
splay_action_t delete;
|
||||
|
||||
} splay_tree_t;
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
extern splay_tree_t *splay_alloc_tree(splay_compare_t, splay_action_t);
|
||||
extern void splay_free_tree(splay_tree_t *);
|
||||
|
||||
extern splay_node_t *splay_alloc_node(void);
|
||||
extern void splay_free_node(splay_tree_t *tree, splay_node_t *);
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
extern splay_node_t *splay_insert(splay_tree_t *, void *);
|
||||
extern splay_node_t *splay_insert_node(splay_tree_t *, splay_node_t *);
|
||||
|
||||
extern void splay_insert_top(splay_tree_t *, splay_node_t *);
|
||||
extern void splay_insert_before(splay_tree_t *, splay_node_t *, splay_node_t *);
|
||||
extern void splay_insert_after(splay_tree_t *, splay_node_t *, splay_node_t *);
|
||||
|
||||
extern splay_node_t *splay_unlink(splay_tree_t *, void *);
|
||||
extern void splay_unlink_node(splay_tree_t *tree, splay_node_t *);
|
||||
extern void splay_delete(splay_tree_t *, void *);
|
||||
extern void splay_delete_node(splay_tree_t *, splay_node_t *);
|
||||
|
||||
/* Fast tree cleanup */
|
||||
|
||||
extern void splay_delete_tree(splay_tree_t *);
|
||||
|
||||
/* Searching */
|
||||
|
||||
extern void *splay_search(splay_tree_t *, const void *);
|
||||
extern void *splay_search_closest(splay_tree_t *, const void *, int *);
|
||||
extern void *splay_search_closest_smaller(splay_tree_t *, const void *);
|
||||
extern void *splay_search_closest_greater(splay_tree_t *, const void *);
|
||||
|
||||
extern splay_node_t *splay_search_node(splay_tree_t *, const void *);
|
||||
extern splay_node_t *splay_search_closest_node(splay_tree_t *, const void *, int *);
|
||||
extern splay_node_t *splay_search_closest_node_nosplay(const splay_tree_t *, const void *, int *);
|
||||
extern splay_node_t *splay_search_closest_smaller_node(splay_tree_t *, const void *);
|
||||
extern splay_node_t *splay_search_closest_greater_node(splay_tree_t *, const void *);
|
||||
|
||||
/* Tree walking */
|
||||
|
||||
extern void splay_foreach(const splay_tree_t *, splay_action_t);
|
||||
extern void splay_foreach_node(const splay_tree_t *, splay_action_t);
|
||||
|
||||
#endif
|
76
src/utils.c
Normal file
76
src/utils.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
utils.c -- gathering of some stupid small functions
|
||||
Copyright (C) 1999-2005 Ivo Timmermans
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "../src/logger.h"
|
||||
#include "utils.h"
|
||||
|
||||
const char hexadecimals[] = "0123456789ABCDEF";
|
||||
|
||||
int charhex2bin(char c) {
|
||||
if(isdigit(c))
|
||||
return c - '0';
|
||||
else
|
||||
return toupper(c) - 'A' + 10;
|
||||
}
|
||||
|
||||
|
||||
void hex2bin(char *src, char *dst, int length) {
|
||||
int i;
|
||||
for(i = 0; i < length; i++)
|
||||
dst[i] = charhex2bin(src[i * 2]) * 16 + charhex2bin(src[i * 2 + 1]);
|
||||
}
|
||||
|
||||
void bin2hex(char *src, char *dst, int length) {
|
||||
int i;
|
||||
for(i = length - 1; i >= 0; i--) {
|
||||
dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15];
|
||||
dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4];
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
|
||||
#ifdef HAVE_CYGWIN
|
||||
#include <w32api/windows.h>
|
||||
#endif
|
||||
|
||||
const char *winerror(int err) {
|
||||
static char buf[1024], *newline;
|
||||
|
||||
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof(buf), NULL)) {
|
||||
strncpy(buf, "(unable to format errormessage)", sizeof(buf));
|
||||
};
|
||||
|
||||
if((newline = strchr(buf, '\r')))
|
||||
*newline = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int bitfield_to_int(void *bitfield, size_t size) {
|
||||
unsigned int value = 0;
|
||||
if(size > sizeof value)
|
||||
size = sizeof value;
|
||||
memcpy(&value, bitfield, size);
|
||||
return value;
|
||||
}
|
47
src/utils.h
Normal file
47
src/utils.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
utils.h -- header file for utils.c
|
||||
Copyright (C) 1999-2005 Ivo Timmermans
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_UTILS_H__
|
||||
#define __TINC_UTILS_H__
|
||||
|
||||
extern void hex2bin(char *src, char *dst, int length);
|
||||
extern void bin2hex(char *src, char *dst, int length);
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
extern const char *winerror(int);
|
||||
#define strerror(x) ((x)>0?strerror(x):winerror(GetLastError()))
|
||||
#define sockerrno WSAGetLastError()
|
||||
#define sockstrerror(x) winerror(x)
|
||||
#define sockwouldblock(x) ((x) == WSAEWOULDBLOCK || (x) == WSAEINTR)
|
||||
#define sockmsgsize(x) ((x) == WSAEMSGSIZE)
|
||||
#define sockinprogress(x) ((x) == WSAEINPROGRESS || (x) == WSAEWOULDBLOCK)
|
||||
#define sockinuse(x) ((x) == WSAEADDRINUSE)
|
||||
#else
|
||||
#define sockerrno errno
|
||||
#define sockstrerror(x) strerror(x)
|
||||
#define sockwouldblock(x) ((x) == EWOULDBLOCK || (x) == EINTR)
|
||||
#define sockmsgsize(x) ((x) == EMSGSIZE)
|
||||
#define sockinprogress(x) ((x) == EINPROGRESS)
|
||||
#define sockinuse(x) ((x) == EADDRINUSE)
|
||||
#endif
|
||||
|
||||
extern unsigned int bitfield_to_int(void *bitfield, size_t size);
|
||||
|
||||
#endif /* __TINC_UTILS_H__ */
|
29
src/xalloc.h
Normal file
29
src/xalloc.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#ifndef PARAMS
|
||||
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
|
||||
# define PARAMS(Args) Args
|
||||
# else
|
||||
# define PARAMS(Args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Exit value when the requested amount of memory is not available.
|
||||
The caller may set it to some other value. */
|
||||
extern int xalloc_exit_failure;
|
||||
|
||||
/* FIXME: describe */
|
||||
extern char *const xalloc_msg_memory_exhausted;
|
||||
|
||||
/* FIXME: describe */
|
||||
extern void (*xalloc_fail_func) ();
|
||||
|
||||
void *xmalloc PARAMS ((size_t n)) __attribute__ ((__malloc__));
|
||||
void *xmalloc_and_zero PARAMS ((size_t n)) __attribute__ ((__malloc__));
|
||||
void *xcalloc PARAMS ((size_t n, size_t s));
|
||||
void *xrealloc PARAMS ((void *p, size_t n)) __attribute__ ((__malloc__));
|
||||
|
||||
char *xstrdup PARAMS ((const char *s)) __attribute__ ((__malloc__));
|
||||
|
||||
extern int xasprintf(char **strp, const char *fmt, ...);
|
||||
extern int xvasprintf(char **strp, const char *fmt, va_list ap);
|
160
src/xmalloc.c
Normal file
160
src/xmalloc.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* xmalloc.c -- malloc with out of memory checking
|
||||
Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
|
||||
|
||||
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, 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., Foundation,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
void *calloc ();
|
||||
void *malloc ();
|
||||
void *realloc ();
|
||||
void free ();
|
||||
#endif
|
||||
|
||||
#include "dropin.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
# define EXIT_FAILURE 1
|
||||
#endif
|
||||
|
||||
/* Prototypes for functions defined here. */
|
||||
#if defined (__STDC__) && __STDC__
|
||||
void *xmalloc (size_t n);
|
||||
void *xcalloc (size_t n, size_t s);
|
||||
void *xrealloc (void *p, size_t n);
|
||||
#endif
|
||||
|
||||
/* Exit value when the requested amount of memory is not available.
|
||||
The caller may set it to some other value. */
|
||||
int xalloc_exit_failure = EXIT_FAILURE;
|
||||
|
||||
/* FIXME: describe */
|
||||
char *const xalloc_msg_memory_exhausted = "Memory exhausted";
|
||||
|
||||
/* FIXME: describe */
|
||||
void (*xalloc_fail_func) (int) = 0;
|
||||
|
||||
static void
|
||||
xalloc_fail (int size)
|
||||
{
|
||||
if (xalloc_fail_func)
|
||||
(*xalloc_fail_func) (size);
|
||||
fprintf(stderr, "%s\n", xalloc_msg_memory_exhausted);
|
||||
exit(xalloc_exit_failure);
|
||||
}
|
||||
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
void *
|
||||
xmalloc (n)
|
||||
size_t n;
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
xalloc_fail ((int)n);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Allocate N bytes of memory dynamically, and set it all to zero. */
|
||||
|
||||
void *
|
||||
xmalloc_and_zero (n)
|
||||
size_t n;
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
xalloc_fail ((int)n);
|
||||
memset (p, '\0', n);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Change the size of an allocated block of memory P to N bytes,
|
||||
with error checking.
|
||||
If P is NULL, run xmalloc. */
|
||||
|
||||
void *
|
||||
xrealloc (p, n)
|
||||
void *p;
|
||||
size_t n;
|
||||
{
|
||||
p = realloc (p, n);
|
||||
if (p == 0)
|
||||
xalloc_fail (n);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Duplicate a string */
|
||||
|
||||
char *xstrdup(const char *s)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strdup(s);
|
||||
if(!p)
|
||||
xalloc_fail ((int)strlen(s));
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
/* Allocate memory for N elements of S bytes, with error checking. */
|
||||
|
||||
void *
|
||||
xcalloc (n, s)
|
||||
size_t n, s;
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = calloc (n, s);
|
||||
if (p == 0)
|
||||
xalloc_fail ();
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* NOT_USED */
|
||||
|
||||
int xasprintf(char **strp, const char *fmt, ...) {
|
||||
int result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = xvasprintf(strp, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
int xvasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
int result = vasprintf(strp, fmt, ap);
|
||||
if(result < 0) {
|
||||
fprintf(stderr, "vasprintf() failed: %s\n", strerror(errno));
|
||||
exit(xalloc_exit_failure);
|
||||
}
|
||||
return result;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue