2005-07-22 07:46:58 +00:00
|
|
|
/* emem.c
|
|
|
|
* Ethereal memory management and garbage collection functions
|
|
|
|
* Ronnie Sahlberg 2005
|
|
|
|
*
|
2005-07-22 17:55:47 +00:00
|
|
|
* $Id$
|
2005-07-22 07:46:58 +00:00
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@ethereal.com>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2005-07-24 01:21:38 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
2005-07-22 07:46:58 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
2005-07-22 23:38:51 +00:00
|
|
|
#include <stdlib.h>
|
2005-07-24 00:29:57 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2006-02-27 20:51:53 +00:00
|
|
|
#include <windows.h> /* VirtualAlloc, VirtualProtect */
|
2006-01-09 23:11:40 +00:00
|
|
|
#include <process.h> /* getpid */
|
|
|
|
#endif
|
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
#include <glib.h>
|
2005-07-24 01:21:38 +00:00
|
|
|
#include <proto.h>
|
2005-07-22 07:46:58 +00:00
|
|
|
#include "emem.h"
|
2006-01-10 21:12:48 +00:00
|
|
|
#include <wiretap/file_util.h>
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
/* Add guard pages at each end of our allocated memory */
|
2006-03-03 20:44:53 +00:00
|
|
|
#if defined(HAVE_SYSCONF) && defined(HAVE_MMAP) && defined(HAVE_MPROTECT) && defined(HAVE_STDINT_H)
|
|
|
|
#include <stdint.h>
|
2006-02-27 20:51:53 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#define USE_GUARD_PAGES 1
|
|
|
|
#endif
|
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
/* When required, allocate more memory from the OS in this size chunks */
|
|
|
|
#define EMEM_PACKET_CHUNK_SIZE 10485760
|
|
|
|
|
2006-01-09 23:11:40 +00:00
|
|
|
/* The maximum number of allocations per chunk */
|
|
|
|
#define EMEM_ALLOCS_PER_CHUNK (EMEM_PACKET_CHUNK_SIZE / 512)
|
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
/*
|
2006-01-09 23:11:40 +00:00
|
|
|
* Tools like Valgrind and ElectricFence don't work well with memchunks.
|
2005-08-26 15:45:31 +00:00
|
|
|
* Uncomment the defines below to make {ep|se}_alloc() allocate each
|
|
|
|
* object individually.
|
|
|
|
*/
|
|
|
|
/* #define EP_DEBUG_FREE 1 */
|
|
|
|
/* #define SE_DEBUG_FREE 1 */
|
|
|
|
|
2006-01-09 23:11:40 +00:00
|
|
|
#if GLIB_MAJOR_VERSION >= 2
|
|
|
|
GRand *rand_state = NULL;
|
|
|
|
#endif
|
2006-01-10 21:12:48 +00:00
|
|
|
|
|
|
|
#define EMEM_CANARY_SIZE 8
|
|
|
|
#define EMEM_CANARY_DATA_SIZE (EMEM_CANARY_SIZE * 2 - 1)
|
|
|
|
guint8 ep_canary[EMEM_CANARY_DATA_SIZE], se_canary[EMEM_CANARY_DATA_SIZE];
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
typedef struct _emem_chunk_t {
|
|
|
|
struct _emem_chunk_t *next;
|
2006-02-27 20:51:53 +00:00
|
|
|
unsigned int amount_free_init;
|
2005-07-22 07:46:58 +00:00
|
|
|
unsigned int amount_free;
|
2006-02-27 20:51:53 +00:00
|
|
|
unsigned int free_offset_init;
|
2005-07-22 07:46:58 +00:00
|
|
|
unsigned int free_offset;
|
|
|
|
char *buf;
|
2006-01-18 20:02:19 +00:00
|
|
|
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
|
2006-01-09 23:11:40 +00:00
|
|
|
unsigned int c_count;
|
|
|
|
void *canary[EMEM_ALLOCS_PER_CHUNK];
|
2006-01-10 21:12:48 +00:00
|
|
|
guint8 cmp_len[EMEM_ALLOCS_PER_CHUNK];
|
2006-01-18 20:02:19 +00:00
|
|
|
#endif
|
2005-07-22 07:46:58 +00:00
|
|
|
} emem_chunk_t;
|
|
|
|
|
|
|
|
typedef struct _emem_header_t {
|
|
|
|
emem_chunk_t *free_list;
|
|
|
|
emem_chunk_t *used_list;
|
|
|
|
} emem_header_t;
|
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
static emem_header_t ep_packet_mem;
|
|
|
|
static emem_header_t se_packet_mem;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-01-09 23:11:40 +00:00
|
|
|
/*
|
|
|
|
* Set a canary value to be placed between memchunks.
|
|
|
|
*/
|
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
void
|
|
|
|
emem_canary(guint8 *canary) {
|
|
|
|
int i;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
/* First, use GLib's random function if we have it */
|
2006-01-09 23:11:40 +00:00
|
|
|
#if GLIB_MAJOR_VERSION >= 2
|
|
|
|
if (rand_state == NULL) {
|
|
|
|
rand_state = g_rand_new();
|
|
|
|
}
|
2006-01-10 21:12:48 +00:00
|
|
|
for (i = 0; i < EMEM_CANARY_DATA_SIZE; i ++) {
|
|
|
|
canary[i] = (guint8) g_rand_int(rand_state);
|
|
|
|
}
|
|
|
|
return;
|
2006-01-09 23:11:40 +00:00
|
|
|
#else
|
2006-01-10 21:12:48 +00:00
|
|
|
FILE *fp;
|
|
|
|
size_t sz;
|
|
|
|
/* Try /dev/urandom */
|
2006-01-11 17:18:33 +00:00
|
|
|
if ((fp = eth_fopen("/dev/urandom", "r")) != NULL) {
|
2006-01-11 02:05:05 +00:00
|
|
|
sz = fread(canary, EMEM_CANARY_DATA_SIZE, 1, fp);
|
2006-01-10 21:31:33 +00:00
|
|
|
fclose(fp);
|
2006-01-10 21:12:48 +00:00
|
|
|
if (sz == EMEM_CANARY_SIZE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-09 23:11:40 +00:00
|
|
|
/* Our last resort */
|
2006-01-10 21:12:48 +00:00
|
|
|
srandom(time(NULL) | getpid());
|
|
|
|
for (i = 0; i < EMEM_CANARY_DATA_SIZE; i ++) {
|
|
|
|
canary[i] = (guint8) random();
|
|
|
|
}
|
|
|
|
return;
|
2006-01-09 23:11:40 +00:00
|
|
|
#endif /* GLIB_MAJOR_VERSION >= 2 */
|
|
|
|
}
|
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
#if !defined(SE_DEBUG_FREE)
|
2006-01-10 21:12:48 +00:00
|
|
|
/*
|
|
|
|
* Given an allocation size, return the amount of padding needed for
|
|
|
|
* the canary value.
|
|
|
|
*/
|
2006-01-11 02:05:05 +00:00
|
|
|
static guint8
|
2006-01-10 21:12:48 +00:00
|
|
|
emem_canary_pad (size_t allocation) {
|
|
|
|
guint8 pad;
|
|
|
|
|
|
|
|
pad = EMEM_CANARY_SIZE - (allocation % EMEM_CANARY_SIZE);
|
|
|
|
if (pad < EMEM_CANARY_SIZE)
|
|
|
|
pad += EMEM_CANARY_SIZE;
|
|
|
|
|
|
|
|
return pad;
|
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
#endif
|
2006-01-10 21:12:48 +00:00
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
/* Initialize the packet-lifetime memory allocation pool.
|
2006-01-09 23:11:40 +00:00
|
|
|
* This function should be called only once when Ethereal or Tethereal starts
|
2005-07-22 07:46:58 +00:00
|
|
|
* up.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ep_init_chunk(void)
|
|
|
|
{
|
2006-01-09 23:11:40 +00:00
|
|
|
ep_packet_mem.free_list=NULL;
|
|
|
|
ep_packet_mem.used_list=NULL;
|
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
emem_canary(ep_canary);
|
2005-08-12 08:51:08 +00:00
|
|
|
}
|
|
|
|
/* Initialize the capture-lifetime memory allocation pool.
|
2006-01-09 23:11:40 +00:00
|
|
|
* This function should be called only once when Ethereal or Tethereal starts
|
2005-08-12 08:51:08 +00:00
|
|
|
* up.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
se_init_chunk(void)
|
|
|
|
{
|
2006-01-09 23:11:40 +00:00
|
|
|
se_packet_mem.free_list=NULL;
|
|
|
|
se_packet_mem.used_list=NULL;
|
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
emem_canary(se_canary);
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
#if !defined(SE_DEBUG_FREE)
|
2006-02-27 20:51:53 +00:00
|
|
|
static void
|
|
|
|
emem_create_chunk(emem_chunk_t **free_list) {
|
|
|
|
#if defined (_WIN32)
|
|
|
|
SYSTEM_INFO sysinfo;
|
|
|
|
int pagesize;
|
|
|
|
BOOL ret;
|
|
|
|
char *buf_end, *prot1, *prot2;
|
|
|
|
DWORD oldprot;
|
|
|
|
#elif defined(USE_GUARD_PAGES)
|
2006-03-03 20:44:53 +00:00
|
|
|
intptr_t pagesize = sysconf(_SC_PAGESIZE);
|
|
|
|
int ret;
|
2006-02-27 20:51:53 +00:00
|
|
|
char *buf_end, *prot1, *prot2;
|
|
|
|
#endif
|
|
|
|
/* we dont have any free data, so we must allocate a new one */
|
|
|
|
if(!*free_list){
|
|
|
|
emem_chunk_t *npc;
|
|
|
|
npc = g_malloc(sizeof(emem_chunk_t));
|
|
|
|
npc->next = NULL;
|
2006-03-07 16:31:47 +00:00
|
|
|
#if ! defined(EP_DEBUG_FREE) && ! defined(SE_DEBUG_FREE)
|
2006-02-27 20:51:53 +00:00
|
|
|
npc->c_count = 0;
|
2006-03-07 16:31:47 +00:00
|
|
|
#endif
|
2006-02-27 20:51:53 +00:00
|
|
|
*free_list = npc;
|
|
|
|
#if defined (_WIN32)
|
|
|
|
/*
|
|
|
|
* MSDN documents VirtualAlloc/VirtualProtect at
|
|
|
|
* http://msdn.microsoft.com/library/en-us/memory/base/creating_guard_pages.asp
|
|
|
|
*/
|
|
|
|
GetSystemInfo(&sysinfo);
|
|
|
|
pagesize = sysinfo.dwPageSize;
|
|
|
|
|
|
|
|
/* XXX - is MEM_COMMIT|MEM_RESERVE correct? */
|
|
|
|
npc->buf = VirtualAlloc(NULL, EMEM_PACKET_CHUNK_SIZE,
|
|
|
|
MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
|
|
|
g_assert(npc->buf != NULL);
|
|
|
|
buf_end = npc->buf + EMEM_PACKET_CHUNK_SIZE;
|
|
|
|
|
|
|
|
/* Align our guard pages on page-sized boundaries */
|
|
|
|
prot1 = (char *) ((((int) npc->buf + pagesize - 1) / pagesize) * pagesize);
|
|
|
|
prot2 = (char *) ((((int) buf_end - (1 * pagesize)) / pagesize) * pagesize);
|
|
|
|
|
|
|
|
ret = VirtualProtect(prot1, pagesize, PAGE_NOACCESS, &oldprot);
|
|
|
|
g_assert(ret == TRUE);
|
|
|
|
ret = VirtualProtect(prot2, pagesize, PAGE_NOACCESS, &oldprot);
|
|
|
|
g_assert(ret == TRUE);
|
|
|
|
|
|
|
|
npc->amount_free_init = prot2 - prot1 - pagesize;
|
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset_init = (prot1 - npc->buf) + pagesize;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
|
|
|
|
#elif defined(USE_GUARD_PAGES)
|
|
|
|
npc->buf = mmap(NULL, EMEM_PACKET_CHUNK_SIZE,
|
|
|
|
PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
|
|
|
|
g_assert(npc->buf != MAP_FAILED);
|
|
|
|
buf_end = npc->buf + EMEM_PACKET_CHUNK_SIZE;
|
|
|
|
|
|
|
|
/* Align our guard pages on page-sized boundaries */
|
2006-03-03 20:44:53 +00:00
|
|
|
prot1 = (char *) ((((intptr_t) npc->buf + pagesize - 1) / pagesize) * pagesize);
|
|
|
|
prot2 = (char *) ((((intptr_t) buf_end - (1 * pagesize)) / pagesize) * pagesize);
|
2006-02-27 20:51:53 +00:00
|
|
|
ret = mprotect(prot1, pagesize, PROT_NONE);
|
|
|
|
g_assert(ret != -1);
|
|
|
|
ret = mprotect(prot2, pagesize, PROT_NONE);
|
|
|
|
g_assert(ret != -1);
|
|
|
|
|
|
|
|
npc->amount_free_init = prot2 - prot1 - pagesize;
|
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset_init = (prot1 - npc->buf) + pagesize;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
|
|
|
|
#else /* Is there a draft in here? */
|
|
|
|
npc->amount_free_init = EMEM_PACKET_CHUNK_SIZE;
|
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset_init = 0;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
npc->buf = g_malloc(EMEM_PACKET_CHUNK_SIZE);
|
|
|
|
#endif /* USE_GUARD_PAGES */
|
2006-01-09 23:11:40 +00:00
|
|
|
}
|
2006-02-27 20:51:53 +00:00
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
#endif
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
/* allocate 'size' amount of memory with an allocation lifetime until the
|
|
|
|
* next packet.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
ep_alloc(size_t size)
|
|
|
|
{
|
2006-03-07 16:31:47 +00:00
|
|
|
void *buf;
|
|
|
|
#ifndef EP_DEBUG_FREE
|
|
|
|
void *cptr;
|
2006-01-10 21:12:48 +00:00
|
|
|
guint8 pad = emem_canary_pad(size);
|
|
|
|
emem_chunk_t *free_list;
|
2006-03-07 16:31:47 +00:00
|
|
|
#endif
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
#ifndef EP_DEBUG_FREE
|
2006-01-10 21:12:48 +00:00
|
|
|
/* Round up to an 8 byte boundary. Make sure we have at least
|
|
|
|
* 8 pad bytes for our canary.
|
|
|
|
*/
|
|
|
|
size += pad;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
|
|
|
/* make sure we dont try to allocate too much (arbitrary limit) */
|
2005-07-24 01:21:38 +00:00
|
|
|
DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
emem_create_chunk(&ep_packet_mem.free_list);
|
2005-08-12 08:51:08 +00:00
|
|
|
|
|
|
|
/* oops, we need to allocate more memory to serve this request
|
|
|
|
* than we have free. move this node to the used list and try again
|
|
|
|
*/
|
2006-01-09 23:11:40 +00:00
|
|
|
if(size>ep_packet_mem.free_list->amount_free || ep_packet_mem.free_list->c_count >= EMEM_ALLOCS_PER_CHUNK){
|
2005-08-12 08:51:08 +00:00
|
|
|
emem_chunk_t *npc;
|
|
|
|
npc=ep_packet_mem.free_list;
|
|
|
|
ep_packet_mem.free_list=ep_packet_mem.free_list->next;
|
|
|
|
npc->next=ep_packet_mem.used_list;
|
|
|
|
ep_packet_mem.used_list=npc;
|
|
|
|
}
|
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
emem_create_chunk(&ep_packet_mem.free_list);
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
free_list = ep_packet_mem.free_list;
|
|
|
|
|
|
|
|
buf = free_list->buf + free_list->free_offset;
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
free_list->amount_free -= size;
|
|
|
|
free_list->free_offset += size;
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
cptr = (char *)buf + size - pad;
|
|
|
|
memcpy(cptr, &ep_canary, pad);
|
|
|
|
free_list->canary[free_list->c_count] = cptr;
|
|
|
|
free_list->cmp_len[free_list->c_count] = pad;
|
|
|
|
free_list->c_count++;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
#else /* EP_DEBUG_FREE */
|
|
|
|
emem_chunk_t *npc;
|
|
|
|
|
|
|
|
npc=g_malloc(sizeof(emem_chunk_t));
|
|
|
|
npc->next=ep_packet_mem.used_list;
|
|
|
|
npc->amount_free=size;
|
|
|
|
npc->free_offset=0;
|
|
|
|
npc->buf=g_malloc(size);
|
|
|
|
buf = npc->buf;
|
|
|
|
ep_packet_mem.used_list=npc;
|
|
|
|
#endif /* EP_DEBUG_FREE */
|
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
/* allocate 'size' amount of memory with an allocation lifetime until the
|
|
|
|
* next capture.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
se_alloc(size_t size)
|
|
|
|
{
|
2006-03-07 16:31:47 +00:00
|
|
|
void *buf;
|
|
|
|
#ifndef SE_DEBUG_FREE
|
|
|
|
void *cptr;
|
2006-01-10 21:12:48 +00:00
|
|
|
guint8 pad = emem_canary_pad(size);
|
|
|
|
emem_chunk_t *free_list;
|
2006-03-07 16:31:47 +00:00
|
|
|
#endif
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
#ifndef SE_DEBUG_FREE
|
2006-01-10 21:12:48 +00:00
|
|
|
/* Round up to an 8 byte boundary. Make sure we have at least
|
|
|
|
* 8 pad bytes for our canary.
|
|
|
|
*/
|
|
|
|
size += pad;
|
2005-08-12 08:51:08 +00:00
|
|
|
|
|
|
|
/* make sure we dont try to allocate too much (arbitrary limit) */
|
|
|
|
DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
|
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
emem_create_chunk(&se_packet_mem.free_list);
|
2005-07-22 07:46:58 +00:00
|
|
|
|
|
|
|
/* oops, we need to allocate more memory to serve this request
|
|
|
|
* than we have free. move this node to the used list and try again
|
|
|
|
*/
|
2006-01-09 23:11:40 +00:00
|
|
|
if(size>se_packet_mem.free_list->amount_free || se_packet_mem.free_list->c_count >= EMEM_ALLOCS_PER_CHUNK){
|
2005-07-22 07:46:58 +00:00
|
|
|
emem_chunk_t *npc;
|
2005-08-12 08:51:08 +00:00
|
|
|
npc=se_packet_mem.free_list;
|
|
|
|
se_packet_mem.free_list=se_packet_mem.free_list->next;
|
|
|
|
npc->next=se_packet_mem.used_list;
|
|
|
|
se_packet_mem.used_list=npc;
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
emem_create_chunk(&se_packet_mem.free_list);
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
free_list = se_packet_mem.free_list;
|
|
|
|
|
|
|
|
buf = free_list->buf + free_list->free_offset;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
free_list->amount_free -= size;
|
|
|
|
free_list->free_offset += size;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
cptr = (char *)buf + size - pad;
|
|
|
|
memcpy(cptr, &se_canary, pad);
|
|
|
|
free_list->canary[free_list->c_count] = cptr;
|
|
|
|
free_list->cmp_len[free_list->c_count] = pad;
|
|
|
|
free_list->c_count++;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
#else /* SE_DEBUG_FREE */
|
|
|
|
emem_chunk_t *npc;
|
|
|
|
|
|
|
|
npc=g_malloc(sizeof(emem_chunk_t));
|
2005-09-02 19:50:01 +00:00
|
|
|
npc->next=se_packet_mem.used_list;
|
2005-08-26 15:45:31 +00:00
|
|
|
npc->amount_free=size;
|
|
|
|
npc->free_offset=0;
|
|
|
|
npc->buf=g_malloc(size);
|
|
|
|
buf = npc->buf;
|
|
|
|
se_packet_mem.used_list=npc;
|
|
|
|
#endif /* SE_DEBUG_FREE */
|
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
void* ep_alloc0(size_t size) {
|
|
|
|
return memset(ep_alloc(size),'\0',size);
|
|
|
|
}
|
2005-07-24 00:29:57 +00:00
|
|
|
|
|
|
|
gchar* ep_strdup(const gchar* src) {
|
|
|
|
guint len = strlen(src);
|
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
dst = strncpy(ep_alloc(len+1), src, len);
|
|
|
|
|
|
|
|
dst[len] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar* ep_strndup(const gchar* src, size_t len) {
|
2005-10-08 12:35:51 +00:00
|
|
|
gchar* dst = ep_alloc(len+1);
|
2005-10-10 08:24:56 +00:00
|
|
|
guint i;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-08 12:35:51 +00:00
|
|
|
for (i = 0; src[i] && i < len; i++)
|
2005-10-10 08:24:56 +00:00
|
|
|
dst[i] = src[i];
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-08 12:35:51 +00:00
|
|
|
dst[i] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2006-02-14 08:34:20 +00:00
|
|
|
void* ep_memdup(const void* src, size_t len) {
|
2005-07-24 00:29:57 +00:00
|
|
|
return memcpy(ep_alloc(len), src, len);
|
|
|
|
}
|
|
|
|
|
2005-10-10 08:24:56 +00:00
|
|
|
gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap) {
|
|
|
|
va_list ap2;
|
|
|
|
guint len;
|
|
|
|
gchar* dst;
|
|
|
|
|
|
|
|
G_VA_COPY(ap2, ap);
|
|
|
|
|
|
|
|
len = g_printf_string_upper_bound(fmt, ap);
|
|
|
|
|
|
|
|
dst = ep_alloc(len+1);
|
|
|
|
g_vsnprintf (dst, len, fmt, ap2);
|
|
|
|
va_end(ap2);
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
gchar* ep_strdup_printf(const gchar* fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
va_start(ap,fmt);
|
2005-10-10 08:24:56 +00:00
|
|
|
dst = ep_strdup_vprintf(fmt, ap);
|
2005-07-24 00:29:57 +00:00
|
|
|
va_end(ap);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
gchar** ep_strsplit(const gchar* string, const gchar* sep, int max_tokens) {
|
|
|
|
gchar* splitted;
|
|
|
|
gchar* s;
|
|
|
|
guint tokens;
|
2005-07-27 00:45:02 +00:00
|
|
|
guint str_len;
|
|
|
|
guint sep_len;
|
2005-07-26 18:32:12 +00:00
|
|
|
guint i;
|
|
|
|
gchar** vec;
|
|
|
|
enum { AT_START, IN_PAD, IN_TOKEN } state;
|
|
|
|
guint curr_tok = 0;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
if ( ! string
|
2005-07-26 18:32:12 +00:00
|
|
|
|| ! sep
|
|
|
|
|| ! sep[0])
|
|
|
|
return NULL;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
s = splitted = ep_strdup(string);
|
|
|
|
str_len = strlen(splitted);
|
|
|
|
sep_len = strlen(sep);
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
if (max_tokens < 1) max_tokens = INT_MAX;
|
|
|
|
|
|
|
|
tokens = 1;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
while (tokens <= (guint)max_tokens && ( s = strstr(s,sep) )) {
|
|
|
|
tokens++;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
for(i=0; i < sep_len; i++ )
|
|
|
|
s[i] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
s += sep_len;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-07-27 00:45:02 +00:00
|
|
|
vec = ep_alloc_array(gchar*,tokens+1);
|
2005-07-26 18:32:12 +00:00
|
|
|
state = AT_START;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
for (i=0; i< str_len; i++) {
|
|
|
|
switch(state) {
|
|
|
|
case AT_START:
|
|
|
|
switch(splitted[i]) {
|
|
|
|
case '\0':
|
|
|
|
state = IN_PAD;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
vec[curr_tok] = &(splitted[i]);
|
|
|
|
curr_tok++;
|
|
|
|
state = IN_TOKEN;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case IN_TOKEN:
|
|
|
|
switch(splitted[i]) {
|
|
|
|
case '\0':
|
|
|
|
state = IN_PAD;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case IN_PAD:
|
|
|
|
switch(splitted[i]) {
|
|
|
|
default:
|
|
|
|
vec[curr_tok] = &(splitted[i]);
|
|
|
|
curr_tok++;
|
|
|
|
state = IN_TOKEN;
|
|
|
|
case '\0':
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
vec[curr_tok] = NULL;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
return vec;
|
|
|
|
}
|
2005-07-24 00:29:57 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
void* se_alloc0(size_t size) {
|
|
|
|
return memset(se_alloc(size),'\0',size);
|
|
|
|
}
|
|
|
|
|
2005-12-09 22:06:38 +00:00
|
|
|
/* If str is NULL, just return the string "<NULL>" so that the callers dont
|
|
|
|
* have to bother checking it.
|
|
|
|
*/
|
2005-08-16 00:55:08 +00:00
|
|
|
gchar* se_strdup(const gchar* src) {
|
2005-12-09 22:06:38 +00:00
|
|
|
guint len;
|
2005-08-16 00:55:08 +00:00
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-12-09 22:06:38 +00:00
|
|
|
if(!src){
|
|
|
|
return "<NULL>";
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(src);
|
2005-08-16 00:55:08 +00:00
|
|
|
dst = strncpy(se_alloc(len+1), src, len);
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
dst[len] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar* se_strndup(const gchar* src, size_t len) {
|
2005-10-08 12:35:51 +00:00
|
|
|
gchar* dst = se_alloc(len+1);
|
2005-10-10 08:24:56 +00:00
|
|
|
guint i;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-08 12:35:51 +00:00
|
|
|
for (i = 0; src[i] && i < len; i++)
|
2005-10-10 08:24:56 +00:00
|
|
|
dst[i] = src[i];
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-08 12:35:51 +00:00
|
|
|
dst[i] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2006-02-14 08:34:20 +00:00
|
|
|
void* se_memdup(const void* src, size_t len) {
|
2005-08-16 00:55:08 +00:00
|
|
|
return memcpy(se_alloc(len), src, len);
|
|
|
|
}
|
|
|
|
|
2005-10-10 08:24:56 +00:00
|
|
|
gchar* se_strdup_vprintf(const gchar* fmt, va_list ap) {
|
|
|
|
va_list ap2;
|
|
|
|
guint len;
|
|
|
|
gchar* dst;
|
|
|
|
|
|
|
|
G_VA_COPY(ap2, ap);
|
|
|
|
|
|
|
|
len = g_printf_string_upper_bound(fmt, ap);
|
|
|
|
|
|
|
|
dst = se_alloc(len+1);
|
|
|
|
g_vsnprintf (dst, len, fmt, ap2);
|
|
|
|
va_end(ap2);
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
gchar* se_strdup_printf(const gchar* fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
va_start(ap,fmt);
|
2005-10-10 08:24:56 +00:00
|
|
|
dst = se_strdup_vprintf(fmt, ap);
|
2005-08-16 00:55:08 +00:00
|
|
|
va_end(ap);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
/* release all allocated memory back to the pool.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ep_free_all(void)
|
|
|
|
{
|
|
|
|
emem_chunk_t *npc;
|
2006-03-07 16:31:47 +00:00
|
|
|
#ifndef EP_DEBUG_FREE
|
2006-01-09 23:11:40 +00:00
|
|
|
guint i;
|
2006-03-07 16:31:47 +00:00
|
|
|
#endif
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
/* move all used chunks over to the free list */
|
2005-08-12 08:51:08 +00:00
|
|
|
while(ep_packet_mem.used_list){
|
|
|
|
npc=ep_packet_mem.used_list;
|
|
|
|
ep_packet_mem.used_list=ep_packet_mem.used_list->next;
|
|
|
|
npc->next=ep_packet_mem.free_list;
|
|
|
|
ep_packet_mem.free_list=npc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear them all out */
|
2005-08-26 15:45:31 +00:00
|
|
|
npc = ep_packet_mem.free_list;
|
|
|
|
while (npc != NULL) {
|
|
|
|
#ifndef EP_DEBUG_FREE
|
2006-01-09 23:11:40 +00:00
|
|
|
for (i = 0; i < npc->c_count; i++) {
|
2006-02-23 23:12:42 +00:00
|
|
|
if (memcmp(npc->canary[i], &ep_canary, npc->cmp_len[i]) != 0)
|
|
|
|
g_error("Per-packet memory corrupted.");
|
2006-01-09 23:11:40 +00:00
|
|
|
}
|
|
|
|
npc->c_count = 0;
|
2006-02-27 20:51:53 +00:00
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
2005-08-26 15:45:31 +00:00
|
|
|
npc = npc->next;
|
|
|
|
#else /* EP_DEBUG_FREE */
|
|
|
|
emem_chunk_t *next = npc->next;
|
|
|
|
|
|
|
|
g_free(npc->buf);
|
|
|
|
g_free(npc);
|
|
|
|
npc = next;
|
|
|
|
#endif /* EP_DEBUG_FREE */
|
2005-08-12 08:51:08 +00:00
|
|
|
}
|
2005-08-26 15:45:31 +00:00
|
|
|
|
|
|
|
#ifdef EP_DEBUG_FREE
|
|
|
|
ep_init_chunk();
|
|
|
|
#endif
|
2005-08-12 08:51:08 +00:00
|
|
|
}
|
|
|
|
/* release all allocated memory back to the pool.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
se_free_all(void)
|
|
|
|
{
|
|
|
|
emem_chunk_t *npc;
|
2006-03-05 04:01:34 +00:00
|
|
|
se_tree_t *se_tree_list;
|
2006-03-07 16:31:47 +00:00
|
|
|
#ifndef SE_DEBUG_FREE
|
|
|
|
guint i;
|
|
|
|
#endif
|
2006-03-05 04:01:34 +00:00
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2006-02-23 23:12:42 +00:00
|
|
|
/* move all used chunks over to the free list */
|
2005-08-12 08:51:08 +00:00
|
|
|
while(se_packet_mem.used_list){
|
|
|
|
npc=se_packet_mem.used_list;
|
|
|
|
se_packet_mem.used_list=se_packet_mem.used_list->next;
|
|
|
|
npc->next=se_packet_mem.free_list;
|
|
|
|
se_packet_mem.free_list=npc;
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* clear them all out */
|
2005-08-26 15:45:31 +00:00
|
|
|
npc = se_packet_mem.free_list;
|
|
|
|
while (npc != NULL) {
|
|
|
|
#ifndef SE_DEBUG_FREE
|
2006-01-09 23:11:40 +00:00
|
|
|
for (i = 0; i < npc->c_count; i++) {
|
2006-02-23 23:12:42 +00:00
|
|
|
if (memcmp(npc->canary[i], &se_canary, npc->cmp_len[i]) != 0)
|
|
|
|
g_error("Per-session memory corrupted.");
|
2006-01-09 23:11:40 +00:00
|
|
|
}
|
|
|
|
npc->c_count = 0;
|
2006-02-27 20:51:53 +00:00
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
2005-08-26 15:45:31 +00:00
|
|
|
npc = npc->next;
|
|
|
|
#else /* SE_DEBUG_FREE */
|
|
|
|
emem_chunk_t *next = npc->next;
|
|
|
|
|
|
|
|
g_free(npc->buf);
|
|
|
|
g_free(npc);
|
|
|
|
npc = next;
|
|
|
|
#endif /* SE_DEBUG_FREE */
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
2005-08-26 15:45:31 +00:00
|
|
|
|
|
|
|
#ifdef SE_DEBUG_FREE
|
|
|
|
se_init_chunk();
|
|
|
|
#endif
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
/* release/reset all se allocated trees */
|
|
|
|
for(se_tree_list=se_trees;se_tree_list;se_tree_list=se_tree_list->next){
|
|
|
|
se_tree_list->tree=NULL;
|
|
|
|
}
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-01 10:36:57 +00:00
|
|
|
ep_stack_t ep_stack_new(void) {
|
|
|
|
ep_stack_t s = ep_new(struct _ep_stack_frame_t*);
|
|
|
|
*s = ep_new0(struct _ep_stack_frame_t);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for ep_stack_t we'll keep the popped frames so we reuse them instead
|
|
|
|
of allocating new ones.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void* ep_stack_push(ep_stack_t stack, void* data) {
|
|
|
|
struct _ep_stack_frame_t* frame;
|
|
|
|
struct _ep_stack_frame_t* head = (*stack);
|
|
|
|
|
|
|
|
if (head->above) {
|
|
|
|
frame = head->above;
|
|
|
|
} else {
|
|
|
|
frame = ep_new(struct _ep_stack_frame_t);
|
|
|
|
head->above = frame;
|
|
|
|
frame->below = head;
|
|
|
|
frame->above = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
frame->payload = data;
|
|
|
|
(*stack) = frame;
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* ep_stack_pop(ep_stack_t stack) {
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-01 10:36:57 +00:00
|
|
|
if ((*stack)->below) {
|
|
|
|
(*stack) = (*stack)->below;
|
|
|
|
return (*stack)->above->payload;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* routines to manage se allocated red-black trees */
|
|
|
|
se_tree_t *se_trees=NULL;
|
|
|
|
|
|
|
|
se_tree_t *
|
|
|
|
se_tree_create(int type)
|
|
|
|
{
|
|
|
|
se_tree_t *tree_list;
|
|
|
|
|
|
|
|
tree_list=malloc(sizeof(se_tree_t));
|
|
|
|
tree_list->next=se_trees;
|
|
|
|
tree_list->type=type;
|
|
|
|
tree_list->tree=NULL;
|
|
|
|
se_trees=tree_list;
|
|
|
|
|
|
|
|
return tree_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
se_tree_lookup32(se_tree_t *se_tree, guint32 key)
|
|
|
|
{
|
|
|
|
se_tree_node_t *node;
|
|
|
|
|
|
|
|
node=se_tree->tree;
|
|
|
|
|
|
|
|
while(node){
|
|
|
|
if(key==node->key32){
|
|
|
|
return node->data;
|
|
|
|
}
|
|
|
|
if(key<node->key32){
|
|
|
|
node=node->left;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(key>node->key32){
|
|
|
|
node=node->right;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline se_tree_node_t *
|
|
|
|
se_tree_parent(se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
return node->parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline se_tree_node_t *
|
|
|
|
se_tree_grandparent(se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *parent;
|
|
|
|
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
if(parent){
|
|
|
|
return parent->parent;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
static inline se_tree_node_t *
|
|
|
|
se_tree_uncle(se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *parent, *grandparent;
|
|
|
|
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
if(!parent){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
grandparent=se_tree_parent(parent);
|
|
|
|
if(!grandparent){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(parent==grandparent->left){
|
|
|
|
return grandparent->right;
|
|
|
|
}
|
|
|
|
return grandparent->left;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void rb_insert_case1(se_tree_t *se_tree, se_tree_node_t *node);
|
|
|
|
static inline void rb_insert_case2(se_tree_t *se_tree, se_tree_node_t *node);
|
|
|
|
|
|
|
|
#ifdef REMOVED
|
|
|
|
void print_tree_item(se_tree_node_t *node, int level){
|
|
|
|
int i;
|
|
|
|
for(i=0;i<level;i++){
|
|
|
|
printf(" ");
|
|
|
|
}
|
|
|
|
printf("%s KEY:0x%08x node:0x%08x parent:0x%08x left:0x%08x right:0x%08x\n",node->rb_color==SE_TREE_RB_COLOR_BLACK?"BLACK":"RED",node->key32,(int)node,(int)node->parent,(int)node->left,(int)node->right);
|
|
|
|
if(node->left)
|
|
|
|
print_tree_item(node->left,level+1);
|
|
|
|
if(node->right)
|
|
|
|
print_tree_item(node->right,level+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_tree(se_tree_node_t *node){
|
|
|
|
while(node->parent){
|
|
|
|
node=node->parent;
|
|
|
|
}
|
|
|
|
print_tree_item(node,0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
rotate_left(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
if(node->parent){
|
|
|
|
if(node->parent->left==node){
|
|
|
|
node->parent->left=node->right;
|
|
|
|
} else {
|
|
|
|
node->parent->right=node->right;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
se_tree->tree=node->right;
|
|
|
|
}
|
|
|
|
node->right->parent=node->parent;
|
|
|
|
node->parent=node->right;
|
|
|
|
node->right=node->right->left;
|
|
|
|
if(node->right){
|
|
|
|
node->right->parent=node;
|
|
|
|
}
|
|
|
|
node->parent->left=node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
rotate_right(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
if(node->parent){
|
|
|
|
if(node->parent->left==node){
|
|
|
|
node->parent->left=node->left;
|
|
|
|
} else {
|
|
|
|
node->parent->right=node->left;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
se_tree->tree=node->left;
|
|
|
|
}
|
|
|
|
node->left->parent=node->parent;
|
|
|
|
node->parent=node->left;
|
|
|
|
node->left=node->left->right;
|
|
|
|
if(node->left){
|
|
|
|
node->left->parent=node;
|
|
|
|
}
|
|
|
|
node->parent->right=node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
rb_insert_case5(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *grandparent;
|
|
|
|
se_tree_node_t *parent;
|
|
|
|
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
parent->rb_color=SE_TREE_RB_COLOR_BLACK;
|
|
|
|
grandparent=se_tree_parent(parent);
|
|
|
|
if(!grandparent){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
grandparent->rb_color=SE_TREE_RB_COLOR_RED;
|
|
|
|
if( (node==parent->left) && (parent==grandparent->left) ){
|
|
|
|
rotate_right(se_tree, grandparent);
|
|
|
|
} else {
|
|
|
|
rotate_left(se_tree, grandparent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
rb_insert_case4(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *grandparent;
|
|
|
|
se_tree_node_t *parent;
|
|
|
|
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
grandparent=se_tree_parent(parent);
|
|
|
|
if(!grandparent){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( (node==parent->right) && (parent==grandparent->left) ){
|
|
|
|
rotate_left(se_tree, parent);
|
|
|
|
node=node->left;
|
|
|
|
} else if( (node==parent->left) && (parent==grandparent->right) ){
|
|
|
|
rotate_right(se_tree, parent);
|
|
|
|
node=node->right;
|
|
|
|
}
|
|
|
|
rb_insert_case5(se_tree, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
rb_insert_case3(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *grandparent;
|
|
|
|
se_tree_node_t *parent;
|
|
|
|
se_tree_node_t *uncle;
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
uncle=se_tree_uncle(node);
|
|
|
|
if(uncle && (uncle->rb_color==SE_TREE_RB_COLOR_RED)){
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
parent->rb_color=SE_TREE_RB_COLOR_BLACK;
|
|
|
|
uncle->rb_color=SE_TREE_RB_COLOR_BLACK;
|
|
|
|
grandparent=se_tree_grandparent(node);
|
|
|
|
if(grandparent){
|
|
|
|
rb_insert_case1(se_tree, grandparent);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rb_insert_case4(se_tree, node);
|
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
}
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
static inline void
|
|
|
|
rb_insert_case2(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *parent;
|
|
|
|
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
/* parent is always non-NULL here */
|
|
|
|
if(parent->rb_color==SE_TREE_RB_COLOR_BLACK){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rb_insert_case3(se_tree, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
rb_insert_case1(se_tree_t *se_tree, se_tree_node_t *node)
|
|
|
|
{
|
|
|
|
se_tree_node_t *parent;
|
|
|
|
|
|
|
|
parent=se_tree_parent(node);
|
|
|
|
if(!parent){
|
|
|
|
node->rb_color=SE_TREE_RB_COLOR_BLACK;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rb_insert_case2(se_tree, node);
|
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
/* insert a new node in the tree. if this node matches an already existing node
|
|
|
|
* then just replace the data for that node */
|
2006-03-07 16:31:47 +00:00
|
|
|
void
|
2006-03-05 04:01:34 +00:00
|
|
|
se_tree_insert32(se_tree_t *se_tree, guint32 key, void *data)
|
|
|
|
{
|
|
|
|
se_tree_node_t *node;
|
|
|
|
|
|
|
|
node=se_tree->tree;
|
|
|
|
|
|
|
|
/* is this the first node ?*/
|
|
|
|
if(!node){
|
|
|
|
node=se_alloc(sizeof(se_tree_node_t));
|
|
|
|
switch(se_tree->type){
|
|
|
|
case SE_TREE_TYPE_RED_BLACK:
|
|
|
|
node->rb_color=SE_TREE_RB_COLOR_BLACK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node->parent=NULL;
|
|
|
|
node->left=NULL;
|
|
|
|
node->right=NULL;
|
|
|
|
node->key32=key;
|
|
|
|
node->data=data;
|
|
|
|
se_tree->tree=node;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it was not the new root so walk the tree until we find where to
|
|
|
|
* insert this new leaf.
|
|
|
|
*/
|
|
|
|
while(1){
|
|
|
|
/* this node already exists, so just replace the data pointer*/
|
|
|
|
if(key==node->key32){
|
|
|
|
node->data=data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(key<node->key32) {
|
|
|
|
if(!node->left){
|
|
|
|
/* new node to the left */
|
2006-03-07 16:31:47 +00:00
|
|
|
se_tree_node_t *new_node;
|
2006-03-05 04:01:34 +00:00
|
|
|
new_node=se_alloc(sizeof(se_tree_node_t));
|
|
|
|
node->left=new_node;
|
|
|
|
new_node->parent=node;
|
|
|
|
new_node->left=NULL;
|
|
|
|
new_node->right=NULL;
|
|
|
|
new_node->key32=key;
|
|
|
|
new_node->data=data;
|
|
|
|
node=new_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node=node->left;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(key>node->key32) {
|
|
|
|
if(!node->right){
|
|
|
|
/* new node to the right */
|
2006-03-07 16:31:47 +00:00
|
|
|
se_tree_node_t *new_node;
|
2006-03-05 04:01:34 +00:00
|
|
|
new_node=se_alloc(sizeof(se_tree_node_t));
|
|
|
|
node->right=new_node;
|
|
|
|
new_node->parent=node;
|
|
|
|
new_node->left=NULL;
|
|
|
|
new_node->right=NULL;
|
|
|
|
new_node->key32=key;
|
|
|
|
new_node->data=data;
|
|
|
|
node=new_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node=node->right;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* node will now point to the newly created node */
|
|
|
|
switch(se_tree->type){
|
|
|
|
case SE_TREE_TYPE_RED_BLACK:
|
|
|
|
node->rb_color=SE_TREE_RB_COLOR_RED;
|
|
|
|
rb_insert_case1(se_tree, node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
/* When the se data is released, this entire tree will dissapear as if it
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
* never existed including all metadata associated with the tree.
|
|
|
|
*/
|
|
|
|
se_tree_t *
|
|
|
|
se_tree_create_non_persistent(int type)
|
|
|
|
{
|
|
|
|
se_tree_t *tree_list;
|
|
|
|
|
|
|
|
tree_list=se_alloc(sizeof(se_tree_t));
|
|
|
|
tree_list->next=NULL;
|
|
|
|
tree_list->type=type;
|
|
|
|
tree_list->tree=NULL;
|
|
|
|
|
|
|
|
return tree_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* insert a new node in the tree. if this node matches an already existing node
|
|
|
|
* then just replace the data for that node */
|
2006-03-07 16:31:47 +00:00
|
|
|
void
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
se_tree_insert32_array(se_tree_t *se_tree, se_tree_key_t *key, void *data)
|
|
|
|
{
|
|
|
|
se_tree_t *next_tree;
|
|
|
|
|
|
|
|
if((key[0].length<1)||(key[0].length>100)){
|
|
|
|
DISSECTOR_ASSERT_NOT_REACHED();
|
|
|
|
}
|
|
|
|
if((key[0].length==1)&&(key[1].length==0)){
|
|
|
|
se_tree_insert32(se_tree, *key[0].key, data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
next_tree=se_tree_lookup32(se_tree, *key[0].key);
|
|
|
|
if(!next_tree){
|
|
|
|
next_tree=se_tree_create_non_persistent(se_tree->type);
|
|
|
|
se_tree_insert32(se_tree, *key[0].key, next_tree);
|
|
|
|
}
|
|
|
|
if(key[0].length==1){
|
|
|
|
key++;
|
|
|
|
} else {
|
|
|
|
key[0].length--;
|
|
|
|
key[0].key++;
|
|
|
|
}
|
|
|
|
se_tree_insert32_array(next_tree, key, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
se_tree_lookup32_array(se_tree_t *se_tree, se_tree_key_t *key)
|
|
|
|
{
|
|
|
|
se_tree_t *next_tree;
|
|
|
|
|
|
|
|
if((key[0].length<1)||(key[0].length>100)){
|
|
|
|
DISSECTOR_ASSERT_NOT_REACHED();
|
|
|
|
}
|
|
|
|
if((key[0].length==1)&&(key[1].length==0)){
|
|
|
|
return se_tree_lookup32(se_tree, *key[0].key);
|
|
|
|
}
|
|
|
|
next_tree=se_tree_lookup32(se_tree, *key[0].key);
|
|
|
|
if(!next_tree){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(key[0].length==1){
|
|
|
|
key++;
|
|
|
|
} else {
|
|
|
|
key[0].length--;
|
|
|
|
key[0].key++;
|
|
|
|
}
|
|
|
|
se_tree_lookup32_array(next_tree, key);
|
|
|
|
}
|
2006-03-07 01:15:29 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
|
2006-03-07 14:10:30 +00:00
|
|
|
void se_tree_insert_string(se_string_hash_t* se_tree, const gchar* k, void* v) {
|
2006-03-07 06:33:47 +00:00
|
|
|
guint32 len = strlen(k);
|
|
|
|
guint32 div = (len-1)/4;
|
|
|
|
guint32 residual = 0;
|
|
|
|
se_tree_key_t key[] = {
|
|
|
|
{1,&len},
|
|
|
|
{div,(guint32*)(&k[0])},
|
|
|
|
{1,&residual},
|
|
|
|
{0,NULL}
|
|
|
|
};
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
if (! div) {
|
|
|
|
key[1].length = key[2].length;
|
|
|
|
key[1].key = key[2].key;
|
|
|
|
key[2].length = 0;
|
|
|
|
key[2].key = NULL;
|
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
div *= 4;
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
switch(len%4) {
|
|
|
|
case 0:
|
|
|
|
residual |= ( k[div+3] << 24 );
|
|
|
|
case 3:
|
|
|
|
residual |= ( k[div+2] << 16 );
|
|
|
|
case 2:
|
|
|
|
residual |= ( k[div+1] << 8 );
|
|
|
|
case 1:
|
|
|
|
residual |= k[div];
|
|
|
|
break;
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
se_tree_insert32_array(se_tree,key,v);
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
|
|
|
|
2006-03-07 14:10:30 +00:00
|
|
|
void* se_tree_lookup_string(se_string_hash_t* se_tree, const gchar* k) {
|
2006-03-07 06:33:47 +00:00
|
|
|
guint32 len = strlen(k);
|
|
|
|
guint32 div = (len-1)/4;
|
|
|
|
guint32 residual = 0;
|
|
|
|
se_tree_key_t key[] = {
|
|
|
|
{1,&len},
|
|
|
|
{div,(guint32*)(&k[0])},
|
|
|
|
{1,&residual},
|
|
|
|
{0,NULL}
|
|
|
|
};
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
if (! div) {
|
|
|
|
key[1].length = key[2].length;
|
|
|
|
key[1].key = key[2].key;
|
|
|
|
key[2].length = 0;
|
|
|
|
key[2].key = NULL;
|
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
div *= 4;
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
switch(len%4) {
|
|
|
|
case 0:
|
|
|
|
residual |= k[div+3] << 24;
|
|
|
|
case 3:
|
|
|
|
residual |= k[div+2] << 16;
|
|
|
|
case 2:
|
|
|
|
residual |= k[div+1] << 8;
|
|
|
|
case 1:
|
|
|
|
residual |= k[div];
|
|
|
|
break;
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
return se_tree_lookup32_array(se_tree, key);
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|