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:
Guus Sliepen 2009-12-31 13:19:13 +01:00
parent 41497246ee
commit 35b1c25093
28 changed files with 12 additions and 25 deletions

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

133
src/getopt.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}